diff --git a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp index ed3083f80e..ca1419e998 100644 --- a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp @@ -77,7 +77,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet Gfx::AntiAliasingPainter aa_painter { painter }; aa_painter.fill_rect_with_rounded_corners(context.rounded_device_rect(color_box.rect).to_type(), - background_color, color_box.radii.top_left.as_corner(), color_box.radii.top_right.as_corner(), color_box.radii.bottom_right.as_corner(), color_box.radii.bottom_left.as_corner()); + background_color, color_box.radii.top_left.as_corner(context), color_box.radii.top_right.as_corner(context), color_box.radii.bottom_right.as_corner(context), color_box.radii.bottom_left.as_corner(context)); if (!has_paintable_layers) return; @@ -114,7 +114,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet CSSPixelRect const& css_clip_rect = clip_box.rect; auto clip_rect = context.rounded_device_rect(css_clip_rect); painter.add_clip_rect(clip_rect.to_type()); - ScopedCornerRadiusClip corner_clip { painter, clip_rect.to_type(), clip_box.radii }; + ScopedCornerRadiusClip corner_clip { context, painter, clip_rect, clip_box.radii }; if (layer.clip == CSS::BackgroundBox::BorderBox) { // Shrink the effective clip rect if to account for the bits the borders will definitely paint over diff --git a/Userland/Libraries/LibWeb/Painting/BorderPainting.cpp b/Userland/Libraries/LibWeb/Painting/BorderPainting.cpp index d29fd8ccad..db94d80214 100644 --- a/Userland/Libraries/LibWeb/Painting/BorderPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/BorderPainting.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, Andreas Kling - * Copyright (c) 2021, Sam Atkins + * Copyright (c) 2021-2022, Sam Atkins * Copyright (c) 2022, MacDue * * SPDX-License-Identifier: BSD-2-Clause @@ -14,7 +14,7 @@ namespace Web::Painting { -BorderRadiiData normalized_border_radii_data(Layout::Node const& node, Gfx::FloatRect const& rect, CSS::BorderRadiusData top_left_radius, CSS::BorderRadiusData top_right_radius, CSS::BorderRadiusData bottom_right_radius, CSS::BorderRadiusData bottom_left_radius) +BorderRadiiData normalized_border_radii_data(Layout::Node const& node, CSSPixelRect const& rect, CSS::BorderRadiusData top_left_radius, CSS::BorderRadiusData top_right_radius, CSS::BorderRadiusData bottom_right_radius, CSS::BorderRadiusData bottom_left_radius) { BorderRadiusData bottom_left_radius_px {}; BorderRadiusData bottom_right_radius_px {}; @@ -34,15 +34,15 @@ BorderRadiiData normalized_border_radii_data(Layout::Node const& node, Gfx::Floa top_right_radius_px.vertical_radius = top_right_radius.vertical_radius.resolved(node, height_length).to_px(node); // Scale overlapping curves according to https://www.w3.org/TR/css-backgrounds-3/#corner-overlap - auto f = 1.0f; - auto width_reciprocal = 1.0f / rect.width(); - auto height_reciprocal = 1.0f / rect.height(); + CSSPixels f = 1.0f; + auto width_reciprocal = 1.0f / rect.width().value(); + auto height_reciprocal = 1.0f / rect.height().value(); f = max(f, width_reciprocal * (top_left_radius_px.horizontal_radius + top_right_radius_px.horizontal_radius)); f = max(f, height_reciprocal * (top_right_radius_px.vertical_radius + bottom_right_radius_px.vertical_radius)); f = max(f, width_reciprocal * (bottom_left_radius_px.horizontal_radius + bottom_right_radius_px.horizontal_radius)); f = max(f, height_reciprocal * (top_left_radius_px.vertical_radius + bottom_left_radius_px.vertical_radius)); - f = 1.0f / f; + f = 1.0f / f.value(); top_left_radius_px.horizontal_radius *= f; top_left_radius_px.vertical_radius *= f; @@ -56,7 +56,7 @@ BorderRadiiData normalized_border_radii_data(Layout::Node const& node, Gfx::Floa return BorderRadiiData { top_left_radius_px, top_right_radius_px, bottom_right_radius_px, bottom_left_radius_px }; } -void paint_border(PaintContext& context, BorderEdge edge, Gfx::IntRect const& rect, BorderRadiiData const& border_radii_data, BordersData const& borders_data) +void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const& rect, BorderRadiiData const& border_radii_data, BordersData const& borders_data) { auto const& border_data = [&] { switch (edge) { @@ -71,20 +71,20 @@ void paint_border(PaintContext& context, BorderEdge edge, Gfx::IntRect const& re } }(); - float width = border_data.width; + CSSPixels width = border_data.width; if (width <= 0) return; auto color = border_data.color; auto border_style = border_data.line_style; - int int_width = ceilf(width); + auto device_pixel_width = context.enclosing_device_pixels(width); struct Points { - Gfx::IntPoint p1; - Gfx::IntPoint p2; + DevicePixelPoint p1; + DevicePixelPoint p2; }; - auto points_for_edge = [](BorderEdge edge, Gfx::IntRect const& rect) -> Points { + auto points_for_edge = [](BorderEdge edge, DevicePixelRect const& rect) -> Points { switch (edge) { case BorderEdge::Top: return { rect.top_left(), rect.top_right() }; @@ -117,28 +117,28 @@ void paint_border(PaintContext& context, BorderEdge edge, Gfx::IntRect const& re auto [p1, p2] = points_for_edge(edge, rect); switch (edge) { case BorderEdge::Top: - p1.translate_by(int_width / 2, int_width / 2); - p2.translate_by(-int_width / 2, int_width / 2); + p1.translate_by(device_pixel_width / 2, device_pixel_width / 2); + p2.translate_by(-device_pixel_width / 2, device_pixel_width / 2); break; case BorderEdge::Right: - p1.translate_by(-int_width / 2, int_width / 2); - p2.translate_by(-int_width / 2, -int_width / 2); + p1.translate_by(-device_pixel_width / 2, device_pixel_width / 2); + p2.translate_by(-device_pixel_width / 2, -device_pixel_width / 2); break; case BorderEdge::Bottom: - p1.translate_by(int_width / 2, -int_width / 2); - p2.translate_by(-int_width / 2, -int_width / 2); + p1.translate_by(device_pixel_width / 2, -device_pixel_width / 2); + p2.translate_by(-device_pixel_width / 2, -device_pixel_width / 2); break; case BorderEdge::Left: - p1.translate_by(int_width / 2, int_width / 2); - p2.translate_by(int_width / 2, -int_width / 2); + p1.translate_by(device_pixel_width / 2, device_pixel_width / 2); + p2.translate_by(device_pixel_width / 2, -device_pixel_width / 2); break; } if (border_style == CSS::LineStyle::Dotted) { Gfx::AntiAliasingPainter aa_painter { context.painter() }; - aa_painter.draw_line(p1.to_type(), p2.to_type(), color, int_width, gfx_line_style); + aa_painter.draw_line(p1.to_type(), p2.to_type(), color, device_pixel_width.value(), gfx_line_style); return; } - context.painter().draw_line(p1, p2, color, int_width, gfx_line_style); + context.painter().draw_line(p1.to_type(), p2.to_type(), color, device_pixel_width.value(), gfx_line_style); return; } @@ -146,19 +146,17 @@ void paint_border(PaintContext& context, BorderEdge edge, Gfx::IntRect const& re // Note: Using fill_rect() here since draw_line() produces some overlapping pixels // at the end of a line, which cause issues on borders with transparency. p2.translate_by(1, 1); - context.painter().fill_rect(Gfx::IntRect::from_two_points(p1, p2), color); + context.painter().fill_rect(Gfx::IntRect::from_two_points(p1.template to_type(), p2.template to_type()), color); }; auto draw_border = [&](auto const& border, auto const& radius, auto const& opposite_border, auto const& opposite_radius, auto p1_step_translate, auto p2_step_translate) { auto [p1, p2] = points_for_edge(edge, rect); - auto current_p1 = p1.to_type(); - auto current_p2 = p2.to_type(); - auto p1_step = radius ? 0 : border.width / static_cast(int_width); - auto p2_step = opposite_radius ? 0 : opposite_border.width / static_cast(int_width); - for (int i = 0; i < int_width; ++i) { - draw_horizontal_or_vertical_line(current_p1.to_type(), current_p2.to_type()); - p1_step_translate(current_p1, p1_step); - p2_step_translate(current_p2, p2_step); + auto p1_step = radius ? 0 : border.width / static_cast(device_pixel_width.value()); + auto p2_step = opposite_radius ? 0 : opposite_border.width / static_cast(device_pixel_width.value()); + for (DevicePixels i = 0; i < device_pixel_width; ++i) { + draw_horizontal_or_vertical_line(p1, p2); + p1_step_translate(p1, p1_step); + p2_step_translate(p2, p2_step); } }; @@ -209,10 +207,10 @@ void paint_border(PaintContext& context, BorderEdge edge, Gfx::IntRect const& re } } -RefPtr get_cached_corner_bitmap(Gfx::IntSize corners_size) +RefPtr get_cached_corner_bitmap(DevicePixelSize corners_size) { auto allocate_mask_bitmap = [&]() -> RefPtr { - auto bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, corners_size); + auto bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, corners_size.to_type()); if (!bitmap.is_error()) return bitmap.release_value(); return nullptr; @@ -221,7 +219,7 @@ RefPtr get_cached_corner_bitmap(Gfx::IntSize corners_size) static thread_local auto corner_bitmap = allocate_mask_bitmap(); // Only reallocate the corner bitmap is the existing one is too small. // (should mean no more allocations after the first paint -- amortised zero allocations :^)) - if (corner_bitmap && corner_bitmap->rect().size().contains(corners_size)) { + if (corner_bitmap && corner_bitmap->rect().size().contains(corners_size.to_type())) { Gfx::Painter painter { *corner_bitmap }; painter.clear_rect({ { 0, 0 }, corners_size }, Gfx::Color()); } else { @@ -234,17 +232,17 @@ RefPtr get_cached_corner_bitmap(Gfx::IntSize corners_size) return corner_bitmap; } -void paint_all_borders(PaintContext& context, Gfx::FloatRect const& bordered_rect, BorderRadiiData const& border_radii_data, BordersData const& borders_data) +void paint_all_borders(PaintContext& context, CSSPixelRect const& bordered_rect, BorderRadiiData const& border_radii_data, BordersData const& borders_data) { if (borders_data.top.width <= 0 && borders_data.right.width <= 0 && borders_data.left.width <= 0 && borders_data.bottom.width <= 0) return; - Gfx::IntRect border_rect = bordered_rect.to_rounded(); + auto border_rect = context.rounded_device_rect(bordered_rect); - auto top_left = border_radii_data.top_left.as_corner(); - auto top_right = border_radii_data.top_right.as_corner(); - auto bottom_right = border_radii_data.bottom_right.as_corner(); - auto bottom_left = border_radii_data.bottom_left.as_corner(); + auto top_left = border_radii_data.top_left.as_corner(context); + auto top_right = border_radii_data.top_right.as_corner(context); + auto bottom_right = border_radii_data.bottom_right.as_corner(context); + auto bottom_left = border_radii_data.bottom_left.as_corner(context); // Disable border radii if the corresponding borders don't exist: if (borders_data.bottom.width <= 0 && borders_data.left.width <= 0) @@ -256,32 +254,28 @@ void paint_all_borders(PaintContext& context, Gfx::FloatRect const& bordered_rec if (borders_data.top.width <= 0 && borders_data.right.width <= 0) top_right = { 0, 0 }; - auto int_width = [&](auto value) -> int { - return ceilf(value); - }; - - Gfx::IntRect top_border_rect = { + DevicePixelRect top_border_rect = { border_rect.x() + top_left.horizontal_radius, border_rect.y(), border_rect.width() - top_left.horizontal_radius - top_right.horizontal_radius, - int_width(borders_data.top.width) + context.enclosing_device_pixels(borders_data.top.width) }; - Gfx::IntRect right_border_rect = { - border_rect.x() + (border_rect.width() - int_width(borders_data.right.width)), + DevicePixelRect right_border_rect = { + border_rect.x() + (border_rect.width() - context.enclosing_device_pixels(borders_data.right.width)), border_rect.y() + top_right.vertical_radius, - int_width(borders_data.right.width), + context.enclosing_device_pixels(borders_data.right.width), border_rect.height() - top_right.vertical_radius - bottom_right.vertical_radius }; - Gfx::IntRect bottom_border_rect = { + DevicePixelRect bottom_border_rect = { border_rect.x() + bottom_left.horizontal_radius, - border_rect.y() + (border_rect.height() - int_width(borders_data.bottom.width)), + border_rect.y() + (border_rect.height() - context.enclosing_device_pixels(borders_data.bottom.width)), border_rect.width() - bottom_left.horizontal_radius - bottom_right.horizontal_radius, - int_width(borders_data.bottom.width) + context.enclosing_device_pixels(borders_data.bottom.width) }; - Gfx::IntRect left_border_rect = { + DevicePixelRect left_border_rect = { border_rect.x(), border_rect.y() + top_left.vertical_radius, - int_width(borders_data.left.width), + context.enclosing_device_pixels(borders_data.left.width), border_rect.height() - top_left.vertical_radius - bottom_left.vertical_radius }; @@ -308,16 +302,16 @@ void paint_all_borders(PaintContext& context, Gfx::FloatRect const& bordered_rec return; // Cache the smallest possible bitmap to render just the corners for the border. - auto expand_width = abs(int_width(borders_data.left.width) - int_width(borders_data.right.width)); - auto expand_height = abs(int_width(borders_data.top.width) - int_width(borders_data.bottom.width)); - Gfx::IntRect corner_mask_rect { + auto expand_width = abs(context.enclosing_device_pixels(borders_data.left.width) - context.enclosing_device_pixels(borders_data.right.width)); + auto expand_height = abs(context.enclosing_device_pixels(borders_data.top.width) - context.enclosing_device_pixels(borders_data.bottom.width)); + DevicePixelRect corner_mask_rect { 0, 0, max( - top_left.horizontal_radius + top_right.horizontal_radius + expand_width, - bottom_left.horizontal_radius + bottom_right.horizontal_radius + expand_height), + top_left.horizontal_radius + top_right.horizontal_radius + expand_width.value(), + bottom_left.horizontal_radius + bottom_right.horizontal_radius + expand_height.value()), max( - top_left.vertical_radius + bottom_left.vertical_radius + expand_width, - top_right.vertical_radius + bottom_right.vertical_radius + expand_height) + top_left.vertical_radius + bottom_left.vertical_radius + expand_width.value(), + top_right.vertical_radius + bottom_right.vertical_radius + expand_height.value()) }; auto corner_bitmap = get_cached_corner_bitmap(corner_mask_rect.size()); @@ -331,27 +325,27 @@ void paint_all_borders(PaintContext& context, Gfx::FloatRect const& bordered_rec // TODO: Support various line styles on the corners (dotted, dashes, etc) // Paint the outer (minimal) corner rounded rectangle: - aa_painter.fill_rect_with_rounded_corners(corner_mask_rect, border_color_no_alpha, top_left, top_right, bottom_right, bottom_left); + aa_painter.fill_rect_with_rounded_corners(corner_mask_rect.to_type(), border_color_no_alpha, top_left, top_right, bottom_right, bottom_left); // Subtract the inner corner rectangle: auto inner_corner_mask_rect = corner_mask_rect.shrunken( - int_width(borders_data.top.width), - int_width(borders_data.right.width), - int_width(borders_data.bottom.width), - int_width(borders_data.left.width)); + context.enclosing_device_pixels(borders_data.top.width), + context.enclosing_device_pixels(borders_data.right.width), + context.enclosing_device_pixels(borders_data.bottom.width), + context.enclosing_device_pixels(borders_data.left.width)); auto inner_top_left = top_left; auto inner_top_right = top_right; auto inner_bottom_right = bottom_right; auto inner_bottom_left = bottom_left; - inner_top_left.horizontal_radius = max(0, inner_top_left.horizontal_radius - int_width(borders_data.left.width)); - inner_top_left.vertical_radius = max(0, inner_top_left.vertical_radius - int_width(borders_data.top.width)); - inner_top_right.horizontal_radius = max(0, inner_top_right.horizontal_radius - int_width(borders_data.right.width)); - inner_top_right.vertical_radius = max(0, inner_top_right.vertical_radius - int_width(borders_data.top.width)); - inner_bottom_right.horizontal_radius = max(0, inner_bottom_right.horizontal_radius - int_width(borders_data.right.width)); - inner_bottom_right.vertical_radius = max(0, inner_bottom_right.vertical_radius - int_width(borders_data.bottom.width)); - inner_bottom_left.horizontal_radius = max(0, inner_bottom_left.horizontal_radius - int_width(borders_data.left.width)); - inner_bottom_left.vertical_radius = max(0, inner_bottom_left.vertical_radius - int_width(borders_data.bottom.width)); - aa_painter.fill_rect_with_rounded_corners(inner_corner_mask_rect, border_color_no_alpha, inner_top_left, inner_top_right, inner_bottom_right, inner_bottom_left, Gfx::AntiAliasingPainter::BlendMode::AlphaSubtract); + inner_top_left.horizontal_radius = max(0, inner_top_left.horizontal_radius - context.enclosing_device_pixels(borders_data.left.width).value()); + inner_top_left.vertical_radius = max(0, inner_top_left.vertical_radius - context.enclosing_device_pixels(borders_data.top.width).value()); + inner_top_right.horizontal_radius = max(0, inner_top_right.horizontal_radius - context.enclosing_device_pixels(borders_data.right.width).value()); + inner_top_right.vertical_radius = max(0, inner_top_right.vertical_radius - context.enclosing_device_pixels(borders_data.top.width).value()); + inner_bottom_right.horizontal_radius = max(0, inner_bottom_right.horizontal_radius - context.enclosing_device_pixels(borders_data.right.width).value()); + inner_bottom_right.vertical_radius = max(0, inner_bottom_right.vertical_radius - context.enclosing_device_pixels(borders_data.bottom.width).value()); + inner_bottom_left.horizontal_radius = max(0, inner_bottom_left.horizontal_radius - context.enclosing_device_pixels(borders_data.left.width).value()); + inner_bottom_left.vertical_radius = max(0, inner_bottom_left.vertical_radius - context.enclosing_device_pixels(borders_data.bottom.width).value()); + aa_painter.fill_rect_with_rounded_corners(inner_corner_mask_rect.to_type(), border_color_no_alpha, inner_top_left, inner_top_right, inner_bottom_right, inner_bottom_left, Gfx::AntiAliasingPainter::BlendMode::AlphaSubtract); // TODO: Support dual color corners. Other browsers will render a rounded corner between two borders of // different colors using both colours, normally split at a 45 degree angle (though the exact angle is interpolated). @@ -370,16 +364,16 @@ void paint_all_borders(PaintContext& context, Gfx::FloatRect const& bordered_rec // Blit the corners into to their corresponding locations: if (top_left) - blit_corner(border_rect.top_left(), top_left.as_rect(), pick_corner_color(borders_data.top, borders_data.left)); + blit_corner(border_rect.top_left().to_type(), top_left.as_rect(), pick_corner_color(borders_data.top, borders_data.left)); if (top_right) - blit_corner(border_rect.top_right().translated(-top_right.horizontal_radius + 1, 0), top_right.as_rect().translated(corner_mask_rect.width() - top_right.horizontal_radius, 0), pick_corner_color(borders_data.top, borders_data.right)); + blit_corner(border_rect.top_right().to_type().translated(-top_right.horizontal_radius + 1, 0), top_right.as_rect().translated(corner_mask_rect.width().value() - top_right.horizontal_radius, 0), pick_corner_color(borders_data.top, borders_data.right)); if (bottom_right) - blit_corner(border_rect.bottom_right().translated(-bottom_right.horizontal_radius + 1, -bottom_right.vertical_radius + 1), bottom_right.as_rect().translated(corner_mask_rect.width() - bottom_right.horizontal_radius, corner_mask_rect.height() - bottom_right.vertical_radius), pick_corner_color(borders_data.bottom, borders_data.right)); + blit_corner(border_rect.bottom_right().to_type().translated(-bottom_right.horizontal_radius + 1, -bottom_right.vertical_radius + 1), bottom_right.as_rect().translated(corner_mask_rect.width().value() - bottom_right.horizontal_radius, corner_mask_rect.height().value() - bottom_right.vertical_radius), pick_corner_color(borders_data.bottom, borders_data.right)); if (bottom_left) - blit_corner(border_rect.bottom_left().translated(0, -bottom_left.vertical_radius + 1), bottom_left.as_rect().translated(0, corner_mask_rect.height() - bottom_left.vertical_radius), pick_corner_color(borders_data.bottom, borders_data.left)); + blit_corner(border_rect.bottom_left().to_type().translated(0, -bottom_left.vertical_radius + 1), bottom_left.as_rect().translated(0, corner_mask_rect.height().value() - bottom_left.vertical_radius), pick_corner_color(borders_data.bottom, borders_data.left)); } } diff --git a/Userland/Libraries/LibWeb/Painting/BorderPainting.h b/Userland/Libraries/LibWeb/Painting/BorderPainting.h index 06e9927c30..462058321a 100644 --- a/Userland/Libraries/LibWeb/Painting/BorderPainting.h +++ b/Userland/Libraries/LibWeb/Painting/BorderPainting.h @@ -13,26 +13,26 @@ namespace Web::Painting { struct BorderRadiusData { - float horizontal_radius { 0 }; - float vertical_radius { 0 }; + CSSPixels horizontal_radius { 0 }; + CSSPixels vertical_radius { 0 }; - Gfx::AntiAliasingPainter::CornerRadius as_corner() const + Gfx::AntiAliasingPainter::CornerRadius as_corner(PaintContext& context) const { return Gfx::AntiAliasingPainter::CornerRadius { - static_cast(horizontal_radius), - static_cast(vertical_radius) + context.floored_device_pixels(horizontal_radius).value(), + context.floored_device_pixels(vertical_radius).value() }; }; inline operator bool() const { - return static_cast(horizontal_radius) > 0 && static_cast(vertical_radius) > 0; + return horizontal_radius > 0 && vertical_radius > 0; } - inline void shrink(float horizontal, float vertical) + inline void shrink(CSSPixels horizontal, CSSPixels vertical) { - horizontal_radius = max(0, horizontal_radius - horizontal); - vertical_radius = max(0, vertical_radius - vertical); + horizontal_radius = max(CSSPixels(0), horizontal_radius - horizontal); + vertical_radius = max(CSSPixels(0), vertical_radius - vertical); } }; @@ -47,7 +47,7 @@ struct BorderRadiiData { return top_left || top_right || bottom_right || bottom_left; } - inline void shrink(float top, float right, float bottom, float left) + inline void shrink(CSSPixels top, CSSPixels right, CSSPixels bottom, CSSPixels left) { top_left.shrink(left, top); top_right.shrink(right, top); @@ -56,7 +56,7 @@ struct BorderRadiiData { } }; -BorderRadiiData normalized_border_radii_data(Layout::Node const&, Gfx::FloatRect const&, CSS::BorderRadiusData top_left_radius, CSS::BorderRadiusData top_right_radius, CSS::BorderRadiusData bottom_right_radius, CSS::BorderRadiusData bottom_left_radius); +BorderRadiiData normalized_border_radii_data(Layout::Node const&, CSSPixelRect const&, CSS::BorderRadiusData top_left_radius, CSS::BorderRadiusData top_right_radius, CSS::BorderRadiusData bottom_right_radius, CSS::BorderRadiusData bottom_left_radius); enum class BorderEdge { Top, @@ -71,9 +71,9 @@ struct BordersData { CSS::BorderData left; }; -RefPtr get_cached_corner_bitmap(Gfx::IntSize corners_size); +RefPtr get_cached_corner_bitmap(DevicePixelSize corners_size); -void paint_border(PaintContext& context, BorderEdge edge, Gfx::IntRect const& rect, BorderRadiiData const& border_radii_data, BordersData const& borders_data); -void paint_all_borders(PaintContext& context, Gfx::FloatRect const& bordered_rect, BorderRadiiData const& border_radii_data, BordersData const&); +void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const& rect, BorderRadiiData const& border_radii_data, BordersData const& borders_data); +void paint_all_borders(PaintContext& context, CSSPixelRect const& bordered_rect, BorderRadiiData const& border_radii_data, BordersData const&); } diff --git a/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp b/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp index 7b21ebe38c..7c2db4f92b 100644 --- a/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp +++ b/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp @@ -10,16 +10,16 @@ namespace Web::Painting { -ErrorOr BorderRadiusCornerClipper::create(Gfx::IntRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip, UseCachedBitmap use_cached_bitmap) +ErrorOr BorderRadiusCornerClipper::create(PaintContext& context, DevicePixelRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip, UseCachedBitmap use_cached_bitmap) { VERIFY(border_radii.has_any_radius()); - auto top_left = border_radii.top_left.as_corner(); - auto top_right = border_radii.top_right.as_corner(); - auto bottom_right = border_radii.bottom_right.as_corner(); - auto bottom_left = border_radii.bottom_left.as_corner(); + auto top_left = border_radii.top_left.as_corner(context); + auto top_right = border_radii.top_right.as_corner(context); + auto bottom_right = border_radii.bottom_right.as_corner(context); + auto bottom_left = border_radii.bottom_left.as_corner(context); - Gfx::IntSize corners_bitmap_size { + DevicePixelSize corners_bitmap_size { max( top_left.horizontal_radius + top_right.horizontal_radius, bottom_left.horizontal_radius + bottom_right.horizontal_radius), @@ -34,7 +34,7 @@ ErrorOr BorderRadiusCornerClipper::create(Gfx::IntRec if (!corner_bitmap) return Error::from_errno(ENOMEM); } else { - corner_bitmap = TRY(Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, corners_bitmap_size)); + corner_bitmap = TRY(Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, corners_bitmap_size.to_type())); } CornerData corner_data { @@ -60,7 +60,7 @@ void BorderRadiusCornerClipper::sample_under_corners(Gfx::Painter& page_painter) corner_aa_painter.fill_rect_with_rounded_corners(corner_rect, Color::NamedColor::Black, m_data.corner_radii.top_left, m_data.corner_radii.top_right, m_data.corner_radii.bottom_right, m_data.corner_radii.bottom_left); - auto copy_page_masked = [&](auto const& mask_src, auto const& page_location) { + auto copy_page_masked = [&](Gfx::IntRect const& mask_src, Gfx::IntPoint const& page_location) { for (int row = 0; row < mask_src.height(); ++row) { for (int col = 0; col < mask_src.width(); ++col) { auto corner_location = mask_src.location().translated(col, row); @@ -81,13 +81,13 @@ void BorderRadiusCornerClipper::sample_under_corners(Gfx::Painter& page_painter) // Copy the pixels under the corner mask (using the alpha of the mask): if (m_data.corner_radii.top_left) - copy_page_masked(m_data.corner_radii.top_left.as_rect().translated(m_data.bitmap_locations.top_left), m_data.page_locations.top_left); + copy_page_masked(m_data.corner_radii.top_left.as_rect().translated(m_data.bitmap_locations.top_left.to_type()), m_data.page_locations.top_left.to_type()); if (m_data.corner_radii.top_right) - copy_page_masked(m_data.corner_radii.top_right.as_rect().translated(m_data.bitmap_locations.top_right), m_data.page_locations.top_right); + copy_page_masked(m_data.corner_radii.top_right.as_rect().translated(m_data.bitmap_locations.top_right.to_type()), m_data.page_locations.top_right.to_type()); if (m_data.corner_radii.bottom_right) - copy_page_masked(m_data.corner_radii.bottom_right.as_rect().translated(m_data.bitmap_locations.bottom_right), m_data.page_locations.bottom_right); + copy_page_masked(m_data.corner_radii.bottom_right.as_rect().translated(m_data.bitmap_locations.bottom_right.to_type()), m_data.page_locations.bottom_right.to_type()); if (m_data.corner_radii.bottom_left) - copy_page_masked(m_data.corner_radii.bottom_left.as_rect().translated(m_data.bitmap_locations.bottom_left), m_data.page_locations.bottom_left); + copy_page_masked(m_data.corner_radii.bottom_left.as_rect().translated(m_data.bitmap_locations.bottom_left.to_type()), m_data.page_locations.bottom_left.to_type()); m_has_sampled = true; } @@ -98,13 +98,13 @@ void BorderRadiusCornerClipper::blit_corner_clipping(Gfx::Painter& painter) // Restore the corners: if (m_data.corner_radii.top_left) - painter.blit(m_data.page_locations.top_left, *m_corner_bitmap, m_data.corner_radii.top_left.as_rect().translated(m_data.bitmap_locations.top_left)); + painter.blit(m_data.page_locations.top_left.to_type(), *m_corner_bitmap, m_data.corner_radii.top_left.as_rect().translated(m_data.bitmap_locations.top_left.to_type())); if (m_data.corner_radii.top_right) - painter.blit(m_data.page_locations.top_right, *m_corner_bitmap, m_data.corner_radii.top_right.as_rect().translated(m_data.bitmap_locations.top_right)); + painter.blit(m_data.page_locations.top_right.to_type(), *m_corner_bitmap, m_data.corner_radii.top_right.as_rect().translated(m_data.bitmap_locations.top_right.to_type())); if (m_data.corner_radii.bottom_right) - painter.blit(m_data.page_locations.bottom_right, *m_corner_bitmap, m_data.corner_radii.bottom_right.as_rect().translated(m_data.bitmap_locations.bottom_right)); + painter.blit(m_data.page_locations.bottom_right.to_type(), *m_corner_bitmap, m_data.corner_radii.bottom_right.as_rect().translated(m_data.bitmap_locations.bottom_right.to_type())); if (m_data.corner_radii.bottom_left) - painter.blit(m_data.page_locations.bottom_left, *m_corner_bitmap, m_data.corner_radii.bottom_left.as_rect().translated(m_data.bitmap_locations.bottom_left)); + painter.blit(m_data.page_locations.bottom_left.to_type(), *m_corner_bitmap, m_data.corner_radii.bottom_left.as_rect().translated(m_data.bitmap_locations.bottom_left.to_type())); } } diff --git a/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.h b/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.h index 602395f246..00a090379c 100644 --- a/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.h +++ b/Userland/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.h @@ -23,7 +23,7 @@ public: No }; - static ErrorOr create(Gfx::IntRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip = CornerClip::Outside, UseCachedBitmap use_cached_bitmap = UseCachedBitmap::Yes); + static ErrorOr create(PaintContext&, DevicePixelRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip = CornerClip::Outside, UseCachedBitmap use_cached_bitmap = UseCachedBitmap::Yes); void sample_under_corners(Gfx::Painter& page_painter); void blit_corner_clipping(Gfx::Painter& page_painter); @@ -38,14 +38,14 @@ private: CornerRadius bottom_left; } corner_radii; struct CornerLocations { - Gfx::IntPoint top_left; - Gfx::IntPoint top_right; - Gfx::IntPoint bottom_right; - Gfx::IntPoint bottom_left; + DevicePixelPoint top_left; + DevicePixelPoint top_right; + DevicePixelPoint bottom_right; + DevicePixelPoint bottom_left; }; CornerLocations page_locations; CornerLocations bitmap_locations; - Gfx::IntSize corner_bitmap_size; + DevicePixelSize corner_bitmap_size; } m_data; NonnullRefPtr m_corner_bitmap; @@ -61,11 +61,11 @@ private: }; struct ScopedCornerRadiusClip { - ScopedCornerRadiusClip(Gfx::Painter& painter, Gfx::IntRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip = CornerClip::Outside, BorderRadiusCornerClipper::UseCachedBitmap use_cached_bitmap = BorderRadiusCornerClipper::UseCachedBitmap::Yes) + ScopedCornerRadiusClip(PaintContext& context, Gfx::Painter& painter, DevicePixelRect const& border_rect, BorderRadiiData const& border_radii, CornerClip corner_clip = CornerClip::Outside, BorderRadiusCornerClipper::UseCachedBitmap use_cached_bitmap = BorderRadiusCornerClipper::UseCachedBitmap::Yes) : m_painter(painter) { if (border_radii.has_any_radius()) { - auto clipper = BorderRadiusCornerClipper::create(border_rect, border_radii, corner_clip, use_cached_bitmap); + auto clipper = BorderRadiusCornerClipper::create(context, border_rect, border_radii, corner_clip, use_cached_bitmap); if (!clipper.is_error()) { m_corner_clipper = clipper.release_value(); m_corner_clipper->sample_under_corners(m_painter); diff --git a/Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp b/Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp index 82253eaa09..ff584c6cb0 100644 --- a/Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp @@ -31,8 +31,8 @@ void CanvasPaintable::paint(PaintContext& context, PaintPhase phase) const PaintableBox::paint(context, phase); if (phase == PaintPhase::Foreground) { - auto canvas_rect = absolute_rect().to_rounded(); - ScopedCornerRadiusClip corner_clip { context.painter(), canvas_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) }; + auto canvas_rect = context.rounded_device_rect(absolute_rect().to_type()); + ScopedCornerRadiusClip corner_clip { context, context.painter(), canvas_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) }; // FIXME: This should be done at a different level. if (is_out_of_view(context)) @@ -41,7 +41,7 @@ void CanvasPaintable::paint(PaintContext& context, PaintPhase phase) const if (layout_box().dom_node().bitmap()) { // FIXME: Remove this const_cast. const_cast(layout_box().dom_node()).present(); - context.painter().draw_scaled_bitmap(canvas_rect, *layout_box().dom_node().bitmap(), layout_box().dom_node().bitmap()->rect(), 1.0f, to_gfx_scaling_mode(computed_values().image_rendering())); + context.painter().draw_scaled_bitmap(canvas_rect.to_type(), *layout_box().dom_node().bitmap(), layout_box().dom_node().bitmap()->rect(), 1.0f, to_gfx_scaling_mode(computed_values().image_rendering())); } } } diff --git a/Userland/Libraries/LibWeb/Painting/FilterPainting.cpp b/Userland/Libraries/LibWeb/Painting/FilterPainting.cpp index 650e5d8357..793faefb35 100644 --- a/Userland/Libraries/LibWeb/Painting/FilterPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/FilterPainting.cpp @@ -125,7 +125,7 @@ void apply_backdrop_filter(PaintContext& context, Layout::Node const& node, Gfx: // FIXME: 3. If element B has any transforms (between B and the Backdrop Root), apply the inverse of those transforms to the contents of T’. // 4. Apply a clip to the contents of T’, using the border box of element B, including border-radius if specified. Note that the children of B are not considered for the sizing or location of this clip. - ScopedCornerRadiusClip corner_clipper { context.painter(), backdrop_region, border_radii_data }; + ScopedCornerRadiusClip corner_clipper { context, context.painter(), backdrop_region.to_type(), border_radii_data }; // FIXME: 5. Draw all of element B, including its background, border, and any children elements, into T’. diff --git a/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp b/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp index 3e46cc1cf5..2fdfb30dc7 100644 --- a/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp @@ -49,9 +49,9 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const alt = image_element.src(); context.painter().draw_text(enclosing_int_rect(absolute_rect()), alt, Gfx::TextAlignment::Center, computed_values().color(), Gfx::TextElision::Right); } else if (auto bitmap = layout_box().image_loader().bitmap(layout_box().image_loader().current_frame_index())) { - auto image_rect = absolute_rect().to_rounded(); - ScopedCornerRadiusClip corner_clip { context.painter(), image_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) }; - context.painter().draw_scaled_bitmap(image_rect, *bitmap, bitmap->rect(), 1.0f, to_gfx_scaling_mode(computed_values().image_rendering())); + auto image_rect = context.rounded_device_rect(absolute_rect().to_type()); + ScopedCornerRadiusClip corner_clip { context, context.painter(), image_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) }; + context.painter().draw_scaled_bitmap(image_rect.to_type(), *bitmap, bitmap->rect(), 1.0f, to_gfx_scaling_mode(computed_values().image_rendering())); } } } diff --git a/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp b/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp index 305ea28a83..03a285034a 100644 --- a/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp @@ -54,7 +54,7 @@ void InlinePaintable::paint(PaintContext& context, Painting::PaintPhase phase) c absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_end_width); } - auto border_radii_data = Painting::normalized_border_radii_data(layout_node(), absolute_fragment_rect, top_left_border_radius, top_right_border_radius, bottom_right_border_radius, bottom_left_border_radius); + auto border_radii_data = Painting::normalized_border_radii_data(layout_node(), absolute_fragment_rect.to_type(), top_left_border_radius, top_right_border_radius, bottom_right_border_radius, bottom_left_border_radius); Painting::paint_background(context, layout_node(), absolute_fragment_rect.to_type(), computed_values().background_color(), computed_values().image_rendering(), &computed_values().background_layers(), border_radii_data); if (auto computed_box_shadow = computed_values().box_shadow(); !computed_box_shadow.is_empty()) { @@ -92,7 +92,7 @@ void InlinePaintable::paint(PaintContext& context, Painting::PaintPhase phase) c auto containing_block_position_in_absolute_coordinates = containing_block()->paint_box()->absolute_position(); for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) { - Gfx::FloatRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() }; + CSSPixelRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() }; if (is_first_fragment) { float extra_start_width = box_model().padding.left; diff --git a/Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.cpp b/Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.cpp index e03e2cca64..5fd754859a 100644 --- a/Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.cpp @@ -36,8 +36,8 @@ void NestedBrowsingContextPaintable::paint(PaintContext& context, PaintPhase pha PaintableBox::paint(context, phase); if (phase == PaintPhase::Foreground) { - auto clip_rect = absolute_rect().to_rounded(); - ScopedCornerRadiusClip corner_clip { context.painter(), clip_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) }; + auto clip_rect = context.rounded_device_rect(absolute_rect().to_type()); + ScopedCornerRadiusClip corner_clip { context, context.painter(), clip_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) }; auto* hosted_document = layout_box().dom_node().content_document_without_origin_check(); if (!hosted_document) @@ -49,7 +49,7 @@ void NestedBrowsingContextPaintable::paint(PaintContext& context, PaintPhase pha context.painter().save(); auto old_viewport_rect = context.device_viewport_rect(); - context.painter().add_clip_rect(clip_rect); + context.painter().add_clip_rect(clip_rect.to_type()); context.painter().translate(absolute_x(), absolute_y()); context.set_device_viewport_rect({ {}, layout_box().dom_node().nested_browsing_context()->size() }); diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index 46cb3b51fc..f628cba738 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -227,7 +227,7 @@ void PaintableBox::paint_border(PaintContext& context) const .bottom = computed_values().border_bottom(), .left = computed_values().border_left(), }; - paint_all_borders(context, absolute_border_box_rect(), normalized_border_radii_data(), borders_data); + paint_all_borders(context, absolute_border_box_rect().to_type(), normalized_border_radii_data(), borders_data); } void PaintableBox::paint_backdrop_filter(PaintContext& context) const @@ -300,7 +300,8 @@ void PaintableBox::paint_box_shadow(PaintContext& context) const BorderRadiiData PaintableBox::normalized_border_radii_data(ShrinkRadiiForBorders shrink) const { - auto border_radius_data = Painting::normalized_border_radii_data(layout_box(), absolute_border_box_rect(), + auto border_radius_data = Painting::normalized_border_radii_data(layout_box(), + absolute_border_box_rect().to_type(), computed_values().border_top_left_radius(), computed_values().border_top_right_radius(), computed_values().border_bottom_right_radius(), @@ -356,7 +357,7 @@ void PaintableBox::before_children_paint(PaintContext& context, PaintPhase phase if (overflow_y == CSS::Overflow::Hidden || overflow_x == CSS::Overflow::Hidden) { auto border_radii_data = normalized_border_radii_data(ShrinkRadiiForBorders::Yes); if (border_radii_data.has_any_radius()) { - auto corner_clipper = BorderRadiusCornerClipper::create(absolute_padding_box_rect().to_rounded(), border_radii_data, CornerClip::Outside, BorderRadiusCornerClipper::UseCachedBitmap::No); + auto corner_clipper = BorderRadiusCornerClipper::create(context, absolute_padding_box_rect().to_type(), border_radii_data, CornerClip::Outside, BorderRadiusCornerClipper::UseCachedBitmap::No); if (corner_clipper.is_error()) { dbgln("Failed to create overflow border-radius corner clipper: {}", corner_clipper.error()); return; @@ -553,7 +554,7 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const auto border_radii = normalized_border_radii_data(ShrinkRadiiForBorders::Yes); if (border_radii.has_any_radius()) { - auto clipper = BorderRadiusCornerClipper::create(clip_box, border_radii); + auto clipper = BorderRadiusCornerClipper::create(context, clip_box.to_type(), border_radii); if (!clipper.is_error()) { corner_clipper = clipper.release_value(); corner_clipper->sample_under_corners(context.painter()); diff --git a/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp b/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp index d900eaf2bb..a47e4f071d 100644 --- a/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp @@ -25,12 +25,12 @@ void paint_box_shadow(PaintContext& context, Gfx::IntRect const& content_rect, B auto& painter = context.painter(); - auto top_left_corner = border_radii.top_left.as_corner(); - auto top_right_corner = border_radii.top_right.as_corner(); - auto bottom_right_corner = border_radii.bottom_right.as_corner(); - auto bottom_left_corner = border_radii.bottom_left.as_corner(); + auto top_left_corner = border_radii.top_left.as_corner(context); + auto top_right_corner = border_radii.top_right.as_corner(context); + auto bottom_right_corner = border_radii.bottom_right.as_corner(context); + auto bottom_left_corner = border_radii.bottom_left.as_corner(context); - ScopedCornerRadiusClip corner_clipper { painter, content_rect, border_radii, CornerClip::Inside }; + ScopedCornerRadiusClip corner_clipper { context, painter, content_rect.to_type(), border_radii, CornerClip::Inside }; // Note: Box-shadow layers are ordered front-to-back, so we paint them in reverse for (auto& box_shadow_data : box_shadow_layers.in_reverse()) {