mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 19:47:34 +00:00
LibWeb: Make CSSPixels and Length use 64-bit (double) floating point
This fixes a plethora of rounding problems on many websites. In the future, we may want to replace this with fixed-point arithmetic (bug #18566) for performance (and consistency with other engines), but in the meantime this makes the web look a bit better. :^) There's a lot more things that could be converted to doubles, which would reduce the amount of casting necessary in this patch. We can do that incrementally, however.
This commit is contained in:
parent
30262d7023
commit
655d9d1462
80 changed files with 298 additions and 299 deletions
|
@ -148,16 +148,16 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
|
|||
CSSPixelRect image_rect;
|
||||
switch (layer.size_type) {
|
||||
case CSS::BackgroundSize::Contain: {
|
||||
float max_width_ratio = (background_positioning_area.width() / natural_image_width).value();
|
||||
float max_height_ratio = (background_positioning_area.height() / natural_image_height).value();
|
||||
float ratio = min(max_width_ratio, max_height_ratio);
|
||||
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 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: {
|
||||
float max_width_ratio = (background_positioning_area.width() / natural_image_width).value();
|
||||
float max_height_ratio = (background_positioning_area.height() / natural_image_height).value();
|
||||
float ratio = max(max_width_ratio, max_height_ratio);
|
||||
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 ratio = max(max_width_ratio, max_height_ratio);
|
||||
image_rect.set_size(natural_image_width * ratio, natural_image_height * ratio);
|
||||
break;
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
|
|||
repeat_x = false;
|
||||
} else {
|
||||
auto space = fmod(background_positioning_area.width(), image_rect.width());
|
||||
x_step = image_rect.width() + (space / (float)(whole_images - 1));
|
||||
x_step = image_rect.width() + (space / static_cast<double>(whole_images - 1));
|
||||
repeat_x = true;
|
||||
}
|
||||
break;
|
||||
|
@ -284,7 +284,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
|
|||
repeat_y = false;
|
||||
} else {
|
||||
auto space = fmod(background_positioning_area.height(), image_rect.height());
|
||||
y_step = image_rect.height() + ((float)space / (float)(whole_images - 1));
|
||||
y_step = image_rect.height() + (static_cast<double>(space) / static_cast<double>(whole_images - 1));
|
||||
repeat_y = true;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -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.0f / rect.width().value();
|
||||
auto height_reciprocal = 1.0f / rect.height().value();
|
||||
auto width_reciprocal = 1.0 / rect.width().value();
|
||||
auto height_reciprocal = 1.0 / 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.value();
|
||||
f = 1.0 / f.value();
|
||||
|
||||
top_left_radius_px.horizontal_radius *= f;
|
||||
top_left_radius_px.vertical_radius *= f;
|
||||
|
@ -149,8 +149,8 @@ void paint_border(PaintContext& context, BorderEdge edge, DevicePixelRect const&
|
|||
|
||||
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 p1_step = radius ? 0 : border.width / static_cast<float>(device_pixel_width.value());
|
||||
auto p2_step = opposite_radius ? 0 : opposite_border.width / static_cast<float>(device_pixel_width.value());
|
||||
auto p1_step = radius ? 0 : border.width / device_pixel_width.value();
|
||||
auto p2_step = opposite_radius ? 0 : opposite_border.width / 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);
|
||||
|
|
|
@ -111,11 +111,11 @@ static ColorStopData resolve_color_stop_positions(auto const& color_stop_list, a
|
|||
LinearGradientData resolve_linear_gradient_data(Layout::Node const& node, CSSPixelSize gradient_size, CSS::LinearGradientStyleValue const& linear_gradient)
|
||||
{
|
||||
auto gradient_angle = linear_gradient.angle_degrees(gradient_size);
|
||||
auto gradient_length_px = Gfx::calculate_gradient_length(gradient_size, gradient_angle);
|
||||
auto gradient_length_px = Gfx::calculate_gradient_length(gradient_size.to_type<double>().to_type<float>(), gradient_angle);
|
||||
|
||||
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() / gradient_length_px;
|
||||
return length_percentage.to_px(node, gradient_length_px).value() / static_cast<double>(gradient_length_px);
|
||||
},
|
||||
linear_gradient.is_repeating());
|
||||
|
||||
|
|
|
@ -32,10 +32,10 @@ void MarkerPaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
return;
|
||||
|
||||
// FIXME: All this does is round to the nearest whole CSS pixel, but it's goofy.
|
||||
CSSPixelRect enclosing = absolute_rect().to_type<float>().to_rounded<float>().to_type<CSSPixels>();
|
||||
CSSPixelRect enclosing = absolute_rect().to_type<double>().to_type<float>().to_rounded<float>().to_type<CSSPixels>();
|
||||
auto device_enclosing = context.enclosing_device_rect(enclosing);
|
||||
|
||||
CSSPixels marker_width = enclosing.height() / 2.0f;
|
||||
CSSPixels marker_width = enclosing.height() / 2.0;
|
||||
|
||||
if (auto const* list_style_image = layout_box().list_style_image()) {
|
||||
CSSPixelRect image_rect {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace Web {
|
||||
|
||||
PaintContext::PaintContext(Gfx::Painter& painter, Palette const& palette, float device_pixels_per_css_pixel)
|
||||
PaintContext::PaintContext(Gfx::Painter& painter, Palette const& palette, double device_pixels_per_css_pixel)
|
||||
: m_painter(painter)
|
||||
, m_palette(palette)
|
||||
, m_device_pixels_per_css_pixel(device_pixels_per_css_pixel)
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Web {
|
|||
|
||||
class PaintContext {
|
||||
public:
|
||||
PaintContext(Gfx::Painter& painter, Palette const& palette, float device_pixels_per_css_pixel);
|
||||
PaintContext(Gfx::Painter& painter, Palette const& palette, double device_pixels_per_css_pixel);
|
||||
|
||||
Gfx::Painter& painter() const { return m_painter; }
|
||||
Palette const& palette() const { return m_palette; }
|
||||
|
@ -64,13 +64,13 @@ public:
|
|||
return clone;
|
||||
}
|
||||
|
||||
float device_pixels_per_css_pixel() const { return m_device_pixels_per_css_pixel; }
|
||||
double device_pixels_per_css_pixel() const { return m_device_pixels_per_css_pixel; }
|
||||
|
||||
private:
|
||||
Gfx::Painter& m_painter;
|
||||
Palette m_palette;
|
||||
Optional<SVGContext> m_svg_context;
|
||||
float m_device_pixels_per_css_pixel;
|
||||
double m_device_pixels_per_css_pixel { 0 };
|
||||
DevicePixelRect m_device_viewport_rect;
|
||||
bool m_should_show_line_box_borders { false };
|
||||
bool m_focus { false };
|
||||
|
|
|
@ -155,7 +155,7 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
|
|||
if (should_clip_rect) {
|
||||
context.painter().save();
|
||||
auto border_box = absolute_border_box_rect();
|
||||
context.painter().add_clip_rect(context.rounded_device_rect(clip_rect.to_rect().resolved(Paintable::layout_node(), border_box.to_type<float>()).to_type<CSSPixels>()).to_type<int>());
|
||||
context.painter().add_clip_rect(context.rounded_device_rect(clip_rect.to_rect().resolved(Paintable::layout_node(), border_box.to_type<double>()).to_type<CSSPixels>()).to_type<int>());
|
||||
}
|
||||
paint_backdrop_filter(context);
|
||||
paint_background(context);
|
||||
|
@ -434,7 +434,7 @@ static void paint_text_decoration(PaintContext& context, Gfx::Painter& painter,
|
|||
CSSPixels css_line_thickness = [&] {
|
||||
CSS::Length computed_thickness = text_node.computed_values().text_decoration_thickness().resolved(text_node, CSS::Length(1, CSS::Length::Type::Em));
|
||||
if (computed_thickness.is_auto())
|
||||
return max(glyph_height * 0.1f, 1.f);
|
||||
return max(glyph_height * 0.1, 1.);
|
||||
|
||||
return computed_thickness.to_px(text_node);
|
||||
}();
|
||||
|
|
|
@ -36,7 +36,7 @@ Optional<HitTestResult> SVGGeometryPaintable::hit_test(CSSPixelPoint position, H
|
|||
if (auto transform = layout_box().layout_transform(); transform.has_value()) {
|
||||
auto transformed_bounding_box = transform->map_to_quad(
|
||||
const_cast<SVG::SVGGeometryElement&>(geometry_element).get_path().bounding_box());
|
||||
if (!transformed_bounding_box.contains(position.to_type<float>()))
|
||||
if (!transformed_bounding_box.contains(position.to_type<double>().to_type<float>()))
|
||||
return {};
|
||||
}
|
||||
return result;
|
||||
|
@ -92,7 +92,7 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
auto svg_viewport = [&] {
|
||||
if (maybe_view_box.has_value())
|
||||
return Gfx::FloatRect { maybe_view_box->min_x, maybe_view_box->min_y, maybe_view_box->width, maybe_view_box->height };
|
||||
return Gfx::FloatRect { { 0, 0 }, svg_context.svg_element_size().to_type<float>() };
|
||||
return Gfx::FloatRect { { 0, 0 }, svg_context.svg_element_size().to_type<double>().to_type<float>() };
|
||||
}();
|
||||
|
||||
SVG::SVGPaintContext paint_context {
|
||||
|
|
|
@ -232,7 +232,7 @@ Gfx::FloatMatrix4x4 StackingContext::get_transformation_matrix(CSS::Transformati
|
|||
auto count = transformation.values.size();
|
||||
auto value = [this, transformation](size_t index, Optional<CSS::Length const&> reference_length = {}) -> float {
|
||||
return transformation.values[index].visit(
|
||||
[this, reference_length](CSS::LengthPercentage const& value) {
|
||||
[this, reference_length](CSS::LengthPercentage const& value) -> float {
|
||||
if (reference_length.has_value()) {
|
||||
return value.resolved(m_box, reference_length.value()).to_px(m_box).value();
|
||||
}
|
||||
|
@ -430,7 +430,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 { x, y };
|
||||
return { static_cast<float>(x.value()), static_cast<float>(y.value()) };
|
||||
}
|
||||
|
||||
template<typename U, typename Callback>
|
||||
|
|
|
@ -378,7 +378,7 @@ VideoPaintable::DispatchEventOfSameName VideoPaintable::handle_mouseup(Badge<Eve
|
|||
|
||||
if (cached_layout_boxes.timeline_rect.has_value() && cached_layout_boxes.timeline_rect->contains(position)) {
|
||||
auto x_offset = position.x() - cached_layout_boxes.timeline_rect->x();
|
||||
auto x_percentage = static_cast<float>(x_offset) / static_cast<float>(cached_layout_boxes.timeline_rect->width());
|
||||
auto x_percentage = static_cast<double>(x_offset) / static_cast<double>(cached_layout_boxes.timeline_rect->width());
|
||||
|
||||
auto position = static_cast<double>(x_percentage) * video_element.duration();
|
||||
video_element.set_current_time(position);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue