mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 14:37:45 +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
|
@ -135,7 +135,7 @@ struct BorderData {
|
|||
public:
|
||||
Color color { Color::Transparent };
|
||||
CSS::LineStyle line_style { CSS::LineStyle::None };
|
||||
float width { 0 };
|
||||
double width { 0 };
|
||||
};
|
||||
|
||||
using TransformValue = Variant<CSS::AngleOrCalculated, CSS::LengthPercentage, float>;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
namespace Web::CSS {
|
||||
|
||||
// https://www.w3.org/TR/CSS2/visufx.html#value-def-shape
|
||||
Gfx::FloatRect EdgeRect::resolved(Layout::Node const& layout_node, Gfx::FloatRect border_box) const
|
||||
Gfx::FloatRect EdgeRect::resolved(Layout::Node const& layout_node, Gfx::Rect<double> border_box) const
|
||||
{
|
||||
// In CSS 2.1, the only valid <shape> value is: rect(<top>, <right>, <bottom>, <left>) where
|
||||
// <top> and <bottom> specify offsets from the top border edge of the box, and <right>, and
|
||||
|
|
|
@ -19,7 +19,7 @@ struct EdgeRect {
|
|||
Length right_edge;
|
||||
Length bottom_edge;
|
||||
Length left_edge;
|
||||
Gfx::FloatRect resolved(Layout::Node const&, Gfx::FloatRect) const;
|
||||
Gfx::FloatRect resolved(Layout::Node const&, Gfx::Rect<double>) const;
|
||||
bool operator==(EdgeRect const&) const = default;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ GridSize::GridSize(LengthPercentage length_percentage)
|
|||
: m_type(Type::LengthPercentage)
|
||||
, m_length_percentage(length_percentage) {};
|
||||
|
||||
GridSize::GridSize(float flex_factor)
|
||||
GridSize::GridSize(double flex_factor)
|
||||
: m_type(Type::FlexibleLength)
|
||||
, m_length_percentage { Length::make_px(0) }
|
||||
, m_flex_factor(flex_factor)
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
};
|
||||
|
||||
GridSize(LengthPercentage);
|
||||
GridSize(float);
|
||||
GridSize(double);
|
||||
GridSize(Type);
|
||||
GridSize();
|
||||
~GridSize();
|
||||
|
@ -37,7 +37,7 @@ public:
|
|||
bool is_min_content() const { return m_type == Type::MinContent; }
|
||||
|
||||
LengthPercentage length_percentage() const { return m_length_percentage; };
|
||||
float flex_factor() const { return m_flex_factor; }
|
||||
double flex_factor() const { return m_flex_factor; }
|
||||
|
||||
// https://www.w3.org/TR/css-grid-2/#layout-algorithm
|
||||
// An intrinsic sizing function (min-content, max-content, auto, fit-content()).
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
private:
|
||||
Type m_type;
|
||||
LengthPercentage m_length_percentage;
|
||||
float m_flex_factor { 0 };
|
||||
double m_flex_factor { 0 };
|
||||
};
|
||||
|
||||
class GridMinMax {
|
||||
|
|
|
@ -35,7 +35,7 @@ Length::Length(int value, Type type)
|
|||
, m_value(value)
|
||||
{
|
||||
}
|
||||
Length::Length(float value, Type type)
|
||||
Length::Length(double value, Type type)
|
||||
: m_type(type)
|
||||
, m_value(value)
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ Length Length::percentage_of(Percentage const& percentage) const
|
|||
return *this;
|
||||
}
|
||||
|
||||
return Length { percentage.as_fraction() * raw_value(), m_type };
|
||||
return Length { static_cast<double>(percentage.as_fraction()) * raw_value(), m_type };
|
||||
}
|
||||
|
||||
CSSPixels Length::font_relative_length_to_px(Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
static Optional<Type> unit_from_name(StringView);
|
||||
|
||||
Length(int value, Type type);
|
||||
Length(float value, Type type);
|
||||
Length(double value, Type type);
|
||||
~Length();
|
||||
|
||||
static Length make_auto();
|
||||
|
@ -154,7 +154,7 @@ public:
|
|||
}
|
||||
|
||||
Type type() const { return m_type; }
|
||||
float raw_value() const { return m_value; }
|
||||
double raw_value() const { return m_value; }
|
||||
|
||||
CSSPixels to_px(Layout::Node const&) const;
|
||||
|
||||
|
@ -171,8 +171,8 @@ public:
|
|||
|
||||
ALWAYS_INLINE CSSPixels absolute_length_to_px() const
|
||||
{
|
||||
constexpr float inch_pixels = 96.0f;
|
||||
constexpr float centimeter_pixels = (inch_pixels / 2.54f);
|
||||
constexpr double inch_pixels = 96.0;
|
||||
constexpr double centimeter_pixels = (inch_pixels / 2.54);
|
||||
switch (m_type) {
|
||||
case Type::Cm:
|
||||
return m_value * centimeter_pixels; // 1cm = 96px/2.54
|
||||
|
@ -181,13 +181,13 @@ public:
|
|||
case Type::Px:
|
||||
return m_value; // 1px = 1/96th of 1in
|
||||
case Type::Pt:
|
||||
return m_value * ((1.0f / 72.0f) * inch_pixels); // 1pt = 1/72th of 1in
|
||||
return m_value * ((1.0 / 72.0) * inch_pixels); // 1pt = 1/72th of 1in
|
||||
case Type::Pc:
|
||||
return m_value * ((1.0f / 6.0f) * inch_pixels); // 1pc = 1/6th of 1in
|
||||
return m_value * ((1.0 / 6.0) * inch_pixels); // 1pc = 1/6th of 1in
|
||||
case Type::Mm:
|
||||
return m_value * ((1.0f / 10.0f) * centimeter_pixels); // 1mm = 1/10th of 1cm
|
||||
return m_value * ((1.0 / 10.0) * centimeter_pixels); // 1mm = 1/10th of 1cm
|
||||
case Type::Q:
|
||||
return m_value * ((1.0f / 40.0f) * centimeter_pixels); // 1Q = 1/40th of 1cm
|
||||
return m_value * ((1.0 / 40.0) * centimeter_pixels); // 1Q = 1/40th of 1cm
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ private:
|
|||
char const* unit_name() const;
|
||||
|
||||
Type m_type;
|
||||
float m_value { 0 };
|
||||
double m_value { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@ CSSPixelPoint PositionValue::resolved(Layout::Node const& node, CSSPixelRect con
|
|||
return rect.width() * [&] {
|
||||
switch (preset) {
|
||||
case HorizontalPreset::Left:
|
||||
return 0.0f;
|
||||
return 0.;
|
||||
case HorizontalPreset::Center:
|
||||
return 0.5f;
|
||||
return 0.5;
|
||||
case HorizontalPreset::Right:
|
||||
return 1.0f;
|
||||
return 1.;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -36,11 +36,11 @@ CSSPixelPoint PositionValue::resolved(Layout::Node const& node, CSSPixelRect con
|
|||
return rect.height() * [&] {
|
||||
switch (preset) {
|
||||
case VerticalPreset::Top:
|
||||
return 0.0f;
|
||||
return 0.;
|
||||
case VerticalPreset::Center:
|
||||
return 0.5f;
|
||||
return 0.5;
|
||||
case VerticalPreset::Bottom:
|
||||
return 1.0f;
|
||||
return 1.;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -1264,7 +1264,7 @@ void StyleComputer::compute_font(StyleProperties& style, DOM::Element const* ele
|
|||
Optional<Length> maybe_length;
|
||||
if (font_size->is_percentage()) {
|
||||
// Percentages refer to parent element's font size
|
||||
maybe_length = Length::make_px(font_size->as_percentage().percentage().as_fraction() * parent_font_size());
|
||||
maybe_length = Length::make_px(static_cast<double>(font_size->as_percentage().percentage().as_fraction()) * parent_font_size());
|
||||
|
||||
} else if (font_size->is_length()) {
|
||||
maybe_length = font_size->to_length();
|
||||
|
@ -1438,7 +1438,7 @@ ErrorOr<void> StyleComputer::absolutize_values(StyleProperties& style, DOM::Elem
|
|||
auto& line_height_value_slot = style.m_property_values[to_underlying(CSS::PropertyID::LineHeight)];
|
||||
if (line_height_value_slot && line_height_value_slot->is_percentage()) {
|
||||
line_height_value_slot = TRY(LengthStyleValue::create(
|
||||
Length::make_px(font_size * line_height_value_slot->as_percentage().percentage().as_fraction())));
|
||||
Length::make_px(font_size * static_cast<double>(line_height_value_slot->as_percentage().percentage().as_fraction()))));
|
||||
}
|
||||
|
||||
auto line_height = style.line_height(viewport_rect(), font_metrics, m_root_element_font_metrics);
|
||||
|
|
|
@ -536,7 +536,7 @@ void CalculatedStyleValue::CalculationResult::multiply_by(CalculationResult cons
|
|||
},
|
||||
[&](Length const& length) {
|
||||
VERIFY(layout_node);
|
||||
m_value = Length::make_px(length.to_px(*layout_node) * other.m_value.get<Number>().value());
|
||||
m_value = Length::make_px(length.to_px(*layout_node) * static_cast<double>(other.m_value.get<Number>().value()));
|
||||
},
|
||||
[&](Time const& time) {
|
||||
m_value = Time::make_seconds(time.to_seconds() * other.m_value.get<Number>().value());
|
||||
|
@ -569,7 +569,7 @@ void CalculatedStyleValue::CalculationResult::divide_by(CalculationResult const&
|
|||
},
|
||||
[&](Length const& length) {
|
||||
VERIFY(layout_node);
|
||||
m_value = Length::make_px(length.to_px(*layout_node) / denominator);
|
||||
m_value = Length::make_px(length.to_px(*layout_node) / static_cast<double>(denominator));
|
||||
},
|
||||
[&](Time const& time) {
|
||||
m_value = Time::make_seconds(time.to_seconds() / denominator);
|
||||
|
|
|
@ -30,7 +30,7 @@ Filter::DropShadow::Resolved Filter::DropShadow::resolved(Layout::Node const& no
|
|||
return Resolved {
|
||||
offset_x.to_px(node).value(),
|
||||
offset_y.to_px(node).value(),
|
||||
radius.has_value() ? radius->to_px(node).value() : 0.0f,
|
||||
radius.has_value() ? radius->to_px(node).value() : 0.0,
|
||||
color.has_value() ? *color : node.computed_values().color()
|
||||
};
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@ struct DropShadow {
|
|||
Optional<Length> radius {};
|
||||
Optional<Color> color {};
|
||||
struct Resolved {
|
||||
float offset_x;
|
||||
float offset_y;
|
||||
float radius;
|
||||
double offset_x;
|
||||
double offset_y;
|
||||
double radius;
|
||||
Color color;
|
||||
};
|
||||
Resolved resolved(Layout::Node const&) const;
|
||||
|
|
|
@ -146,12 +146,12 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node,
|
|||
},
|
||||
[&](CircleSize const& circle_size) {
|
||||
auto radius = circle_size.radius.to_px(node);
|
||||
return Gfx::FloatSize { radius, radius };
|
||||
return Gfx::FloatSize { radius.value(), radius.value() };
|
||||
},
|
||||
[&](EllipseSize const& ellipse_size) {
|
||||
auto radius_a = ellipse_size.radius_a.resolved(node, CSS::Length::make_px(size.width())).to_px(node);
|
||||
auto radius_b = ellipse_size.radius_b.resolved(node, CSS::Length::make_px(size.height())).to_px(node);
|
||||
return Gfx::FloatSize { radius_a, radius_b };
|
||||
return Gfx::FloatSize { radius_a.value(), radius_b.value() };
|
||||
});
|
||||
|
||||
// Handle degenerate cases
|
||||
|
@ -187,8 +187,8 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node,
|
|||
void RadialGradientStyleValue::resolve_for_size(Layout::Node const& node, CSSPixelSize paint_size) const
|
||||
{
|
||||
CSSPixelRect gradient_box { { 0, 0 }, paint_size };
|
||||
auto center = m_properties.position.resolved(node, gradient_box).to_type<float>();
|
||||
auto gradient_size = resolve_size(node, center, gradient_box.to_type<float>());
|
||||
auto center = m_properties.position.resolved(node, gradient_box).to_type<double>().to_type<float>();
|
||||
auto gradient_size = resolve_size(node, center, gradient_box.to_type<double>().to_type<float>());
|
||||
if (m_resolved.has_value() && m_resolved->gradient_size == gradient_size)
|
||||
return;
|
||||
m_resolved = ResolvedData {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue