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

LibWeb+WebContent: Forbid access to underlying type of CSSPixels

Although DistinctNumeric, which is supposed to abstract the underlying
type, was used to represent CSSPixels, we have a whole bunch of places
in the layout code that assume CSSPixels::value() returns a
floating-point type. This assumption makes it difficult to replace the
underlying type in CSSPixels with a non-floating type.

To make it easier to transition CSSPixels to fixed-point math, one step
we can take is to prevent access to the underlying type using value()
and instead use explicit conversions with the to_float(), to_double(),
and to_int() methods.
This commit is contained in:
Aliaksandr Kalenik 2023-06-12 21:37:35 +03:00 committed by Andreas Kling
parent 5a54c686a7
commit 147c3b3d97
43 changed files with 340 additions and 220 deletions

View file

@ -29,7 +29,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
inline void shrink(CSSPixels top, CSSPixels right, CSSPixels bottom, CSSPixels left)
{
rect.shrink(top, right, bottom, left);
radii.shrink(top.value(), right.value(), bottom.value(), left.value());
radii.shrink(top, right, bottom, left);
}
};
@ -137,8 +137,8 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
}
// FIXME: Implement proper default sizing algorithm: https://drafts.csswg.org/css-images/#default-sizing
CSSPixels natural_image_width = image.natural_width().value_or(background_positioning_area.width().value());
CSSPixels natural_image_height = image.natural_height().value_or(background_positioning_area.height().value());
CSSPixels natural_image_width = image.natural_width().value_or(background_positioning_area.width());
CSSPixels natural_image_height = image.natural_height().value_or(background_positioning_area.height());
// If any of these are zero, the NaNs will pop up in the painting code.
if (background_positioning_area.is_empty() || natural_image_height <= 0 || natural_image_width <= 0)
@ -148,15 +148,15 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
CSSPixelRect image_rect;
switch (layer.size_type) {
case CSS::BackgroundSize::Contain: {
double max_width_ratio = (background_positioning_area.width() / natural_image_width).value();
double max_height_ratio = (background_positioning_area.height() / natural_image_height).value();
double max_width_ratio = (background_positioning_area.width() / natural_image_width).to_double();
double max_height_ratio = (background_positioning_area.height() / natural_image_height).to_double();
double ratio = min(max_width_ratio, max_height_ratio);
image_rect.set_size(natural_image_width * ratio, natural_image_height * ratio);
break;
}
case CSS::BackgroundSize::Cover: {
double max_width_ratio = (background_positioning_area.width() / natural_image_width).value();
double max_height_ratio = (background_positioning_area.height() / natural_image_height).value();
double max_width_ratio = (background_positioning_area.width() / natural_image_width).to_double();
double max_height_ratio = (background_positioning_area.height() / natural_image_height).to_double();
double ratio = max(max_width_ratio, max_height_ratio);
image_rect.set_size(natural_image_width * ratio, natural_image_height * ratio);
break;
@ -247,12 +247,12 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
repeat_x = true;
break;
case CSS::Repeat::Space: {
int whole_images = (background_positioning_area.width() / image_rect.width()).value();
int whole_images = (background_positioning_area.width() / image_rect.width()).to_int();
if (whole_images <= 1) {
x_step = image_rect.width();
repeat_x = false;
} else {
auto space = fmod(background_positioning_area.width(), image_rect.width());
auto space = fmod(background_positioning_area.width().to_float(), image_rect.width().to_float());
x_step = image_rect.width() + (space / static_cast<double>(whole_images - 1));
repeat_x = true;
}
@ -278,12 +278,12 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
repeat_y = true;
break;
case CSS::Repeat::Space: {
int whole_images = (background_positioning_area.height() / image_rect.height()).value();
int whole_images = (background_positioning_area.height() / image_rect.height()).to_int();
if (whole_images <= 1) {
y_step = image_rect.height();
repeat_y = false;
} else {
auto space = fmod(background_positioning_area.height(), image_rect.height());
auto space = fmod(background_positioning_area.height().to_float(), image_rect.height().to_float());
y_step = image_rect.height() + (static_cast<double>(space) / static_cast<double>(whole_images - 1));
repeat_y = true;
}

View file

@ -33,14 +33,14 @@ BorderRadiiData normalized_border_radii_data(Layout::Node const& node, CSSPixelR
// Scale overlapping curves according to https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
CSSPixels f = 1.0f;
auto width_reciprocal = 1.0 / rect.width().value();
auto height_reciprocal = 1.0 / rect.height().value();
auto width_reciprocal = 1.0 / rect.width().to_double();
auto height_reciprocal = 1.0 / rect.height().to_double();
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.0 / f.value();
f = 1.0 / f.to_double();
top_left_radius_px.horizontal_radius *= f;
top_left_radius_px.vertical_radius *= f;

View file

@ -115,7 +115,7 @@ LinearGradientData resolve_linear_gradient_data(Layout::Node const& node, CSSPix
auto resolved_color_stops = resolve_color_stop_positions(
linear_gradient.color_stop_list(), [&](auto const& length_percentage) {
return length_percentage.to_px(node, gradient_length_px).value() / static_cast<double>(gradient_length_px);
return length_percentage.to_px(node, gradient_length_px).to_float() / static_cast<float>(gradient_length_px);
},
linear_gradient.is_repeating());
@ -138,7 +138,7 @@ RadialGradientData resolve_radial_gradient_data(Layout::Node const& node, CSSPix
// Start center, goes right to ending point, where the gradient line intersects the ending shape
auto resolved_color_stops = resolve_color_stop_positions(
radial_gradient.color_stop_list(), [&](auto const& length_percentage) {
return (length_percentage.to_px(node, gradient_size.width()) / gradient_size.width()).value();
return (length_percentage.to_px(node, gradient_size.width()) / gradient_size.width()).to_float();
},
radial_gradient.is_repeating());
return { resolved_color_stops };

View file

@ -44,8 +44,8 @@ void MarkerPaintable::paint(PaintContext& context, PaintPhase phase) const
if (auto const* list_style_image = layout_box().list_style_image()) {
CSSPixelRect image_rect {
0, 0,
list_style_image->natural_width().value_or(marker_width.value()),
list_style_image->natural_height().value_or(marker_width.value())
list_style_image->natural_width().value_or(marker_width),
list_style_image->natural_height().value_or(marker_width)
};
image_rect.center_within(enclosing);

View file

@ -47,68 +47,68 @@ CSSPixelRect PaintContext::css_viewport_rect() const
DevicePixels PaintContext::rounded_device_pixels(CSSPixels css_pixels) const
{
return roundf(css_pixels.value() * m_device_pixels_per_css_pixel);
return roundf(css_pixels.to_double() * m_device_pixels_per_css_pixel);
}
DevicePixels PaintContext::enclosing_device_pixels(CSSPixels css_pixels) const
{
return ceilf(css_pixels.value() * m_device_pixels_per_css_pixel);
return ceilf(css_pixels.to_double() * m_device_pixels_per_css_pixel);
}
DevicePixels PaintContext::floored_device_pixels(CSSPixels css_pixels) const
{
return floorf(css_pixels.value() * m_device_pixels_per_css_pixel);
return floorf(css_pixels.to_double() * m_device_pixels_per_css_pixel);
}
DevicePixelPoint PaintContext::rounded_device_point(CSSPixelPoint point) const
{
return {
roundf(point.x().value() * m_device_pixels_per_css_pixel),
roundf(point.y().value() * m_device_pixels_per_css_pixel)
roundf(point.x().to_double() * m_device_pixels_per_css_pixel),
roundf(point.y().to_double() * m_device_pixels_per_css_pixel)
};
}
DevicePixelPoint PaintContext::floored_device_point(CSSPixelPoint point) const
{
return {
floorf(point.x().value() * m_device_pixels_per_css_pixel),
floorf(point.y().value() * m_device_pixels_per_css_pixel)
floorf(point.x().to_double() * m_device_pixels_per_css_pixel),
floorf(point.y().to_double() * m_device_pixels_per_css_pixel)
};
}
DevicePixelRect PaintContext::enclosing_device_rect(CSSPixelRect rect) const
{
return {
floorf(rect.x().value() * m_device_pixels_per_css_pixel),
floorf(rect.y().value() * m_device_pixels_per_css_pixel),
ceilf(rect.width().value() * m_device_pixels_per_css_pixel),
ceilf(rect.height().value() * m_device_pixels_per_css_pixel)
floorf(rect.x().to_double() * m_device_pixels_per_css_pixel),
floorf(rect.y().to_double() * m_device_pixels_per_css_pixel),
ceilf(rect.width().to_double() * m_device_pixels_per_css_pixel),
ceilf(rect.height().to_double() * m_device_pixels_per_css_pixel)
};
}
DevicePixelRect PaintContext::rounded_device_rect(CSSPixelRect rect) const
{
return {
roundf(rect.x().value() * m_device_pixels_per_css_pixel),
roundf(rect.y().value() * m_device_pixels_per_css_pixel),
roundf(rect.width().value() * m_device_pixels_per_css_pixel),
roundf(rect.height().value() * m_device_pixels_per_css_pixel)
roundf(rect.x().to_double() * m_device_pixels_per_css_pixel),
roundf(rect.y().to_double() * m_device_pixels_per_css_pixel),
roundf(rect.width().to_double() * m_device_pixels_per_css_pixel),
roundf(rect.height().to_double() * m_device_pixels_per_css_pixel)
};
}
DevicePixelSize PaintContext::enclosing_device_size(CSSPixelSize size) const
{
return {
ceilf(size.width().value() * m_device_pixels_per_css_pixel),
ceilf(size.height().value() * m_device_pixels_per_css_pixel)
ceilf(size.width().to_double() * m_device_pixels_per_css_pixel),
ceilf(size.height().to_double() * m_device_pixels_per_css_pixel)
};
}
DevicePixelSize PaintContext::rounded_device_size(CSSPixelSize size) const
{
return {
roundf(size.width().value() * m_device_pixels_per_css_pixel),
roundf(size.height().value() * m_device_pixels_per_css_pixel)
roundf(size.width().to_double() * m_device_pixels_per_css_pixel),
roundf(size.height().to_double() * m_device_pixels_per_css_pixel)
};
}

View file

@ -235,10 +235,10 @@ Gfx::FloatMatrix4x4 StackingContext::get_transformation_matrix(CSS::Transformati
return transformation.values[index].visit(
[this, reference_length](CSS::LengthPercentage const& value) -> double {
if (reference_length.has_value()) {
return value.resolved(m_box, reference_length.value()).to_px(m_box).value();
return value.resolved(m_box, reference_length.value()).to_px(m_box).to_float();
}
return value.length().to_px(m_box).value();
return value.length().to_px(m_box).to_float();
},
[this](CSS::AngleOrCalculated const& value) {
return value.resolved(m_box).to_degrees() * M_DEG2RAD;
@ -431,7 +431,7 @@ Gfx::FloatPoint StackingContext::compute_transform_origin() const
auto reference_box = paintable_box().absolute_border_box_rect();
auto x = reference_box.left() + style_value.x.to_px(m_box, reference_box.width());
auto y = reference_box.top() + style_value.y.to_px(m_box, reference_box.height());
return { static_cast<float>(x.value()), static_cast<float>(y.value()) };
return { x.to_float(), y.to_float() };
}
template<typename U, typename Callback>
@ -472,14 +472,14 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
auto transform_origin = this->transform_origin().to_type<CSSPixels>();
// NOTE: This CSSPixels -> Float -> CSSPixels conversion is because we can't AffineTransform::map() a CSSPixelPoint.
Gfx::FloatPoint offset_position {
position.x().value() - transform_origin.x().value(),
position.y().value() - transform_origin.y().value()
(position.x() - transform_origin.x()).to_float(),
(position.y() - transform_origin.y()).to_float()
};
auto transformed_position = affine_transform_matrix().inverse().value_or({}).map(offset_position).to_type<CSSPixels>() + transform_origin;
// FIXME: Support more overflow variations.
if (paintable_box().computed_values().overflow_x() == CSS::Overflow::Hidden && paintable_box().computed_values().overflow_y() == CSS::Overflow::Hidden) {
if (!paintable_box().absolute_border_box_rect().contains(transformed_position.x().value(), transformed_position.y().value()))
if (!paintable_box().absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
return {};
}
@ -502,7 +502,7 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
for_each_in_subtree_of_type_within_same_stacking_context_in_reverse<PaintableBox>(paintable_box(), [&](PaintableBox const& paintable_box) {
// FIXME: Support more overflow variations.
if (paintable_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paintable_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
if (!paintable_box.absolute_border_box_rect().contains(transformed_position.x().value(), transformed_position.y().value()))
if (!paintable_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
return TraversalDecision::SkipChildrenAndContinue;
}
@ -542,7 +542,7 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
for_each_in_subtree_of_type_within_same_stacking_context_in_reverse<PaintableBox>(paintable_box(), [&](PaintableBox const& paintable_box) {
// FIXME: Support more overflow variations.
if (paintable_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paintable_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
if (!paintable_box.absolute_border_box_rect().contains(transformed_position.x().value(), transformed_position.y().value()))
if (!paintable_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
return TraversalDecision::SkipChildrenAndContinue;
}
@ -563,7 +563,7 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
for_each_in_subtree_of_type_within_same_stacking_context_in_reverse<PaintableBox>(paintable_box(), [&](PaintableBox const& paintable_box) {
// FIXME: Support more overflow variations.
if (paintable_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paintable_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
if (!paintable_box.absolute_border_box_rect().contains(transformed_position.x().value(), transformed_position.y().value()))
if (!paintable_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
return TraversalDecision::SkipChildrenAndContinue;
}
@ -592,7 +592,7 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
}
// 1. the background and borders of the element forming the stacking context.
if (paintable_box().absolute_border_box_rect().contains(transformed_position.x().value(), transformed_position.y().value())) {
if (paintable_box().absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y())) {
return HitTestResult {
.paintable = const_cast<PaintableBox&>(paintable_box()),
};