diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 5417dd8e635..8cfb11e6fac 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -35,7 +35,7 @@ AK_TYPEDEF_DISTINCT_NUMERIC_GENERAL(i64, UniqueNodeID, Comparison, Increment, Ca namespace Web::Painting { class BackingStore; - +class DevicePixelConverter; class DisplayList; class DisplayListPlayerSkia; class DisplayListRecorder; diff --git a/Libraries/LibWeb/Painting/BackgroundPainting.cpp b/Libraries/LibWeb/Painting/BackgroundPainting.cpp index a50c5b1b2f2..4bc765e1e1c 100644 --- a/Libraries/LibWeb/Painting/BackgroundPainting.cpp +++ b/Libraries/LibWeb/Painting/BackgroundPainting.cpp @@ -116,10 +116,10 @@ void paint_background(PaintContext& context, PaintableBox const& paintable_box, display_list_recorder.fill_rect_with_rounded_corners( context.rounded_device_rect(color_box.rect).to_type(), resolved_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)); + color_box.radii.top_left.as_corner(context.device_pixel_converter()), + color_box.radii.top_right.as_corner(context.device_pixel_converter()), + color_box.radii.bottom_right.as_corner(context.device_pixel_converter()), + color_box.radii.bottom_left.as_corner(context.device_pixel_converter())); } struct { diff --git a/Libraries/LibWeb/Painting/BorderRadiiData.cpp b/Libraries/LibWeb/Painting/BorderRadiiData.cpp index 2215db0194c..e5467844aa8 100644 --- a/Libraries/LibWeb/Painting/BorderRadiiData.cpp +++ b/Libraries/LibWeb/Painting/BorderRadiiData.cpp @@ -10,11 +10,11 @@ namespace Web::Painting { -CornerRadius BorderRadiusData::as_corner(PaintContext const& context) const +CornerRadius BorderRadiusData::as_corner(DevicePixelConverter const& device_pixel_scale) const { return CornerRadius { - context.floored_device_pixels(horizontal_radius).value(), - context.floored_device_pixels(vertical_radius).value() + device_pixel_scale.floored_device_pixels(horizontal_radius).value(), + device_pixel_scale.floored_device_pixels(vertical_radius).value() }; } diff --git a/Libraries/LibWeb/Painting/BorderRadiiData.h b/Libraries/LibWeb/Painting/BorderRadiiData.h index fa69b77918d..a8cc8130f25 100644 --- a/Libraries/LibWeb/Painting/BorderRadiiData.h +++ b/Libraries/LibWeb/Painting/BorderRadiiData.h @@ -25,7 +25,7 @@ struct BorderRadiusData { CSSPixels horizontal_radius { 0 }; CSSPixels vertical_radius { 0 }; - CornerRadius as_corner(PaintContext const& context) const; + CornerRadius as_corner(DevicePixelConverter const& device_pixel_converter) const; inline operator bool() const { @@ -91,15 +91,15 @@ struct BorderRadiiData { shrink(-top, -right, -bottom, -left); } - inline CornerRadii as_corners(PaintContext const& context) const + inline CornerRadii as_corners(DevicePixelConverter const& device_pixel_converter) const { if (!has_any_radius()) return {}; return CornerRadii { - top_left.as_corner(context), - top_right.as_corner(context), - bottom_right.as_corner(context), - bottom_left.as_corner(context) + top_left.as_corner(device_pixel_converter), + top_right.as_corner(device_pixel_converter), + bottom_right.as_corner(device_pixel_converter), + bottom_left.as_corner(device_pixel_converter) }; } }; diff --git a/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp b/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp index 091c5260291..db49ae77ae8 100644 --- a/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp +++ b/Libraries/LibWeb/Painting/BorderRadiusCornerClipper.cpp @@ -17,10 +17,10 @@ ScopedCornerRadiusClip::ScopedCornerRadiusClip(PaintContext& context, DevicePixe if (!do_apply) return; CornerRadii const corner_radii { - .top_left = border_radii.top_left.as_corner(context), - .top_right = border_radii.top_right.as_corner(context), - .bottom_right = border_radii.bottom_right.as_corner(context), - .bottom_left = border_radii.bottom_left.as_corner(context) + .top_left = border_radii.top_left.as_corner(context.device_pixel_converter()), + .top_right = border_radii.top_right.as_corner(context.device_pixel_converter()), + .bottom_right = border_radii.bottom_right.as_corner(context.device_pixel_converter()), + .bottom_left = border_radii.bottom_left.as_corner(context.device_pixel_converter()) }; m_has_radius = corner_radii.has_any_radius(); if (!m_has_radius) diff --git a/Libraries/LibWeb/Painting/DevicePixelConverter.h b/Libraries/LibWeb/Painting/DevicePixelConverter.h new file mode 100644 index 00000000000..b8cc4103974 --- /dev/null +++ b/Libraries/LibWeb/Painting/DevicePixelConverter.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018-2022, Andreas Kling + * Copyright (c) 2022, Sam Atkins + * Copyright (c) 2025, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::Painting { + +class DevicePixelConverter { +public: + DevicePixels rounded_device_pixels(CSSPixels css_pixels) const + { + return round(css_pixels.to_double() * m_device_pixels_per_css_pixel); + } + + DevicePixels enclosing_device_pixels(CSSPixels css_pixels) const + { + return ceil(css_pixels.to_double() * m_device_pixels_per_css_pixel); + } + + DevicePixels floored_device_pixels(CSSPixels css_pixels) const + { + return floor(css_pixels.to_double() * m_device_pixels_per_css_pixel); + } + + DevicePixelPoint rounded_device_point(CSSPixelPoint point) const + { + return { + round(point.x().to_double() * m_device_pixels_per_css_pixel), + round(point.y().to_double() * m_device_pixels_per_css_pixel) + }; + } + + DevicePixelPoint floored_device_point(CSSPixelPoint point) const + { + return { + floor(point.x().to_double() * m_device_pixels_per_css_pixel), + floor(point.y().to_double() * m_device_pixels_per_css_pixel) + }; + } + + DevicePixelRect enclosing_device_rect(CSSPixelRect rect) const + { + return { + floor(rect.x().to_double() * m_device_pixels_per_css_pixel), + floor(rect.y().to_double() * m_device_pixels_per_css_pixel), + ceil(rect.width().to_double() * m_device_pixels_per_css_pixel), + ceil(rect.height().to_double() * m_device_pixels_per_css_pixel) + }; + } + + DevicePixelRect rounded_device_rect(CSSPixelRect rect) const + { + return { + round(rect.x().to_double() * m_device_pixels_per_css_pixel), + round(rect.y().to_double() * m_device_pixels_per_css_pixel), + round(rect.width().to_double() * m_device_pixels_per_css_pixel), + round(rect.height().to_double() * m_device_pixels_per_css_pixel) + }; + } + + DevicePixelSize enclosing_device_size(CSSPixelSize size) const + { + return { + ceil(size.width().to_double() * m_device_pixels_per_css_pixel), + ceil(size.height().to_double() * m_device_pixels_per_css_pixel) + }; + } + + DevicePixelSize rounded_device_size(CSSPixelSize size) const + { + return { + round(size.width().to_double() * m_device_pixels_per_css_pixel), + round(size.height().to_double() * m_device_pixels_per_css_pixel) + }; + } + + double device_pixels_per_css_pixel() const { return m_device_pixels_per_css_pixel; } + + DevicePixelConverter(double device_pixels_per_css_pixel) + : m_device_pixels_per_css_pixel(device_pixels_per_css_pixel) + { + } + +private: + double m_device_pixels_per_css_pixel { 0 }; +}; + +} diff --git a/Libraries/LibWeb/Painting/FieldSetPaintable.cpp b/Libraries/LibWeb/Painting/FieldSetPaintable.cpp index a2aff22e39a..9580f8456fa 100644 --- a/Libraries/LibWeb/Painting/FieldSetPaintable.cpp +++ b/Libraries/LibWeb/Painting/FieldSetPaintable.cpp @@ -62,7 +62,7 @@ void FieldSetPaintable::paint(PaintContext& context, PaintPhase phase) const .left = box_model().border.left == 0 ? CSS::BorderData() : computed_values().border_left(), }; - paint_all_borders(display_list_recorder, fieldset_border_rect, normalized_border_radii_data().as_corners(context), borders_data.to_device_pixels(context)); + paint_all_borders(display_list_recorder, fieldset_border_rect, normalized_border_radii_data().as_corners(context.device_pixel_converter()), borders_data.to_device_pixels(context)); auto top_border_data = box_model().border.top == 0 ? CSS::BorderData() : computed_values().border_top(); auto top_border = context.enclosing_device_pixels(top_border_data.width).value(); @@ -92,7 +92,7 @@ void FieldSetPaintable::paint(PaintContext& context, PaintPhase phase) const display_list_recorder.save(); display_list_recorder.add_clip_rect(left_segment.to_type()); - paint_all_borders(display_list_recorder, fieldset_border_rect, normalized_border_radii_data().as_corners(context), top_border_only.to_device_pixels(context)); + paint_all_borders(display_list_recorder, fieldset_border_rect, normalized_border_radii_data().as_corners(context.device_pixel_converter()), top_border_only.to_device_pixels(context)); display_list_recorder.restore(); display_list_recorder.save(); @@ -100,7 +100,7 @@ void FieldSetPaintable::paint(PaintContext& context, PaintPhase phase) const paint_all_borders( display_list_recorder, fieldset_border_rect, - normalized_border_radii_data().as_corners(context), + normalized_border_radii_data().as_corners(context.device_pixel_converter()), top_border_only.to_device_pixels(context)); display_list_recorder.restore(); } diff --git a/Libraries/LibWeb/Painting/PaintContext.cpp b/Libraries/LibWeb/Painting/PaintContext.cpp index b7cdcee1d3c..01055e9f6ba 100644 --- a/Libraries/LibWeb/Painting/PaintContext.cpp +++ b/Libraries/LibWeb/Painting/PaintContext.cpp @@ -14,7 +14,7 @@ static u64 s_next_paint_generation_id = 0; PaintContext::PaintContext(Painting::DisplayListRecorder& display_list_recorder, Palette const& palette, double device_pixels_per_css_pixel) : m_display_list_recorder(display_list_recorder) , m_palette(palette) - , m_device_pixels_per_css_pixel(device_pixels_per_css_pixel) + , m_device_pixel_converter(device_pixels_per_css_pixel) , m_paint_generation_id(s_next_paint_generation_id++) { } @@ -22,83 +22,61 @@ PaintContext::PaintContext(Painting::DisplayListRecorder& display_list_recorder, CSSPixelRect PaintContext::css_viewport_rect() const { return { - m_device_viewport_rect.x().value() / m_device_pixels_per_css_pixel, - m_device_viewport_rect.y().value() / m_device_pixels_per_css_pixel, - m_device_viewport_rect.width().value() / m_device_pixels_per_css_pixel, - m_device_viewport_rect.height().value() / m_device_pixels_per_css_pixel + m_device_viewport_rect.x().value() / m_device_pixel_converter.device_pixels_per_css_pixel(), + m_device_viewport_rect.y().value() / m_device_pixel_converter.device_pixels_per_css_pixel(), + m_device_viewport_rect.width().value() / m_device_pixel_converter.device_pixels_per_css_pixel(), + m_device_viewport_rect.height().value() / m_device_pixel_converter.device_pixels_per_css_pixel() }; } DevicePixels PaintContext::rounded_device_pixels(CSSPixels css_pixels) const { - return round(css_pixels.to_double() * m_device_pixels_per_css_pixel); + return m_device_pixel_converter.rounded_device_pixels(css_pixels); } DevicePixels PaintContext::enclosing_device_pixels(CSSPixels css_pixels) const { - return ceil(css_pixels.to_double() * m_device_pixels_per_css_pixel); + return m_device_pixel_converter.enclosing_device_pixels(css_pixels); } DevicePixels PaintContext::floored_device_pixels(CSSPixels css_pixels) const { - return floor(css_pixels.to_double() * m_device_pixels_per_css_pixel); + return m_device_pixel_converter.floored_device_pixels(css_pixels); } DevicePixelPoint PaintContext::rounded_device_point(CSSPixelPoint point) const { - return { - round(point.x().to_double() * m_device_pixels_per_css_pixel), - round(point.y().to_double() * m_device_pixels_per_css_pixel) - }; + return m_device_pixel_converter.rounded_device_point(point); } DevicePixelPoint PaintContext::floored_device_point(CSSPixelPoint point) const { - return { - floor(point.x().to_double() * m_device_pixels_per_css_pixel), - floor(point.y().to_double() * m_device_pixels_per_css_pixel) - }; + return m_device_pixel_converter.floored_device_point(point); } DevicePixelRect PaintContext::enclosing_device_rect(CSSPixelRect rect) const { - return { - floor(rect.x().to_double() * m_device_pixels_per_css_pixel), - floor(rect.y().to_double() * m_device_pixels_per_css_pixel), - ceil(rect.width().to_double() * m_device_pixels_per_css_pixel), - ceil(rect.height().to_double() * m_device_pixels_per_css_pixel) - }; + return m_device_pixel_converter.enclosing_device_rect(rect); } DevicePixelRect PaintContext::rounded_device_rect(CSSPixelRect rect) const { - return { - round(rect.x().to_double() * m_device_pixels_per_css_pixel), - round(rect.y().to_double() * m_device_pixels_per_css_pixel), - round(rect.width().to_double() * m_device_pixels_per_css_pixel), - round(rect.height().to_double() * m_device_pixels_per_css_pixel) - }; + return m_device_pixel_converter.rounded_device_rect(rect); } DevicePixelSize PaintContext::enclosing_device_size(CSSPixelSize size) const { - return { - ceil(size.width().to_double() * m_device_pixels_per_css_pixel), - ceil(size.height().to_double() * m_device_pixels_per_css_pixel) - }; + return m_device_pixel_converter.enclosing_device_size(size); } DevicePixelSize PaintContext::rounded_device_size(CSSPixelSize size) const { - return { - round(size.width().to_double() * m_device_pixels_per_css_pixel), - round(size.height().to_double() * m_device_pixels_per_css_pixel) - }; + return m_device_pixel_converter.rounded_device_size(size); } CSSPixels PaintContext::scale_to_css_pixels(DevicePixels device_pixels) const { - return CSSPixels::nearest_value_for(device_pixels.value() / m_device_pixels_per_css_pixel); + return CSSPixels::nearest_value_for(device_pixels.value() / m_device_pixel_converter.device_pixels_per_css_pixel()); } CSSPixelPoint PaintContext::scale_to_css_point(DevicePixelPoint point) const diff --git a/Libraries/LibWeb/Painting/PaintContext.h b/Libraries/LibWeb/Painting/PaintContext.h index 1419e765807..563625f8713 100644 --- a/Libraries/LibWeb/Painting/PaintContext.h +++ b/Libraries/LibWeb/Painting/PaintContext.h @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace Web { @@ -68,21 +69,22 @@ public: PaintContext clone(Painting::DisplayListRecorder& painter) const { - auto clone = PaintContext(painter, m_palette, m_device_pixels_per_css_pixel); + auto clone = PaintContext(painter, m_palette, m_device_pixel_converter.device_pixels_per_css_pixel()); clone.m_device_viewport_rect = m_device_viewport_rect; clone.m_should_show_line_box_borders = m_should_show_line_box_borders; clone.m_should_paint_overlay = m_should_paint_overlay; return clone; } - double device_pixels_per_css_pixel() const { return m_device_pixels_per_css_pixel; } + Painting::DevicePixelConverter const& device_pixel_converter() const { return m_device_pixel_converter; } + double device_pixels_per_css_pixel() const { return m_device_pixel_converter.device_pixels_per_css_pixel(); } u64 paint_generation_id() const { return m_paint_generation_id; } private: Painting::DisplayListRecorder& m_display_list_recorder; Palette m_palette; - double m_device_pixels_per_css_pixel { 0 }; + Painting::DevicePixelConverter m_device_pixel_converter; DevicePixelRect m_device_viewport_rect; bool m_should_show_line_box_borders { false }; bool m_should_paint_overlay { true }; diff --git a/Libraries/LibWeb/Painting/PaintableBox.cpp b/Libraries/LibWeb/Painting/PaintableBox.cpp index 8abfc4cddef..1f18a33f3ed 100644 --- a/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -479,7 +479,7 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const border_radius_data.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x); borders_rect.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x); - paint_all_borders(context.display_list_recorder(), context.rounded_device_rect(borders_rect), border_radius_data.as_corners(context), outline_data->to_device_pixels(context)); + paint_all_borders(context.display_list_recorder(), context.rounded_device_rect(borders_rect), border_radius_data.as_corners(context.device_pixel_converter()), outline_data->to_device_pixels(context)); } } @@ -571,7 +571,7 @@ void PaintableBox::paint_border(PaintContext& context) const .bottom = box_model().border.bottom == 0 ? CSS::BorderData() : computed_values().border_bottom(), .left = box_model().border.left == 0 ? CSS::BorderData() : computed_values().border_left(), }; - paint_all_borders(context.display_list_recorder(), context.rounded_device_rect(absolute_border_box_rect()), normalized_border_radii_data().as_corners(context), borders_data.to_device_pixels(context)); + paint_all_borders(context.display_list_recorder(), context.rounded_device_rect(absolute_border_box_rect()), normalized_border_radii_data().as_corners(context.device_pixel_converter()), borders_data.to_device_pixels(context)); } void PaintableBox::paint_backdrop_filter(PaintContext& context) const @@ -661,7 +661,7 @@ void PaintableBox::apply_clip(PaintContext& context, RefPtr con clip_scroll_frame_id = clip_rect.enclosing_scroll_frame->id(); display_list_recorder.push_scroll_frame_id(clip_scroll_frame_id); auto rect = context.rounded_device_rect(clip_rect.rect).to_type(); - auto corner_radii = clip_rect.corner_radii.as_corners(context); + auto corner_radii = clip_rect.corner_radii.as_corners(context.device_pixel_converter()); if (corner_radii.has_any_radius()) { display_list_recorder.add_rounded_rect_clip(corner_radii, rect, CornerClip::Outside); } else { diff --git a/Libraries/LibWeb/Painting/ShadowPainting.cpp b/Libraries/LibWeb/Painting/ShadowPainting.cpp index 736e83d3bbd..18e2604d3b6 100644 --- a/Libraries/LibWeb/Painting/ShadowPainting.cpp +++ b/Libraries/LibWeb/Painting/ShadowPainting.cpp @@ -41,10 +41,10 @@ void paint_box_shadow(PaintContext& context, .color = box_shadow_data.color, .placement = box_shadow_data.placement, .corner_radii = CornerRadii { - .top_left = border_radii.top_left.as_corner(context), - .top_right = border_radii.top_right.as_corner(context), - .bottom_right = border_radii.bottom_right.as_corner(context), - .bottom_left = border_radii.bottom_left.as_corner(context) }, + .top_left = border_radii.top_left.as_corner(context.device_pixel_converter()), + .top_right = border_radii.top_right.as_corner(context.device_pixel_converter()), + .bottom_right = border_radii.bottom_right.as_corner(context.device_pixel_converter()), + .bottom_left = border_radii.bottom_left.as_corner(context.device_pixel_converter()) }, .offset_x = offset_x.value(), .offset_y = offset_y.value(), .blur_radius = blur_radius.value(), diff --git a/Libraries/LibWeb/Painting/TableBordersPainting.cpp b/Libraries/LibWeb/Painting/TableBordersPainting.cpp index 09dfe53a67f..6e24225473a 100644 --- a/Libraries/LibWeb/Painting/TableBordersPainting.cpp +++ b/Libraries/LibWeb/Painting/TableBordersPainting.cpp @@ -354,7 +354,7 @@ static void paint_separate_cell_borders(PaintableBox const& cell_box, HashMaprow_index, cell_box.table_cell_coordinates()->column_index }).value(); - paint_all_borders(context.display_list_recorder(), cell_rect, cell_box.normalized_border_radii_data().as_corners(context), borders_data.to_device_pixels(context)); + paint_all_borders(context.display_list_recorder(), cell_rect, cell_box.normalized_border_radii_data().as_corners(context.device_pixel_converter()), borders_data.to_device_pixels(context)); } void paint_table_borders(PaintContext& context, PaintableBox const& table_paintable) @@ -428,10 +428,10 @@ void paint_table_borders(PaintContext& context, PaintableBox const& table_painta for (auto const& cell_box : cell_boxes) { auto const& border_radii_data = cell_box.normalized_border_radii_data(); - 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); + auto top_left = border_radii_data.top_left.as_corner(context.device_pixel_converter()); + auto top_right = border_radii_data.top_right.as_corner(context.device_pixel_converter()); + auto bottom_right = border_radii_data.bottom_right.as_corner(context.device_pixel_converter()); + auto bottom_left = border_radii_data.bottom_left.as_corner(context.device_pixel_converter()); if (!top_left && !top_right && !bottom_left && !bottom_right) { continue; } else { @@ -441,7 +441,7 @@ void paint_table_borders(PaintContext& context, PaintableBox const& table_painta .bottom = cell_box.box_model().border.bottom == 0 ? CSS::BorderData() : cell_box.computed_values().border_bottom(), .left = cell_box.box_model().border.left == 0 ? CSS::BorderData() : cell_box.computed_values().border_left(), }; - paint_all_borders(context.display_list_recorder(), context.rounded_device_rect(cell_box.absolute_border_box_rect()), cell_box.normalized_border_radii_data().as_corners(context), borders_data.to_device_pixels(context)); + paint_all_borders(context.display_list_recorder(), context.rounded_device_rect(cell_box.absolute_border_box_rect()), cell_box.normalized_border_radii_data().as_corners(context.device_pixel_converter()), borders_data.to_device_pixels(context)); } } }