1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 01:07:36 +00:00

LibGfx+Everywhere: Change Gfx::Rect to be endpoint exclusive

Previously, calling `.right()` on a `Gfx::Rect` would return the last
column's coordinate still inside the rectangle, or `left + width - 1`.
This is called 'endpoint inclusive' and does not make a lot of sense for
`Gfx::Rect<float>` where a rectangle of width 5 at position (0, 0) would
return 4 as its right side. This same problem exists for `.bottom()`.

This changes `Gfx::Rect` to be endpoint exclusive, which gives us the
nice property that `width = right - left` and `height = bottom - top`.
It enables us to treat `Gfx::Rect<int>` and `Gfx::Rect<float>` exactly
the same.

All users of `Gfx::Rect` have been updated accordingly.
This commit is contained in:
Jelle Raaijmakers 2023-05-22 00:41:18 +02:00 committed by Andreas Kling
parent b7f4363791
commit f391ccfe53
88 changed files with 524 additions and 518 deletions

View file

@ -204,9 +204,9 @@ template<>
FloatRect AffineTransform::map(FloatRect const& rect) const
{
FloatPoint p1 = map(rect.top_left());
FloatPoint p2 = map(rect.top_right().translated(1, 0));
FloatPoint p3 = map(rect.bottom_right().translated(1, 1));
FloatPoint p4 = map(rect.bottom_left().translated(0, 1));
FloatPoint p2 = map(rect.top_right());
FloatPoint p3 = map(rect.bottom_right());
FloatPoint p4 = map(rect.bottom_left());
float left = smallest_of(p1.x(), p2.x(), p3.x(), p4.x());
float top = smallest_of(p1.y(), p2.y(), p3.y(), p4.y());
float right = largest_of(p1.x(), p2.x(), p3.x(), p4.x());

View file

@ -683,11 +683,11 @@ void AntiAliasingPainter::fill_rect_with_rounded_corners(IntRect const& a_rect,
if (top_left)
fill_corner(top_left_corner, bounding_rect.top_left(), top_left);
if (top_right)
fill_corner(top_right_corner, bounding_rect.top_right(), top_right);
fill_corner(top_right_corner, bounding_rect.top_right().moved_left(1), top_right);
if (bottom_left)
fill_corner(bottom_left_corner, bounding_rect.bottom_left(), bottom_left);
fill_corner(bottom_left_corner, bounding_rect.bottom_left().moved_up(1), bottom_left);
if (bottom_right)
fill_corner(bottom_right_corner, bounding_rect.bottom_right(), bottom_right);
fill_corner(bottom_right_corner, bounding_rect.bottom_right().translated(-1), bottom_right);
}
void AntiAliasingPainter::stroke_segment_intersection(FloatPoint current_line_a, FloatPoint current_line_b, FloatLine const& previous_line, Color color, float thickness)

View file

@ -280,12 +280,12 @@ void ClassicStylePainter::paint_frame(Painter& painter, IntRect const& rect, Pal
VERIFY_NOT_REACHED();
}
painter.draw_line(rect.top_left(), rect.top_right(), top_left_color);
painter.draw_line(rect.bottom_left(), rect.bottom_right(), bottom_right_color);
painter.draw_line(rect.top_left(), rect.top_right().moved_left(1), top_left_color);
painter.draw_line(rect.bottom_left().moved_up(1), rect.bottom_right().translated(-1), bottom_right_color);
if ((style != FrameStyle::SunkenPanel && style != FrameStyle::RaisedPanel) || !skip_vertical_lines) {
painter.draw_line(rect.top_left().translated(0, 1), rect.bottom_left().translated(0, -1), top_left_color);
painter.draw_line(rect.top_right(), rect.bottom_right().translated(0, -1), bottom_right_color);
painter.draw_line(rect.top_left().moved_down(1), rect.bottom_left().moved_up(2), top_left_color);
painter.draw_line(rect.top_right().moved_left(1), rect.bottom_right().translated(-1, -2), bottom_right_color);
}
if (style == FrameStyle::RaisedContainer || style == FrameStyle::SunkenContainer) {
@ -302,19 +302,19 @@ void ClassicStylePainter::paint_frame(Painter& painter, IntRect const& rect, Pal
bottom_right_color = light_shade;
}
IntRect inner_container_frame_rect = rect.shrunken(2, 2);
painter.draw_line(inner_container_frame_rect.top_left(), inner_container_frame_rect.top_right(), top_left_color);
painter.draw_line(inner_container_frame_rect.bottom_left(), inner_container_frame_rect.bottom_right(), bottom_right_color);
painter.draw_line(inner_container_frame_rect.top_left().translated(0, 1), inner_container_frame_rect.bottom_left().translated(0, -1), top_left_color);
painter.draw_line(inner_container_frame_rect.top_right(), inner_container_frame_rect.bottom_right().translated(0, -1), bottom_right_color);
painter.draw_line(inner_container_frame_rect.top_left(), inner_container_frame_rect.top_right().moved_left(1), top_left_color);
painter.draw_line(inner_container_frame_rect.bottom_left().moved_up(1), inner_container_frame_rect.bottom_right().translated(-1), bottom_right_color);
painter.draw_line(inner_container_frame_rect.top_left().moved_down(1), inner_container_frame_rect.bottom_left().moved_up(2), top_left_color);
painter.draw_line(inner_container_frame_rect.top_right().moved_left(1), inner_container_frame_rect.bottom_right().translated(-1, -2), bottom_right_color);
}
if (style == FrameStyle::RaisedBox || style == FrameStyle::SunkenBox) {
swap(top_left_color, bottom_right_color);
IntRect inner_rect = rect.shrunken(2, 2);
painter.draw_line(inner_rect.top_left(), inner_rect.top_right(), top_left_color);
painter.draw_line(inner_rect.bottom_left(), inner_rect.bottom_right(), bottom_right_color);
painter.draw_line(inner_rect.top_left().translated(0, 1), inner_rect.bottom_left().translated(0, -1), top_left_color);
painter.draw_line(inner_rect.top_right(), inner_rect.bottom_right().translated(0, -1), bottom_right_color);
painter.draw_line(inner_rect.top_left(), inner_rect.top_right().moved_left(1), top_left_color);
painter.draw_line(inner_rect.bottom_left().moved_up(1), inner_rect.bottom_right().translated(-1), bottom_right_color);
painter.draw_line(inner_rect.top_left().moved_down(1), inner_rect.bottom_left().moved_up(2), top_left_color);
painter.draw_line(inner_rect.top_right().moved_left(1), inner_rect.bottom_right().translated(-1, -2), bottom_right_color);
}
}
@ -342,22 +342,22 @@ void ClassicStylePainter::paint_window_frame(Painter& painter, IntRect const& re
rect.height() - border_thickness },
base_color, border_thickness);
painter.draw_line(rect.top_left().translated(0, 1), rect.bottom_left(), base_color);
painter.draw_line(rect.top_left().translated(1, 1), rect.top_right().translated(-1, 1), light_shade);
painter.draw_line(rect.top_left().translated(1, 1), rect.bottom_left().translated(1, -1), light_shade);
painter.draw_line(rect.top_left().translated(2, 2), rect.top_right().translated(-2, 2), base_color);
painter.draw_line(rect.top_left().translated(2, 2), rect.bottom_left().translated(2, -2), base_color);
painter.draw_line(rect.top_left().translated(3, 3), rect.top_right().translated(-3, 3), base_color);
painter.draw_line(rect.top_left().translated(3, 3), rect.bottom_left().translated(3, -3), base_color);
painter.draw_line(rect.top_left().translated(0, 1), rect.bottom_left().translated(0, -1), base_color);
painter.draw_line(rect.top_left().translated(1, 1), rect.top_right().translated(-2, 1), light_shade);
painter.draw_line(rect.top_left().translated(1, 1), rect.bottom_left().translated(1, -2), light_shade);
painter.draw_line(rect.top_left().translated(2, 2), rect.top_right().translated(-3, 2), base_color);
painter.draw_line(rect.top_left().translated(2, 2), rect.bottom_left().translated(2, -3), base_color);
painter.draw_line(rect.top_left().translated(3, 3), rect.top_right().translated(-4, 3), base_color);
painter.draw_line(rect.top_left().translated(3, 3), rect.bottom_left().translated(3, -4), base_color);
painter.draw_line(rect.top_right(), rect.bottom_right(), dark_shade);
painter.draw_line(rect.top_right().translated(-1, 1), rect.bottom_right().translated(-1, -1), mid_shade);
painter.draw_line(rect.top_right().translated(-2, 2), rect.bottom_right().translated(-2, -2), base_color);
painter.draw_line(rect.top_right().translated(-3, 3), rect.bottom_right().translated(-3, -3), base_color);
painter.draw_line(rect.bottom_left(), rect.bottom_right(), dark_shade);
painter.draw_line(rect.bottom_left().translated(1, -1), rect.bottom_right().translated(-1, -1), mid_shade);
painter.draw_line(rect.bottom_left().translated(2, -2), rect.bottom_right().translated(-2, -2), base_color);
painter.draw_line(rect.bottom_left().translated(3, -3), rect.bottom_right().translated(-3, -3), base_color);
painter.draw_line(rect.top_right().translated(-1, 0), rect.bottom_right().translated(-1, -1), dark_shade);
painter.draw_line(rect.top_right().translated(-2, 1), rect.bottom_right().translated(-2, -2), mid_shade);
painter.draw_line(rect.top_right().translated(-3, 2), rect.bottom_right().translated(-3, -3), base_color);
painter.draw_line(rect.top_right().translated(-4, 3), rect.bottom_right().translated(-4, -4), base_color);
painter.draw_line(rect.bottom_left().translated(0, -1), rect.bottom_right().translated(-1, -1), dark_shade);
painter.draw_line(rect.bottom_left().translated(1, -2), rect.bottom_right().translated(-2, -2), mid_shade);
painter.draw_line(rect.bottom_left().translated(2, -3), rect.bottom_right().translated(-3, -3), base_color);
painter.draw_line(rect.bottom_left().translated(3, -4), rect.bottom_right().translated(-4, -4), base_color);
}
void ClassicStylePainter::paint_progressbar(Painter& painter, IntRect const& rect, Palette const& palette, int min, int max, int value, StringView text, Orientation orientation)
@ -624,7 +624,7 @@ void ClassicStylePainter::paint_simple_rect_shadow(Painter& painter, IntRect con
auto half_width = containing_horizontal_rect.width() / 2;
int corner_piece_width = min(containing_horizontal_rect.width() / 2, base_size * 2);
int left_corners_right = containing_horizontal_rect.left() + corner_piece_width;
int right_corners_left = max(containing_horizontal_rect.right() - corner_piece_width + 1, left_corners_right + 1);
int right_corners_left = max(containing_horizontal_rect.right() - corner_piece_width, left_corners_right + 1);
auto paint_horizontal = [&](int y, int src_row) {
if (half_width <= 0)
return;
@ -639,7 +639,7 @@ void ClassicStylePainter::paint_simple_rect_shadow(Painter& painter, IntRect con
};
paint_horizontal(containing_rect.top(), 0);
paint_horizontal(containing_rect.bottom() - base_size + 1, 1);
paint_horizontal(containing_rect.bottom() - base_size, 1);
int corner_piece_height = min(half_height, base_size);
int top_corners_bottom = base_size + corner_piece_height;
@ -658,7 +658,7 @@ void ClassicStylePainter::paint_simple_rect_shadow(Painter& painter, IntRect con
paint_vertical(containing_rect.left(), 0, horizontal_shift, 0);
if (shadow_includes_frame)
horizontal_shift = 0; // TODO: fix off-by-one on rectangles barely wide enough
paint_vertical(containing_rect.right() - base_size + 1, 1, 0, horizontal_shift);
paint_vertical(containing_rect.right() - base_size, 1, 0, horizontal_shift);
if (fill_content) {
// Fill the enclosed rectangle with the RGBA color of the right-bottom pixel of the TL tile

View file

@ -64,8 +64,8 @@ void ClassicWindowTheme::paint_normal_frame(Painter& painter, WindowState window
auto [title_color, border_color, border_color2, stripes_color, shadow_color] = compute_frame_colors(window_state, palette);
painter.draw_line(titlebar_rect.bottom_left().translated(0, 1), titlebar_rect.bottom_right().translated(0, 1), palette.button());
painter.draw_line(titlebar_rect.bottom_left().translated(0, 2), titlebar_rect.bottom_right().translated(0, 2), palette.button());
painter.draw_line(titlebar_rect.bottom_left(), titlebar_rect.bottom_right().moved_left(1), palette.button());
painter.draw_line(titlebar_rect.bottom_left().moved_down(1), titlebar_rect.bottom_right().translated(-1, 1), palette.button());
painter.fill_rect_with_gradient(titlebar_rect, border_color, border_color2);
@ -87,7 +87,7 @@ void ClassicWindowTheme::paint_normal_frame(Painter& painter, WindowState window
if (stripes_color.alpha() > 0) {
switch (title_alignment) {
case Gfx::TextAlignment::CenterLeft: {
int stripe_left = titlebar_title_rect.right() + 5;
int stripe_left = titlebar_title_rect.right() + 4;
if (stripe_left && stripe_right && stripe_left < stripe_right) {
for (int i = 2; i <= titlebar_inner_rect.height() - 2; i += 2) {
@ -164,12 +164,11 @@ void ClassicWindowTheme::paint_notification_frame(Painter& painter, WindowMode w
painter.fill_rect_with_gradient(Gfx::Orientation::Vertical, titlebar_rect, palette.active_window_border1(), palette.active_window_border2());
if (palette.active_window_title_stripes().alpha() > 0) {
int stripe_top = close_button_rect.bottom() + 4;
int stripe_top = close_button_rect.bottom() + 3;
int stripe_bottom = window_rect.height() - 3;
if (stripe_top && stripe_bottom && stripe_top < stripe_bottom) {
for (int i = 2; i <= palette.window_title_height() - 2; i += 2) {
for (int i = 2; i <= palette.window_title_height() - 2; i += 2)
painter.draw_line({ titlebar_rect.x() + i, stripe_top }, { titlebar_rect.x() + i, stripe_bottom }, palette.active_window_title_stripes());
}
}
}
}
@ -208,7 +207,7 @@ Vector<IntRect> ClassicWindowTheme::layout_buttons(WindowType window_type, Windo
if (window_type == WindowType::Notification)
pos = titlebar_rect(window_type, window_mode, window_rect, palette).top() + 2;
else
pos = titlebar_text_rect(window_type, window_mode, window_rect, palette).right() + 1;
pos = titlebar_text_rect(window_type, window_mode, window_rect, palette).right();
for (size_t i = 0; i < buttons; i++) {
if (window_type == WindowType::Notification) {

View file

@ -68,7 +68,7 @@ ALWAYS_INLINE void Painter::draw_scanline_for_fill_path(int y, T x_start, T x_en
if (paint_left_subpixel)
set_physical_pixel(clipped.top_left(), get_color_with_alpha(0, left_subpixel_alpha), true);
if (paint_right_subpixel)
set_physical_pixel(clipped.top_right(), get_color_with_alpha(scanline.width(), right_subpixel_alpha), true);
set_physical_pixel(clipped.top_right().moved_left(1), get_color_with_alpha(scanline.width(), right_subpixel_alpha), true);
clipped.shrink(0, paint_right_subpixel, 0, paint_left_subpixel);
if (clipped.is_empty())
return;
@ -82,9 +82,8 @@ ALWAYS_INLINE void Painter::draw_scanline_for_fill_path(int y, T x_start, T x_en
}
}
for (int x = clipped.x(); x <= clipped.right(); x++) {
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)
@ -144,8 +143,8 @@ void Painter::fill_path_impl(Path const& path, ColorOrFunction color, Gfx::Paint
active_list.ensure_capacity(segments.size());
// first, grab the segments for the very first scanline
GridCoordinateType first_y = path.bounding_box().bottom_right().y() + 1;
GridCoordinateType last_y = path.bounding_box().top_left().y() - 1;
GridCoordinateType first_y = path.bounding_box().bottom();
GridCoordinateType last_y = path.bounding_box().top() - 1;
float scanline = first_y;
size_t last_active_segment { 0 };

View file

@ -110,7 +110,7 @@ public:
FloatVector3 value(0, 0, 0);
for (auto k = 0l; k < (ssize_t)N; ++k) {
auto ki = i + k - offset;
if (ki < source_rect.x() || ki > source_rect.right()) {
if (ki < source_rect.x() || ki >= source_rect.right()) {
if (parameters.should_wrap())
ki = (ki + source.size().width()) % source.size().width(); // TODO: fix up using source_rect
else
@ -119,7 +119,7 @@ public:
for (auto l = 0l; l < (ssize_t)N; ++l) {
auto lj = j + l - offset;
if (lj < source_rect.y() || lj > source_rect.bottom()) {
if (lj < source_rect.y() || lj >= source_rect.bottom()) {
if (parameters.should_wrap())
lj = (lj + source.size().height()) % source.size().height(); // TODO: fix up using source_rect
else

View file

@ -560,18 +560,14 @@ static void for_each_pixel_around_rect_clockwise(RectType const& rect, Callback
{
if (rect.is_empty())
return;
for (auto x = rect.left(); x <= rect.right(); ++x) {
for (auto x = rect.left(); x < rect.right(); ++x)
callback(x, rect.top());
}
for (auto y = rect.top() + 1; y <= rect.bottom(); ++y) {
callback(rect.right(), y);
}
for (auto x = rect.right() - 1; x >= rect.left(); --x) {
callback(x, rect.bottom());
}
for (auto y = rect.bottom() - 1; y > rect.top(); --y) {
for (auto y = rect.top() + 1; y < rect.bottom(); ++y)
callback(rect.right() - 1, y);
for (auto x = rect.right() - 2; x >= rect.left(); --x)
callback(x, rect.bottom() - 1);
for (auto y = rect.bottom() - 2; y > rect.top(); --y)
callback(rect.left(), y);
}
}
void Painter::draw_focus_rect(IntRect const& rect, Color color)
@ -596,17 +592,17 @@ void Painter::draw_rect(IntRect const& a_rect, Color color, bool rough)
return;
int min_y = clipped_rect.top();
int max_y = clipped_rect.bottom();
int max_y = clipped_rect.bottom() - 1;
int scale = this->scale();
if (rect.top() >= clipped_rect.top() && rect.top() <= clipped_rect.bottom()) {
if (rect.top() >= clipped_rect.top() && rect.top() < clipped_rect.bottom()) {
int start_x = rough ? max(rect.x() + 1, clipped_rect.x()) : clipped_rect.x();
int width = rough ? min(rect.width() - 2, clipped_rect.width()) : clipped_rect.width();
for (int i = 0; i < scale; ++i)
fill_physical_scanline_with_draw_op(rect.top() * scale + i, start_x * scale, width * scale, color);
++min_y;
}
if (rect.bottom() >= clipped_rect.top() && rect.bottom() <= clipped_rect.bottom()) {
if (rect.bottom() > clipped_rect.top() && rect.bottom() <= clipped_rect.bottom()) {
int start_x = rough ? max(rect.x() + 1, clipped_rect.x()) : clipped_rect.x();
int width = rough ? min(rect.width() - 2, clipped_rect.width()) : clipped_rect.width();
for (int i = 0; i < scale; ++i)
@ -624,7 +620,7 @@ void Painter::draw_rect(IntRect const& a_rect, Color color, bool rough)
for (int i = 0; i < scale; ++i)
set_physical_pixel_with_draw_op(bits[rect.left() * scale + i], color);
for (int i = 0; i < scale; ++i)
set_physical_pixel_with_draw_op(bits[rect.right() * scale + i], color);
set_physical_pixel_with_draw_op(bits[(rect.right() - 1) * scale + i], color);
}
} else {
for (int y = min_y * scale; y <= max_y * scale; ++y) {
@ -634,7 +630,7 @@ void Painter::draw_rect(IntRect const& a_rect, Color color, bool rough)
set_physical_pixel_with_draw_op(bits[rect.left() * scale + i], color);
if (draw_right_side)
for (int i = 0; i < scale; ++i)
set_physical_pixel_with_draw_op(bits[rect.right() * scale + i], color);
set_physical_pixel_with_draw_op(bits[(rect.right() - 1) * scale + i], color);
}
}
}
@ -672,8 +668,8 @@ void Painter::draw_bitmap(IntPoint p, CharacterBitmap const& bitmap, Color color
char const* bitmap_row = &bitmap.bits()[first_row * bitmap.width() + first_column];
size_t const bitmap_skip = bitmap.width();
for (int row = first_row; row <= last_row; ++row) {
for (int j = 0; j <= (last_column - first_column); ++j) {
for (int row = first_row; row < last_row; ++row) {
for (int j = 0; j < (last_column - first_column); ++j) {
char fc = bitmap_row[j];
if (fc == '#')
dst[j] = color.value();
@ -700,16 +696,16 @@ void Painter::draw_bitmap(IntPoint p, GlyphBitmap const& bitmap, Color color)
size_t const dst_skip = m_target->pitch() / sizeof(ARGB32);
if (scale == 1) {
for (int row = first_row; row <= last_row; ++row) {
for (int j = 0; j <= (last_column - first_column); ++j) {
for (int row = first_row; row < last_row; ++row) {
for (int j = 0; j < (last_column - first_column); ++j) {
if (bitmap.bit_at(j + first_column, row))
dst[j] = color_for_format(dst_format, dst[j]).blend(color).value();
}
dst += dst_skip;
}
} else {
for (int row = first_row; row <= last_row; ++row) {
for (int j = 0; j <= (last_column - first_column); ++j) {
for (int row = first_row; row < last_row; ++row) {
for (int j = 0; j < (last_column - first_column); ++j) {
if (bitmap.bit_at((j + first_column), row)) {
for (int iy = 0; iy < scale; ++iy)
for (int ix = 0; ix < scale; ++ix) {
@ -753,7 +749,7 @@ void Painter::draw_triangle(IntPoint a, IntPoint b, IntPoint c, Color color)
// return if top is below clip rect or bottom is above clip rect
auto clip = clip_rect();
if (p0.y() >= clip.bottom())
if (p0.y() >= clip.bottom() - 1)
return;
if (p2.y() < clip.top())
return;
@ -801,7 +797,7 @@ void Painter::draw_triangle(IntPoint a, IntPoint b, IntPoint c, Color color)
int rgba = color.value();
for (int y = max(p0.y(), clip.top()); y <= min(p2.y(), clip.bottom()); y++) {
for (int y = max(p0.y(), clip.top()); y < min(p2.y() + 1, clip.bottom()); y++) {
Optional<int>
x0 = l0.intersection_on_x(y),
x1 = l1.intersection_on_x(y),
@ -827,9 +823,8 @@ void Painter::draw_triangle(IntPoint a, IntPoint b, IntPoint c, Color color)
int left_bound = result_a, right_bound = result_b;
ARGB32* scanline = m_target->scanline(y);
for (int x = max(left_bound, clip.left()); x <= min(right_bound, clip.right()); x++) {
for (int x = max(left_bound, clip.left()); x <= min(right_bound, clip.right() - 1); x++)
scanline[x] = rgba;
}
}
}
@ -920,8 +915,8 @@ void Painter::blit_with_opacity(IntPoint position, Gfx::Bitmap const& source, In
.dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x(),
.src_pitch = source.pitch() / sizeof(ARGB32),
.dst_pitch = m_target->pitch() / sizeof(ARGB32),
.row_count = last_row - first_row + 1,
.column_count = last_column - first_column + 1,
.row_count = last_row - first_row,
.column_count = last_column - first_column,
.opacity = opacity,
.src_format = source.format(),
};
@ -968,8 +963,8 @@ void Painter::blit_filtered(IntPoint position, Gfx::Bitmap const& source, IntRec
ARGB32 const* src = source.scanline(safe_src_rect.top() + first_row) + safe_src_rect.left() + first_column;
size_t const src_skip = source.pitch() / sizeof(ARGB32);
for (int row = first_row; row <= last_row; ++row) {
for (int x = 0; x <= (last_column - first_column); ++x) {
for (int row = first_row; row < last_row; ++row) {
for (int x = 0; x < (last_column - first_column); ++x) {
u8 alpha = color_for_format(src_format, src[x]).alpha();
if (alpha == 0xff) {
auto color = filter(Color::from_argb(src[x]));
@ -986,9 +981,9 @@ void Painter::blit_filtered(IntPoint position, Gfx::Bitmap const& source, IntRec
src += src_skip;
}
} else {
for (int row = first_row; row <= last_row; ++row) {
for (int row = first_row; row < last_row; ++row) {
ARGB32 const* src = source.scanline(safe_src_rect.top() + row / s) + safe_src_rect.left() + first_column / s;
for (int x = 0; x <= (last_column - first_column); ++x) {
for (int x = 0; x < (last_column - first_column); ++x) {
u8 alpha = color_for_format(src_format, src[x / s]).alpha();
if (alpha == 0xff) {
auto color = filter(color_for_format(src_format, src[x / s]));
@ -1033,9 +1028,9 @@ void Painter::draw_tiled_bitmap(IntRect const& a_dst_rect, Gfx::Bitmap const& so
clipped_rect *= scale;
dst_rect *= scale;
int const first_row = (clipped_rect.top() - dst_rect.top());
int const last_row = (clipped_rect.bottom() - dst_rect.top());
int const first_column = (clipped_rect.left() - dst_rect.left());
int const first_row = clipped_rect.top() - dst_rect.top();
int const last_row = clipped_rect.bottom() - dst_rect.top();
int const first_column = clipped_rect.left() - dst_rect.left();
ARGB32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x();
size_t const dst_skip = m_target->pitch() / sizeof(ARGB32);
@ -1043,20 +1038,18 @@ void Painter::draw_tiled_bitmap(IntRect const& a_dst_rect, Gfx::Bitmap const& so
int s = scale / source.scale();
if (s == 1) {
int x_start = first_column + a_dst_rect.left() * scale;
for (int row = first_row; row <= last_row; ++row) {
for (int row = first_row; row < last_row; ++row) {
ARGB32 const* sl = source.scanline((row + a_dst_rect.top() * scale) % source.physical_height());
for (int x = x_start; x < clipped_rect.width() + x_start; ++x) {
for (int x = x_start; x < clipped_rect.width() + x_start; ++x)
dst[x - x_start] = sl[x % source.physical_width()];
}
dst += dst_skip;
}
} else {
int x_start = first_column + a_dst_rect.left() * scale;
for (int row = first_row; row <= last_row; ++row) {
for (int row = first_row; row < last_row; ++row) {
ARGB32 const* sl = source.scanline(((row + a_dst_rect.top() * scale) / s) % source.physical_height());
for (int x = x_start; x < clipped_rect.width() + x_start; ++x) {
for (int x = x_start; x < clipped_rect.width() + x_start; ++x)
dst[x - x_start] = sl[(x / s) % source.physical_width()];
}
dst += dst_skip;
}
}
@ -1114,7 +1107,7 @@ void Painter::blit(IntPoint position, Gfx::Bitmap const& source, IntRect const&
if (source.format() == BitmapFormat::BGRx8888 || source.format() == BitmapFormat::BGRA8888) {
ARGB32 const* src = source.scanline(src_rect.top() + first_row) + src_rect.left() + first_column;
size_t const src_skip = source.pitch() / sizeof(ARGB32);
for (int row = first_row; row <= last_row; ++row) {
for (int row = first_row; row < last_row; ++row) {
memcpy(dst, src, sizeof(ARGB32) * clipped_rect.width());
dst += dst_skip;
src += src_skip;
@ -1125,7 +1118,7 @@ void Painter::blit(IntPoint position, Gfx::Bitmap const& source, IntRect const&
if (source.format() == BitmapFormat::RGBA8888) {
u32 const* src = source.scanline(src_rect.top() + first_row) + src_rect.left() + first_column;
size_t const src_skip = source.pitch() / sizeof(u32);
for (int row = first_row; row <= last_row; ++row) {
for (int row = first_row; row < last_row; ++row) {
for (int i = 0; i < clipped_rect.width(); ++i) {
u32 rgba = src[i];
u32 bgra = (rgba & 0xff00ff00)
@ -1200,9 +1193,9 @@ ALWAYS_INLINE static void do_draw_box_sampled_scaled_bitmap(Gfx::Bitmap& target,
return (intersected_right - intersected_left) * (intersected_bottom - intersected_top);
};
for (int y = clipped_rect.top(); y <= clipped_rect.bottom(); ++y) {
for (int y = clipped_rect.top(); y < clipped_rect.bottom(); ++y) {
auto* scanline = reinterpret_cast<Color*>(target.scanline(y));
for (int x = clipped_rect.left(); x <= clipped_rect.right(); ++x) {
for (int x = clipped_rect.left(); x < clipped_rect.right(); ++x) {
// Project the destination pixel in the source image
FloatRect const source_box = {
src_rect.left() + (x - dst_rect.x()) * source_pixel_width,
@ -1217,8 +1210,8 @@ ALWAYS_INLINE static void do_draw_box_sampled_scaled_bitmap(Gfx::Bitmap& target,
float green_accumulator = 0.f;
float blue_accumulator = 0.f;
float total_area = 0.f;
for (int sy = enclosing_source_box.y(); sy <= enclosing_source_box.bottom(); ++sy) {
for (int sx = enclosing_source_box.x(); sx <= enclosing_source_box.right(); ++sx) {
for (int sy = enclosing_source_box.y(); sy < enclosing_source_box.bottom(); ++sy) {
for (int sx = enclosing_source_box.x(); sx < enclosing_source_box.right(); ++sx) {
float area = float_rect_intersection_area_fixme(source_box, pixel_box.translated(sx, sy));
auto pixel = get_pixel(source, sx, sy);
@ -1281,11 +1274,11 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect con
i64 src_left = src_rect.left() * shift;
i64 src_top = src_rect.top() * shift;
for (int y = clipped_rect.top(); y <= clipped_rect.bottom(); ++y) {
for (int y = clipped_rect.top(); y < clipped_rect.bottom(); ++y) {
auto* scanline = reinterpret_cast<Color*>(target.scanline(y));
auto desired_y = (y - dst_rect.y()) * vscale + src_top;
for (int x = clipped_rect.left(); x <= clipped_rect.right(); ++x) {
for (int x = clipped_rect.left(); x < clipped_rect.right(); ++x) {
auto desired_x = (x - dst_rect.x()) * hscale + src_left;
Color src_pixel;
@ -1293,10 +1286,10 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect con
auto shifted_x = desired_x + bilinear_offset_x;
auto shifted_y = desired_y + bilinear_offset_y;
auto scaled_x0 = clamp(shifted_x >> 32, clipped_src_rect.left(), clipped_src_rect.right());
auto scaled_x1 = clamp((shifted_x >> 32) + 1, clipped_src_rect.left(), clipped_src_rect.right());
auto scaled_y0 = clamp(shifted_y >> 32, clipped_src_rect.top(), clipped_src_rect.bottom());
auto scaled_y1 = clamp((shifted_y >> 32) + 1, clipped_src_rect.top(), clipped_src_rect.bottom());
auto scaled_x0 = clamp(shifted_x >> 32, clipped_src_rect.left(), clipped_src_rect.right() - 1);
auto scaled_x1 = clamp((shifted_x >> 32) + 1, clipped_src_rect.left(), clipped_src_rect.right() - 1);
auto scaled_y0 = clamp(shifted_y >> 32, clipped_src_rect.top(), clipped_src_rect.bottom() - 1);
auto scaled_y1 = clamp((shifted_y >> 32) + 1, clipped_src_rect.top(), clipped_src_rect.bottom() - 1);
float x_ratio = (shifted_x & fractional_mask) / static_cast<float>(shift);
float y_ratio = (shifted_y & fractional_mask) / static_cast<float>(shift);
@ -1311,10 +1304,10 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect con
src_pixel = top.mixed_with(bottom, y_ratio);
} else if constexpr (scaling_mode == Painter::ScalingMode::SmoothPixels) {
auto scaled_x1 = clamp(desired_x >> 32, clipped_src_rect.left(), clipped_src_rect.right());
auto scaled_x0 = clamp(scaled_x1 - 1, clipped_src_rect.left(), clipped_src_rect.right());
auto scaled_y1 = clamp(desired_y >> 32, clipped_src_rect.top(), clipped_src_rect.bottom());
auto scaled_y0 = clamp(scaled_y1 - 1, clipped_src_rect.top(), clipped_src_rect.bottom());
auto scaled_x1 = clamp(desired_x >> 32, clipped_src_rect.left(), clipped_src_rect.right() - 1);
auto scaled_x0 = clamp(scaled_x1 - 1, clipped_src_rect.left(), clipped_src_rect.right() - 1);
auto scaled_y1 = clamp(desired_y >> 32, clipped_src_rect.top(), clipped_src_rect.bottom() - 1);
auto scaled_y0 = clamp(scaled_y1 - 1, clipped_src_rect.top(), clipped_src_rect.bottom() - 1);
float x_ratio = (desired_x & fractional_mask) / (float)shift;
float y_ratio = (desired_y & fractional_mask) / (float)shift;
@ -1332,8 +1325,8 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect con
src_pixel = top.mixed_with(bottom, scaled_y_ratio);
} else {
auto scaled_x = clamp(desired_x >> 32, clipped_src_rect.left(), clipped_src_rect.right());
auto scaled_y = clamp(desired_y >> 32, clipped_src_rect.top(), clipped_src_rect.bottom());
auto scaled_x = clamp(desired_x >> 32, clipped_src_rect.left(), clipped_src_rect.right() - 1);
auto scaled_y = clamp(desired_y >> 32, clipped_src_rect.top(), clipped_src_rect.bottom() - 1);
src_pixel = get_pixel(source, scaled_x, scaled_y);
}
@ -1556,7 +1549,7 @@ void draw_text_line(FloatRect const& a_rect, Utf8View const& text, Font const& f
case TextAlignment::TopRight:
case TextAlignment::CenterRight:
case TextAlignment::BottomRight:
rect.set_x(rect.right() - font.width(text));
rect.set_x(rect.right() - 1 - font.width(text));
break;
case TextAlignment::TopCenter:
case TextAlignment::BottomCenter:
@ -2043,16 +2036,16 @@ void Painter::draw_line(IntPoint a_p1, IntPoint a_p2, Color color, int thickness
// Special case: vertical line.
if (point1.x() == point2.x()) {
int const x = point1.x();
if (x < clip_rect.left() || x > clip_rect.right())
if (x < clip_rect.left() || x >= clip_rect.right())
return;
if (point1.y() > point2.y())
swap(point1, point2);
if (point1.y() > clip_rect.bottom())
if (point1.y() >= clip_rect.bottom())
return;
if (point2.y() < clip_rect.top())
return;
int min_y = max(point1.y(), clip_rect.top());
int max_y = min(point2.y(), clip_rect.bottom());
int max_y = min(point2.y(), clip_rect.bottom() - 1);
if (style == LineStyle::Dotted) {
for (int y = min_y; y <= max_y; y += thickness * 2)
draw_physical_pixel({ x, y }, color, thickness);
@ -2078,16 +2071,16 @@ void Painter::draw_line(IntPoint a_p1, IntPoint a_p2, Color color, int thickness
// Special case: horizontal line.
if (point1.y() == point2.y()) {
int const y = point1.y();
if (y < clip_rect.top() || y > clip_rect.bottom())
if (y < clip_rect.top() || y >= clip_rect.bottom())
return;
if (point1.x() > point2.x())
swap(point1, point2);
if (point1.x() > clip_rect.right())
if (point1.x() >= clip_rect.right())
return;
if (point2.x() < clip_rect.left())
return;
int min_x = max(point1.x(), clip_rect.left());
int max_x = min(point2.x(), clip_rect.right());
int max_x = min(point2.x(), clip_rect.right() - 1);
if (style == LineStyle::Dotted) {
for (int x = min_x; x <= max_x; x += thickness * 2)
draw_physical_pixel({ x, y }, color, thickness);
@ -2490,19 +2483,17 @@ void Painter::blit_tiled(IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Int
{
auto tile_width = rect.width();
auto tile_height = rect.height();
auto dst_right = dst_rect.right();
auto dst_bottom = dst_rect.bottom();
auto dst_right = dst_rect.right() - 1;
auto dst_bottom = dst_rect.bottom() - 1;
for (int tile_y = dst_rect.top(); tile_y < dst_bottom; tile_y += tile_height) {
for (int tile_x = dst_rect.left(); tile_x < dst_right; tile_x += tile_width) {
IntRect tile_src_rect = rect;
auto tile_x_overflow = tile_x + tile_width - dst_right;
if (tile_x_overflow > 0) {
if (tile_x_overflow > 0)
tile_src_rect.set_width(tile_width - tile_x_overflow);
}
auto tile_y_overflow = tile_y + tile_height - dst_bottom;
if (tile_y_overflow > 0) {
if (tile_y_overflow > 0)
tile_src_rect.set_height(tile_height - tile_y_overflow);
}
blit(IntPoint(tile_x, tile_y), bitmap, tile_src_rect);
}
}
@ -2545,7 +2536,7 @@ void Gfx::Painter::draw_ui_text(Gfx::IntRect const& rect, StringView text, Gfx::
float width = 0;
for (auto it = utf8_view.begin(); it != utf8_view.end(); ++it) {
if (utf8_view.byte_offset_of(it) >= underline_offset.value()) {
int y = text_rect.bottom() + 1;
int y = text_rect.bottom();
int x1 = text_rect.left() + width;
int x2 = x1 + font.glyph_or_emoji_width(it);
draw_line({ x1, y }, { x2, y }, color);

View file

@ -15,8 +15,8 @@ namespace Gfx {
template<typename T>
void Point<T>::constrain(Rect<T> const& rect)
{
m_x = AK::clamp<T>(x(), rect.left(), rect.right());
m_y = AK::clamp<T>(y(), rect.top(), rect.bottom());
m_x = AK::clamp<T>(x(), rect.left(), rect.right() - 1);
m_y = AK::clamp<T>(y(), rect.top(), rect.bottom() - 1);
}
template<typename T>

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
* Copyright (c) 2022-2023, Jelle Raaijmakers <jelle@gmta.nl>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -9,6 +9,7 @@
#pragma once
#include <AK/Format.h>
#include <AK/Vector.h>
#include <LibGfx/AffineTransform.h>
#include <LibGfx/Line.h>
#include <LibGfx/Orientation.h>
@ -19,12 +20,6 @@
namespace Gfx {
template<typename T>
T abst(T value)
{
return value < 0 ? -value : value;
}
template<typename T>
class Rect {
public:
@ -291,17 +286,17 @@ public:
[[nodiscard]] bool contains_vertically(T y) const
{
return y >= top() && y <= bottom();
return y >= top() && y < bottom();
}
[[nodiscard]] bool contains_horizontally(T x) const
{
return x >= left() && x <= right();
return x >= left() && x < right();
}
[[nodiscard]] bool contains(T x, T y) const
{
return x >= m_location.x() && x <= right() && y >= m_location.y() && y <= bottom();
return contains_horizontally(x) && contains_vertically(y);
}
[[nodiscard]] ALWAYS_INLINE bool contains(Point<T> const& point) const
@ -354,29 +349,14 @@ public:
}
[[nodiscard]] ALWAYS_INLINE T left() const { return x(); }
[[nodiscard]] ALWAYS_INLINE T right() const { return x() + width() - 1; }
[[nodiscard]] ALWAYS_INLINE T right() const { return x() + width(); }
[[nodiscard]] ALWAYS_INLINE T top() const { return y(); }
[[nodiscard]] ALWAYS_INLINE T bottom() const { return y() + height() - 1; }
[[nodiscard]] ALWAYS_INLINE T bottom() const { return y() + height(); }
ALWAYS_INLINE void set_left(T left)
{
set_x(left);
}
ALWAYS_INLINE void set_top(T top)
{
set_y(top);
}
ALWAYS_INLINE void set_right(T right)
{
set_width(right - x() + 1);
}
ALWAYS_INLINE void set_bottom(T bottom)
{
set_height(bottom - y() + 1);
}
ALWAYS_INLINE void set_left(T left) { set_x(left); }
ALWAYS_INLINE void set_top(T top) { set_y(top); }
ALWAYS_INLINE void set_right(T right) { set_width(right - x()); }
ALWAYS_INLINE void set_bottom(T bottom) { set_height(bottom - y()); }
void set_right_without_resize(T new_right)
{
@ -392,20 +372,20 @@ public:
[[nodiscard]] bool intersects_vertically(Rect<T> const& other) const
{
return top() <= other.bottom() && other.top() <= bottom();
return top() < other.bottom() && other.top() < bottom();
}
[[nodiscard]] bool intersects_horizontally(Rect<T> const& other) const
{
return left() <= other.right() && other.left() <= right();
return left() < other.right() && other.left() < right();
}
[[nodiscard]] bool intersects(Rect<T> const& other) const
{
return left() <= other.right()
&& other.left() <= right()
&& top() <= other.bottom()
&& other.top() <= bottom();
return left() < other.right()
&& other.left() < right()
&& top() < other.bottom()
&& other.top() < bottom();
}
template<typename Container>
@ -445,25 +425,25 @@ public:
x(),
y(),
width(),
hammer.y() - y()
hammer.y() - y(),
};
Rect<T> bottom_shard {
x(),
hammer.y() + hammer.height(),
hammer.bottom(),
width(),
(y() + height()) - (hammer.y() + hammer.height())
bottom() - hammer.bottom(),
};
Rect<T> left_shard {
x(),
max(hammer.y(), y()),
hammer.x() - x(),
min((hammer.y() + hammer.height()), (y() + height())) - max(hammer.y(), y())
min(hammer.bottom(), bottom()) - max(hammer.y(), y()),
};
Rect<T> right_shard {
hammer.x() + hammer.width(),
hammer.right(),
max(hammer.y(), y()),
right() - hammer.right(),
min((hammer.y() + hammer.height()), (y() + height())) - max(hammer.y(), y())
min(hammer.bottom(), bottom()) - max(hammer.y(), y()),
};
if (!top_shard.is_empty())
pieces.unchecked_append(top_shard);
@ -505,10 +485,10 @@ public:
return;
}
m_location.set_x(l);
m_location.set_y(t);
m_size.set_width((r - l) + 1);
m_size.set_height((b - t) + 1);
set_x(l);
set_y(t);
set_right(r);
set_bottom(b);
}
[[nodiscard]] static Rect<T> centered_on(Point<T> const& center, Size<T> const& size)
@ -518,7 +498,7 @@ public:
[[nodiscard]] static Rect<T> from_two_points(Point<T> const& a, Point<T> const& b)
{
return { min(a.x(), b.x()), min(a.y(), b.y()), abst(a.x() - b.x()), abst(a.y() - b.y()) };
return { min(a.x(), b.x()), min(a.y(), b.y()), AK::abs(a.x() - b.x()), AK::abs(a.y() - b.y()) };
}
[[nodiscard]] static Rect<T> intersection(Rect<T> const& a, Rect<T> const& b)
@ -541,18 +521,18 @@ public:
if (auto point = line.intersected({ top_left(), top_right() }); point.has_value())
points.append({ point.value().x(), y() });
if (auto point = line.intersected({ bottom_left(), bottom_right() }); point.has_value()) {
points.append({ point.value().x(), bottom() });
points.append({ point.value().x(), bottom() - 1 });
if (points.size() == 2)
return points;
}
if (height() > 2) {
if (auto point = line.intersected({ { x(), y() + 1 }, { x(), bottom() - 1 } }); point.has_value()) {
if (auto point = line.intersected({ { x(), y() + 1 }, { x(), bottom() - 2 } }); point.has_value()) {
points.append({ x(), point.value().y() });
if (points.size() == 2)
return points;
}
if (auto point = line.intersected({ { right(), y() + 1 }, { right(), bottom() - 1 } }); point.has_value())
points.append({ right(), point.value().y() });
if (auto point = line.intersected({ { right() - 1, y() + 1 }, { right() - 1, bottom() - 2 } }); point.has_value())
points.append({ right() - 1, point.value().y() });
}
return points;
}
@ -560,11 +540,11 @@ public:
template<typename U = T>
[[nodiscard]] Gfx::Rect<U> interpolated_to(Gfx::Rect<T> const& to, float factor) const
{
VERIFY(factor >= 0.0f);
VERIFY(factor <= 1.0f);
if (factor == 0.0f)
VERIFY(factor >= 0.f);
VERIFY(factor <= 1.f);
if (factor == 0.f)
return *this;
if (factor == 1.0f)
if (factor == 1.f)
return to;
if (this == &to)
return *this;
@ -572,7 +552,7 @@ public:
auto interpolated_top = round_to<U>(mix<float>(y(), to.y(), factor));
auto interpolated_right = round_to<U>(mix<float>(right(), to.right(), factor));
auto interpolated_bottom = round_to<U>(mix<float>(bottom(), to.bottom(), factor));
return { interpolated_left, interpolated_top, interpolated_right - interpolated_left + 1, interpolated_bottom - interpolated_top + 1 };
return { interpolated_left, interpolated_top, interpolated_right - interpolated_left, interpolated_bottom - interpolated_top };
}
[[nodiscard]] float center_point_distance_to(Rect<T> const& other) const
@ -596,7 +576,7 @@ public:
{
auto points = closest_outside_center_points(other);
if (points.is_empty())
return 0.0;
return 0.f;
return Line { points[0], points[0] }.length();
}
@ -679,8 +659,8 @@ public:
check_distance({ top_left(), top_right() });
check_distance({ bottom_left(), bottom_right() });
if (height() > 2) {
check_distance({ { x(), y() + 1 }, { x(), bottom() - 1 } });
check_distance({ { right(), y() + 1 }, { right(), bottom() - 1 } });
check_distance({ { x(), y() + 1 }, { x(), bottom() - 2 } });
check_distance({ { right() - 1, y() + 1 }, { right() - 1, bottom() - 2 } });
}
VERIFY(closest_point.has_value());
VERIFY(side(closest_point.value()) != Side::None);
@ -699,23 +679,23 @@ public:
if (part.x() < other_rect.x()) {
if (part.y() < other_rect.y())
m_top_left = true;
if ((part.y() >= other_rect.y() && part.y() < other_rect.bottom()) || (part.y() <= other_rect.bottom() && part.bottom() > other_rect.y()))
if ((part.y() >= other_rect.y() && part.y() < other_rect.bottom() - 1) || (part.y() < other_rect.bottom() && part.bottom() - 1 > other_rect.y()))
m_left = true;
if (part.y() >= other_rect.bottom() || part.bottom() > other_rect.y())
if (part.y() >= other_rect.bottom() - 1 || part.bottom() - 1 > other_rect.y())
m_bottom_left = true;
}
if (part.x() >= other_rect.x() || part.right() > other_rect.x()) {
if (part.x() >= other_rect.x() || part.right() - 1 > other_rect.x()) {
if (part.y() < other_rect.y())
m_top = true;
if (part.y() >= other_rect.bottom() || part.bottom() > other_rect.bottom())
if (part.y() >= other_rect.bottom() - 1 || part.bottom() > other_rect.bottom())
m_bottom = true;
}
if (part.x() >= other_rect.right() || part.right() > other_rect.right()) {
if (part.x() >= other_rect.right() - 1 || part.right() > other_rect.right()) {
if (part.y() < other_rect.y())
m_top_right = true;
if ((part.y() >= other_rect.y() && part.y() < other_rect.bottom()) || (part.y() <= other_rect.bottom() && part.bottom() > other_rect.y()))
if ((part.y() >= other_rect.y() && part.y() < other_rect.bottom() - 1) || (part.y() < other_rect.bottom() && part.bottom() - 1 > other_rect.y()))
m_right = true;
if (part.y() >= other_rect.bottom() || part.bottom() > other_rect.y())
if (part.y() >= other_rect.bottom() - 1 || part.bottom() - 1 > other_rect.y())
m_bottom_right = true;
}
}
@ -763,9 +743,9 @@ public:
{
if (is_empty())
return Side::None;
if (point.y() == y() || point.y() == bottom())
return (point.x() >= x() && point.x() <= right()) ? (point.y() == y() ? Side::Top : Side::Bottom) : Side::None;
if (point.x() == x() || point.x() == right())
if (point.y() == y() || point.y() == bottom() - 1)
return (point.x() >= x() && point.x() < right()) ? (point.y() == y() ? Side::Top : Side::Bottom) : Side::None;
if (point.x() == x() || point.x() == right() - 1)
return (point.y() > y() && point.y() < bottom()) ? (point.x() == x() ? Side::Left : Side::Right) : Side::None;
return Side::None;
}
@ -778,7 +758,7 @@ public:
case Side::Left:
// Return the area in other that is to the left of this rect
if (other.x() < x()) {
if (other.right() >= x())
if (other.right() > x())
return { other.location(), { x() - other.x(), other.height() } };
else
return other;
@ -787,7 +767,7 @@ public:
case Side::Top:
// Return the area in other that is above this rect
if (other.y() < y()) {
if (other.bottom() >= y())
if (other.bottom() > y())
return { other.location(), { other.width(), y() - other.y() } };
else
return other;
@ -795,18 +775,18 @@ public:
break;
case Side::Right:
// Return the area in other that is to the right of this rect
if (other.right() >= x()) {
if (other.x() <= right())
return { { right() + 1, other.y() }, { other.width() - (right() - other.x()), other.height() } };
if (other.right() > x()) {
if (other.x() < right())
return { { right(), other.y() }, { other.width() - (right() - 1 - other.x()), other.height() } };
else
return other;
}
break;
case Side::Bottom:
// Return the area in other that is below this rect
if (other.bottom() >= y()) {
if (other.y() <= bottom())
return { { other.x(), bottom() + 1 }, { other.width(), other.height() - (bottom() - other.y()) } };
if (other.bottom() > y()) {
if (other.y() < bottom())
return { { other.x(), bottom() }, { other.width(), other.height() - (bottom() - 1 - other.y()) } };
else
return other;
}
@ -878,10 +858,10 @@ public:
return false;
if (intersects(other))
return false;
if (other.x() + other.width() == x() || other.x() == x() + width())
return max(top(), other.top()) <= min(bottom(), other.bottom());
if (other.y() + other.height() == y() || other.y() == y() + height())
return max(left(), other.left()) <= min(right(), other.right());
if (other.right() == x() || other.x() == right())
return max(top(), other.top()) < min(bottom(), other.bottom());
if (other.bottom() == y() || other.y() == bottom())
return max(left(), other.left()) < min(right(), other.right());
return false;
}
@ -923,7 +903,7 @@ public:
set_location(other.location());
return;
case TextAlignment::TopRight:
set_x(other.x() + other.width() - width());
set_x(other.right() - width());
set_y(other.y());
return;
case TextAlignment::CenterLeft:
@ -931,20 +911,20 @@ public:
center_vertically_within(other);
return;
case TextAlignment::CenterRight:
set_x(other.x() + other.width() - width());
set_x(other.right() - width());
center_vertically_within(other);
return;
case TextAlignment::BottomCenter:
center_horizontally_within(other);
set_y(other.y() + other.height() - height());
set_y(other.bottom() - height());
return;
case TextAlignment::BottomLeft:
set_x(other.x());
set_y(other.y() + other.height() - height());
set_y(other.bottom() - height());
return;
case TextAlignment::BottomRight:
set_x(other.x() + other.width() - width());
set_y(other.y() + other.height() - height());
set_x(other.right() - width());
set_y(other.bottom() - height());
return;
}
}
@ -1036,8 +1016,8 @@ using FloatRect = Rect<float>;
{
int x1 = floorf(float_rect.x());
int y1 = floorf(float_rect.y());
int x2 = ceilf(float_rect.x() + float_rect.width());
int y2 = ceilf(float_rect.y() + float_rect.height());
int x2 = ceilf(float_rect.right());
int y2 = ceilf(float_rect.bottom());
return Gfx::IntRect::from_two_points({ x1, y1 }, { x2, y2 });
}