mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 15:17:36 +00:00
LibWeb: Remove implicit conversion from float and double to CSSPixels
In general it is not safe to convert any arbitrary floating-point value to CSSPixels. CSSPixels has a resolution of 0.015625, which for small values (e.g. scale factors between 0 and 1), can produce bad results if converted to CSSPixels then scaled back up. In the worst case values can underflow to zero and produce incorrect results.
This commit is contained in:
parent
0f9c088302
commit
360c0eb509
43 changed files with 248 additions and 221 deletions
|
@ -24,10 +24,10 @@ Gfx::FloatRect EdgeRect::resolved(Layout::Node const& layout_node, Gfx::Rect<dou
|
|||
// widths for <bottom>, and the same as the used value of the width plus the sum of the
|
||||
// horizontal padding and border widths for <right>, such that four 'auto' values result in the
|
||||
// clipping region being the same as the element's border box).
|
||||
auto left = border_box.left() + (left_edge.is_auto() ? 0 : left_edge.to_px(layout_node)).to_double();
|
||||
auto top = border_box.top() + (top_edge.is_auto() ? 0 : top_edge.to_px(layout_node)).to_double();
|
||||
auto right = border_box.left() + (right_edge.is_auto() ? border_box.width() : right_edge.to_px(layout_node)).to_double();
|
||||
auto bottom = border_box.top() + (bottom_edge.is_auto() ? border_box.height() : bottom_edge.to_px(layout_node)).to_double();
|
||||
auto left = border_box.left() + (left_edge.is_auto() ? 0 : left_edge.to_px(layout_node).to_double());
|
||||
auto top = border_box.top() + (top_edge.is_auto() ? 0 : top_edge.to_px(layout_node).to_double());
|
||||
auto right = border_box.left() + (right_edge.is_auto() ? border_box.width() : right_edge.to_px(layout_node).to_double());
|
||||
auto bottom = border_box.top() + (bottom_edge.is_auto() ? border_box.height() : bottom_edge.to_px(layout_node).to_double());
|
||||
return Gfx::FloatRect {
|
||||
left,
|
||||
top,
|
||||
|
|
|
@ -61,31 +61,31 @@ CSSPixels Length::font_relative_length_to_px(Length::FontMetrics const& font_met
|
|||
{
|
||||
switch (m_type) {
|
||||
case Type::Em:
|
||||
return m_value * font_metrics.font_size.to_double();
|
||||
return CSSPixels(m_value * font_metrics.font_size.to_double());
|
||||
case Type::Rem:
|
||||
return m_value * root_font_metrics.font_size.to_double();
|
||||
return CSSPixels(m_value * root_font_metrics.font_size.to_double());
|
||||
case Type::Ex:
|
||||
return m_value * font_metrics.x_height.to_double();
|
||||
return CSSPixels(m_value * font_metrics.x_height.to_double());
|
||||
case Type::Rex:
|
||||
return m_value * root_font_metrics.x_height.to_double();
|
||||
return CSSPixels(m_value * root_font_metrics.x_height.to_double());
|
||||
case Type::Cap:
|
||||
return m_value * font_metrics.cap_height.to_double();
|
||||
return CSSPixels(m_value * font_metrics.cap_height.to_double());
|
||||
case Type::Rcap:
|
||||
return m_value * root_font_metrics.cap_height.to_double();
|
||||
return CSSPixels(m_value * root_font_metrics.cap_height.to_double());
|
||||
case Type::Ch:
|
||||
return m_value * font_metrics.zero_advance.to_double();
|
||||
return CSSPixels(m_value * font_metrics.zero_advance.to_double());
|
||||
case Type::Rch:
|
||||
return m_value * root_font_metrics.zero_advance.to_double();
|
||||
return CSSPixels(m_value * root_font_metrics.zero_advance.to_double());
|
||||
case Type::Ic:
|
||||
// FIXME: Use the "advance measure of the “水” (CJK water ideograph, U+6C34) glyph"
|
||||
return m_value * font_metrics.font_size.to_double();
|
||||
return CSSPixels(m_value * font_metrics.font_size.to_double());
|
||||
case Type::Ric:
|
||||
// FIXME: Use the "advance measure of the “水” (CJK water ideograph, U+6C34) glyph"
|
||||
return m_value * root_font_metrics.font_size.to_double();
|
||||
return CSSPixels(m_value * root_font_metrics.font_size.to_double());
|
||||
case Type::Lh:
|
||||
return m_value * font_metrics.line_height.to_double();
|
||||
return CSSPixels(m_value * font_metrics.line_height.to_double());
|
||||
case Type::Rlh:
|
||||
return m_value * root_font_metrics.line_height.to_double();
|
||||
return CSSPixels(m_value * root_font_metrics.line_height.to_double());
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -98,34 +98,34 @@ CSSPixels Length::viewport_relative_length_to_px(CSSPixelRect const& viewport_re
|
|||
case Type::Svw:
|
||||
case Type::Lvw:
|
||||
case Type::Dvw:
|
||||
return viewport_rect.width() * (m_value / 100);
|
||||
return CSSPixels(viewport_rect.width() * (m_value / 100));
|
||||
case Type::Vh:
|
||||
case Type::Svh:
|
||||
case Type::Lvh:
|
||||
case Type::Dvh:
|
||||
return viewport_rect.height() * (m_value / 100);
|
||||
return CSSPixels(viewport_rect.height() * (m_value / 100));
|
||||
case Type::Vi:
|
||||
case Type::Svi:
|
||||
case Type::Lvi:
|
||||
case Type::Dvi:
|
||||
// FIXME: Select the width or height based on which is the inline axis.
|
||||
return viewport_rect.width() * (m_value / 100);
|
||||
return CSSPixels(viewport_rect.width() * (m_value / 100));
|
||||
case Type::Vb:
|
||||
case Type::Svb:
|
||||
case Type::Lvb:
|
||||
case Type::Dvb:
|
||||
// FIXME: Select the width or height based on which is the block axis.
|
||||
return viewport_rect.height() * (m_value / 100);
|
||||
return CSSPixels(viewport_rect.height() * (m_value / 100));
|
||||
case Type::Vmin:
|
||||
case Type::Svmin:
|
||||
case Type::Lvmin:
|
||||
case Type::Dvmin:
|
||||
return min(viewport_rect.width(), viewport_rect.height()) * (m_value / 100);
|
||||
return CSSPixels(min(viewport_rect.width(), viewport_rect.height()) * (m_value / 100));
|
||||
case Type::Vmax:
|
||||
case Type::Svmax:
|
||||
case Type::Lvmax:
|
||||
case Type::Dvmax:
|
||||
return max(viewport_rect.width(), viewport_rect.height()) * (m_value / 100);
|
||||
return CSSPixels(max(viewport_rect.width(), viewport_rect.height()) * (m_value / 100));
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -138,8 +138,8 @@ Length::ResolutionContext Length::ResolutionContext::for_layout_node(Layout::Nod
|
|||
VERIFY(root_element->layout_node());
|
||||
return Length::ResolutionContext {
|
||||
.viewport_rect = node.browsing_context().viewport_rect(),
|
||||
.font_metrics = { node.computed_values().font_size(), node.font().pixel_metrics(), node.line_height() },
|
||||
.root_font_metrics = { root_element->layout_node()->computed_values().font_size(), root_element->layout_node()->font().pixel_metrics(), root_element->layout_node()->line_height() },
|
||||
.font_metrics = { CSSPixels(node.computed_values().font_size()), node.font().pixel_metrics(), node.line_height() },
|
||||
.root_font_metrics = { CSSPixels(root_element->layout_node()->computed_values().font_size()), root_element->layout_node()->font().pixel_metrics(), root_element->layout_node()->line_height() },
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -168,12 +168,12 @@ CSSPixels Length::to_px(Layout::Node const& layout_node) const
|
|||
return 0;
|
||||
|
||||
FontMetrics font_metrics {
|
||||
layout_node.computed_values().font_size(),
|
||||
CSSPixels(layout_node.computed_values().font_size()),
|
||||
layout_node.font().pixel_metrics(),
|
||||
layout_node.line_height()
|
||||
};
|
||||
FontMetrics root_font_metrics {
|
||||
root_element->layout_node()->computed_values().font_size(),
|
||||
CSSPixels(root_element->layout_node()->computed_values().font_size()),
|
||||
root_element->layout_node()->font().pixel_metrics(),
|
||||
root_element->layout_node()->line_height()
|
||||
};
|
||||
|
|
|
@ -185,19 +185,19 @@ public:
|
|||
constexpr double centimeter_pixels = (inch_pixels / 2.54);
|
||||
switch (m_type) {
|
||||
case Type::Cm:
|
||||
return m_value * centimeter_pixels; // 1cm = 96px/2.54
|
||||
return CSSPixels(m_value * centimeter_pixels); // 1cm = 96px/2.54
|
||||
case Type::In:
|
||||
return m_value * inch_pixels; // 1in = 2.54 cm = 96px
|
||||
return CSSPixels(m_value * inch_pixels); // 1in = 2.54 cm = 96px
|
||||
case Type::Px:
|
||||
return m_value; // 1px = 1/96th of 1in
|
||||
return CSSPixels(m_value); // 1px = 1/96th of 1in
|
||||
case Type::Pt:
|
||||
return m_value * ((1.0 / 72.0) * inch_pixels); // 1pt = 1/72th of 1in
|
||||
return CSSPixels(m_value * ((1.0 / 72.0) * inch_pixels)); // 1pt = 1/72th of 1in
|
||||
case Type::Pc:
|
||||
return m_value * ((1.0 / 6.0) * inch_pixels); // 1pc = 1/6th of 1in
|
||||
return CSSPixels(m_value * ((1.0 / 6.0) * inch_pixels)); // 1pc = 1/6th of 1in
|
||||
case Type::Mm:
|
||||
return m_value * ((1.0 / 10.0) * centimeter_pixels); // 1mm = 1/10th of 1cm
|
||||
return CSSPixels(m_value * ((1.0 / 10.0) * centimeter_pixels)); // 1mm = 1/10th of 1cm
|
||||
case Type::Q:
|
||||
return m_value * ((1.0 / 40.0) * centimeter_pixels); // 1Q = 1/40th of 1cm
|
||||
return CSSPixels(m_value * ((1.0 / 40.0) * centimeter_pixels)); // 1Q = 1/40th of 1cm
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ bool MediaFeature::compare(HTML::Window const& window, MediaFeatureValue left, C
|
|||
|
||||
auto const& initial_font = window.associated_document().style_computer().initial_font();
|
||||
Gfx::FontPixelMetrics const& initial_font_metrics = initial_font.pixel_metrics();
|
||||
Length::FontMetrics font_metrics { static_cast<CSSPixels>(initial_font.presentation_size()), initial_font_metrics, initial_font_metrics.line_spacing() };
|
||||
Length::FontMetrics font_metrics { CSSPixels(initial_font.presentation_size()), initial_font_metrics, CSSPixels(initial_font_metrics.line_spacing()) };
|
||||
|
||||
left_px = left.length().to_px(viewport_rect, font_metrics, font_metrics);
|
||||
right_px = right.length().to_px(viewport_rect, font_metrics, font_metrics);
|
||||
|
|
|
@ -1787,7 +1787,7 @@ Optional<Dimension> Parser::parse_dimension(ComponentValue const& component_valu
|
|||
// FIXME: Disallow quirk when inside a CSS sub-expression (like `calc()`)
|
||||
// "The <quirky-length> value must not be supported in arguments to CSS expressions other than the rect()
|
||||
// expression, and must not be supported in the supports() static method of the CSS interface."
|
||||
return Length::make_px(numeric_value);
|
||||
return Length::make_px(CSSPixels(numeric_value));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,11 @@ CSSPixelPoint PositionValue::resolved(Layout::Node const& node, CSSPixelRect con
|
|||
return rect.width() * [&] {
|
||||
switch (preset) {
|
||||
case HorizontalPreset::Left:
|
||||
return 0.;
|
||||
return CSSPixels(0.0);
|
||||
case HorizontalPreset::Center:
|
||||
return 0.5;
|
||||
return CSSPixels(0.5);
|
||||
case HorizontalPreset::Right:
|
||||
return 1.;
|
||||
return CSSPixels(1.0);
|
||||
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.;
|
||||
return CSSPixels(0.0);
|
||||
case VerticalPreset::Center:
|
||||
return 0.5;
|
||||
return CSSPixels(0.5);
|
||||
case VerticalPreset::Bottom:
|
||||
return 1.;
|
||||
return CSSPixels(1.0);
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -596,7 +596,7 @@ RefPtr<StyleValue const> ResolvedCSSStyleDeclaration::style_value_for_property(L
|
|||
case PropertyID::Float:
|
||||
return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().float_()));
|
||||
case PropertyID::FontSize:
|
||||
return LengthStyleValue::create(Length::make_px(layout_node.computed_values().font_size()));
|
||||
return LengthStyleValue::create(Length::make_px(CSSPixels(layout_node.computed_values().font_size())));
|
||||
case PropertyID::FontVariant: {
|
||||
auto font_variant = layout_node.computed_values().font_variant();
|
||||
switch (font_variant) {
|
||||
|
|
|
@ -2036,7 +2036,7 @@ Length::FontMetrics StyleComputer::calculate_root_element_font_metrics(StyleProp
|
|||
auto root_value = style.property(CSS::PropertyID::FontSize);
|
||||
|
||||
auto font_pixel_metrics = style.computed_font().pixel_metrics();
|
||||
Length::FontMetrics font_metrics { m_default_font_metrics.font_size, font_pixel_metrics, font_pixel_metrics.line_spacing() };
|
||||
Length::FontMetrics font_metrics { m_default_font_metrics.font_size, font_pixel_metrics, CSSPixels(font_pixel_metrics.line_spacing()) };
|
||||
font_metrics.font_size = root_value->as_length().length().to_px(viewport_rect(), font_metrics, font_metrics);
|
||||
font_metrics.line_height = style.line_height(viewport_rect(), font_metrics, font_metrics);
|
||||
|
||||
|
@ -2150,7 +2150,7 @@ RefPtr<Gfx::Font const> StyleComputer::compute_font_for_style_values(DOM::Elemen
|
|||
bool bold = weight > Gfx::FontWeight::Regular;
|
||||
|
||||
// FIXME: Should be based on "user's default font size"
|
||||
float font_size_in_px = 16;
|
||||
CSSPixels font_size_in_px = 16;
|
||||
|
||||
auto parent_line_height = parent_or_root_element_line_height(element, pseudo_element);
|
||||
Gfx::FontPixelMetrics font_pixel_metrics;
|
||||
|
@ -2197,11 +2197,11 @@ RefPtr<Gfx::Font const> StyleComputer::compute_font_for_style_values(DOM::Elemen
|
|||
// and smaller may compute the font size to the previous entry in the table.
|
||||
if (identifier == CSS::ValueID::Smaller || identifier == CSS::ValueID::Larger) {
|
||||
if (parent_element && parent_element->computed_css_values()) {
|
||||
font_size_in_px = parent_element->computed_css_values()->computed_font().pixel_metrics().size;
|
||||
font_size_in_px = CSSPixels(parent_element->computed_css_values()->computed_font().pixel_metrics().size);
|
||||
}
|
||||
}
|
||||
auto const multiplier = absolute_size_mapping.get(identifier).value_or(1.0);
|
||||
font_size_in_px *= multiplier;
|
||||
font_size_in_px.scale_by(multiplier);
|
||||
|
||||
} else {
|
||||
Length::ResolutionContext const length_resolution_context {
|
||||
|
@ -2213,7 +2213,7 @@ RefPtr<Gfx::Font const> StyleComputer::compute_font_for_style_values(DOM::Elemen
|
|||
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().to_double());
|
||||
maybe_length = Length::make_px(CSSPixels(font_size.as_percentage().percentage().as_fraction() * parent_font_size().to_double()));
|
||||
|
||||
} else if (font_size.is_length()) {
|
||||
maybe_length = font_size.as_length().length();
|
||||
|
@ -2350,7 +2350,7 @@ void StyleComputer::compute_font(StyleProperties& style, DOM::Element const* ele
|
|||
|
||||
auto found_font = compute_font_for_style_values(element, pseudo_element, font_family, font_size, font_style, font_weight, font_stretch);
|
||||
|
||||
style.set_property(CSS::PropertyID::FontSize, LengthStyleValue::create(CSS::Length::make_px(found_font->pixel_size())), nullptr);
|
||||
style.set_property(CSS::PropertyID::FontSize, LengthStyleValue::create(CSS::Length::make_px(CSSPixels(found_font->pixel_size()))), nullptr);
|
||||
style.set_property(CSS::PropertyID::FontWeight, NumberStyleValue::create(font_weight->to_font_weight()));
|
||||
|
||||
style.set_computed_font(found_font.release_nonnull());
|
||||
|
@ -2401,7 +2401,7 @@ void StyleComputer::absolutize_values(StyleProperties& style, DOM::Element const
|
|||
auto line_height_value_slot = style.m_property_values[to_underlying(CSS::PropertyID::LineHeight)].map([](auto& x) -> auto& { return x.style; });
|
||||
if (line_height_value_slot.has_value() && (*line_height_value_slot)->is_percentage()) {
|
||||
*line_height_value_slot = LengthStyleValue::create(
|
||||
Length::make_px(font_size * static_cast<double>((*line_height_value_slot)->as_percentage().percentage().as_fraction())));
|
||||
Length::make_px(CSSPixels(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);
|
||||
|
|
|
@ -204,7 +204,7 @@ CSSPixels StyleProperties::line_height(Layout::Node const& layout_node) const
|
|||
auto line_height = property(CSS::PropertyID::LineHeight);
|
||||
|
||||
if (line_height->is_identifier() && line_height->to_identifier() == ValueID::Normal)
|
||||
return layout_node.font().pixel_metrics().line_spacing();
|
||||
return CSSPixels(layout_node.font().pixel_metrics().line_spacing());
|
||||
|
||||
if (line_height->is_length()) {
|
||||
auto line_height_length = line_height->as_length().length();
|
||||
|
@ -226,7 +226,7 @@ CSSPixels StyleProperties::line_height(Layout::Node const& layout_node) const
|
|||
auto resolved = line_height->as_calculated().resolve_number();
|
||||
if (!resolved.has_value()) {
|
||||
dbgln("FIXME: Failed to resolve calc() line-height (number): {}", line_height->as_calculated().to_string());
|
||||
return layout_node.font().pixel_metrics().line_spacing();
|
||||
return CSSPixels(layout_node.font().pixel_metrics().line_spacing());
|
||||
}
|
||||
return Length(resolved.value(), Length::Type::Em).to_px(layout_node);
|
||||
}
|
||||
|
@ -234,12 +234,12 @@ CSSPixels StyleProperties::line_height(Layout::Node const& layout_node) const
|
|||
auto resolved = line_height->as_calculated().resolve_length(layout_node);
|
||||
if (!resolved.has_value()) {
|
||||
dbgln("FIXME: Failed to resolve calc() line-height: {}", line_height->as_calculated().to_string());
|
||||
return layout_node.font().pixel_metrics().line_spacing();
|
||||
return CSSPixels(layout_node.font().pixel_metrics().line_spacing());
|
||||
}
|
||||
return resolved->to_px(layout_node);
|
||||
}
|
||||
|
||||
return layout_node.font().pixel_metrics().line_spacing();
|
||||
return CSSPixels(layout_node.font().pixel_metrics().line_spacing());
|
||||
}
|
||||
|
||||
Optional<int> StyleProperties::z_index() const
|
||||
|
|
|
@ -77,7 +77,7 @@ static CalculatedStyleValue::CalculationResult to_resolved_type(CalculatedStyleV
|
|||
case CalculatedStyleValue::ResolvedType::Frequency:
|
||||
return { Frequency::make_hertz(value) };
|
||||
case CalculatedStyleValue::ResolvedType::Length:
|
||||
return { Length::make_px(value) };
|
||||
return { Length::make_px(CSSPixels(value)) };
|
||||
case CalculatedStyleValue::ResolvedType::Percentage:
|
||||
return { Percentage(value) };
|
||||
case CalculatedStyleValue::ResolvedType::Time:
|
||||
|
@ -2155,7 +2155,7 @@ void CalculatedStyleValue::CalculationResult::multiply_by(CalculationResult cons
|
|||
m_value = Frequency::make_hertz(frequency.to_hertz() * other.m_value.get<Number>().value());
|
||||
},
|
||||
[&](Length const& length) {
|
||||
m_value = Length::make_px(length.to_px(*context) * static_cast<double>(other.m_value.get<Number>().value()));
|
||||
m_value = Length::make_px(CSSPixels(length.to_px(*context) * 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());
|
||||
|
@ -2187,7 +2187,7 @@ void CalculatedStyleValue::CalculationResult::divide_by(CalculationResult const&
|
|||
m_value = Frequency::make_hertz(frequency.to_hertz() / denominator);
|
||||
},
|
||||
[&](Length const& length) {
|
||||
m_value = Length::make_px(length.to_px(*context) / static_cast<double>(denominator));
|
||||
m_value = Length::make_px(CSSPixels(length.to_px(*context) / static_cast<double>(denominator)));
|
||||
},
|
||||
[&](Time const& time) {
|
||||
m_value = Time::make_seconds(time.to_seconds() / denominator);
|
||||
|
|
|
@ -150,8 +150,8 @@ Gfx::FloatSize RadialGradientStyleValue::resolve_size(Layout::Node const& node,
|
|||
return Gfx::FloatSize { radius.to_float(), radius.to_float() };
|
||||
},
|
||||
[&](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);
|
||||
auto radius_a = ellipse_size.radius_a.resolved(node, CSS::Length::make_px(CSSPixels(size.width()))).to_px(node);
|
||||
auto radius_b = ellipse_size.radius_b.resolved(node, CSS::Length::make_px(CSSPixels(size.height()))).to_px(node);
|
||||
return Gfx::FloatSize { radius_a.to_float(), radius_b.to_float() };
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue