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:
MacDue 2023-08-26 15:03:04 +01:00 committed by Alexander Kalenik
parent 0f9c088302
commit 360c0eb509
Notes: sideshowbarker 2024-07-17 10:10:18 +09:00
43 changed files with 248 additions and 221 deletions

View file

@ -2,37 +2,37 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x616 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x600 children: not-inline
Box <div.outer.row> at (8,8) content-size 150x150 flex-container(row) [FFC] children: not-inline
BlockContainer <div.inner> at (12.625,8) content-size 30.078125x150 flex-item [BFC] children: inline
BlockContainer <div.inner> at (12.609375,8) content-size 30.078125x150 flex-item [BFC] children: inline
line 0 width: 30.078125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 4, rect: [12.625,8 30.078125x17.46875]
frag 0 from TextNode start: 0, length: 4, rect: [12.609375,8 30.078125x17.46875]
"Well"
TextNode <#text>
BlockContainer <div.inner> at (51.9375,8) content-size 36.84375x150 flex-item [BFC] children: inline
BlockContainer <div.inner> at (51.921875,8) content-size 36.84375x150 flex-item [BFC] children: inline
line 0 width: 36.84375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 5, rect: [51.9375,8 36.84375x17.46875]
frag 0 from TextNode start: 0, length: 5, rect: [51.921875,8 36.84375x17.46875]
"hello"
TextNode <#text>
BlockContainer <div.inner> at (98.015625,8) content-size 55.359375x150 flex-item [BFC] children: inline
BlockContainer <div.inner> at (98,8) content-size 55.359375x150 flex-item [BFC] children: inline
line 0 width: 55.359375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 7, rect: [98.015625,8 55.359375x17.46875]
frag 0 from TextNode start: 0, length: 7, rect: [98,8 55.359375x17.46875]
"friends"
TextNode <#text>
BlockContainer <(anonymous)> at (8,158) content-size 784x0 children: inline
TextNode <#text>
Box <div.outer.row-reverse> at (8,158) content-size 150x150 flex-container(row-reverse) [FFC] children: not-inline
BlockContainer <div.inner> at (123.296875,158) content-size 30.078125x150 flex-item [BFC] children: inline
BlockContainer <div.inner> at (123.3125,158) content-size 30.078125x150 flex-item [BFC] children: inline
line 0 width: 30.078125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 4, rect: [123.296875,158 30.078125x17.46875]
frag 0 from TextNode start: 0, length: 4, rect: [123.3125,158 30.078125x17.46875]
"Well"
TextNode <#text>
BlockContainer <div.inner> at (77.21875,158) content-size 36.84375x150 flex-item [BFC] children: inline
BlockContainer <div.inner> at (77.234375,158) content-size 36.84375x150 flex-item [BFC] children: inline
line 0 width: 36.84375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 5, rect: [77.21875,158 36.84375x17.46875]
frag 0 from TextNode start: 0, length: 5, rect: [77.234375,158 36.84375x17.46875]
"hello"
TextNode <#text>
BlockContainer <div.inner> at (12.625,158) content-size 55.359375x150 flex-item [BFC] children: inline
BlockContainer <div.inner> at (12.640625,158) content-size 55.359375x150 flex-item [BFC] children: inline
line 0 width: 55.359375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 7, rect: [12.625,158 55.359375x17.46875]
frag 0 from TextNode start: 0, length: 7, rect: [12.640625,158 55.359375x17.46875]
"friends"
TextNode <#text>
BlockContainer <(anonymous)> at (8,308) content-size 784x0 children: inline
@ -76,19 +76,19 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 800x616]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x616]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x600]
PaintableBox (Box<DIV>.outer.row) [8,8 150x150]
PaintableWithLines (BlockContainer<DIV>.inner) [12.625,8 30.078125x150]
PaintableWithLines (BlockContainer<DIV>.inner) [12.609375,8 30.078125x150]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.inner) [51.9375,8 36.84375x150]
PaintableWithLines (BlockContainer<DIV>.inner) [51.921875,8 36.84375x150]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.inner) [98.015625,8 55.359375x150]
PaintableWithLines (BlockContainer<DIV>.inner) [98,8 55.359375x150]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,158 784x0]
PaintableBox (Box<DIV>.outer.row-reverse) [8,158 150x150]
PaintableWithLines (BlockContainer<DIV>.inner) [123.296875,158 30.078125x150]
PaintableWithLines (BlockContainer<DIV>.inner) [123.3125,158 30.078125x150]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.inner) [77.21875,158 36.84375x150]
PaintableWithLines (BlockContainer<DIV>.inner) [77.234375,158 36.84375x150]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.inner) [12.625,158 55.359375x150]
PaintableWithLines (BlockContainer<DIV>.inner) [12.640625,158 55.359375x150]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,308 784x0]
PaintableBox (Box<DIV>.outer.column) [8,308 150x150]

View file

@ -2,9 +2,9 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (1,1) content-size 798x37.46875 [BFC] children: not-inline
BlockContainer <body> at (10,10) content-size 780x19.46875 children: not-inline
Box <div.container> at (11,11) content-size 800x17.46875 flex-container(row) [FFC] children: not-inline
BlockContainer <(anonymous)> at (392.21875,11) content-size 37.578125x17.46875 flex-item [BFC] children: inline
BlockContainer <(anonymous)> at (392.203125,11) content-size 37.578125x17.46875 flex-item [BFC] children: inline
line 0 width: 37.578125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 4, rect: [392.21875,11 37.578125x17.46875]
frag 0 from TextNode start: 0, length: 4, rect: [392.203125,11 37.578125x17.46875]
"Text"
TextNode <#text>
@ -12,5 +12,5 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 812x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x39.46875] overflow: [1,1 811x37.46875]
PaintableWithLines (BlockContainer<BODY>) [9,9 782x21.46875] overflow: [10,10 802x19.46875]
PaintableBox (Box<DIV>.container) [10,10 802x19.46875]
PaintableWithLines (BlockContainer(anonymous)) [392.21875,11 37.578125x17.46875]
PaintableWithLines (BlockContainer(anonymous)) [392.203125,11 37.578125x17.46875]
TextPaintable (TextNode<#text>)

View file

@ -33,7 +33,7 @@ TEST_CASE(division1)
EXPECT_EQ(c, CSSPixels(2));
a = CSSPixels::from_raw(0x3FFF'FFFF); // int_max / 2
b = 0.25;
b = CSSPixels(0.25);
EXPECT(!a.might_be_saturated());
EXPECT((a / b).might_be_saturated());
}

View file

@ -1 +1 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque eu ante est. Integer ipsum sem, tincidunt quis felis quis, efficitur fringilla neque. Aliquam erat volutpat. Donec feugiat euismod sapien. Donec vel egestas arcu. Suspendisse luctus rhoncus mi quis elementum. Maecenas vel nisi maximus, viverra tellus quis, ultrices elit. Quisque congue velit quis lectus congue, ut consectetur nulla pharetra. Nullam euismod leo eget magna auctor, et bibendum urna tincidunt. Morbi molestie gravida ex ac consectetur. Duis pretium gravida augue eu sagittis. 193
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque eu ante est. Integer ipsum sem, tincidunt quis felis quis, efficitur fringilla neque. Aliquam erat volutpat. Donec feugiat euismod sapien. Donec vel egestas arcu. Suspendisse luctus rhoncus mi quis elementum. Maecenas vel nisi maximus, viverra tellus quis, ultrices elit. Quisque congue velit quis lectus congue, ut consectetur nulla pharetra. Nullam euismod leo eget magna auctor, et bibendum urna tincidunt. Morbi molestie gravida ex ac consectetur. Duis pretium gravida augue eu sagittis. 192

View file

@ -185,18 +185,18 @@ void InspectorWidget::update_node_box_model(StringView node_box_sizing_json)
auto json_value = json_or_error.release_value();
auto const& json_object = json_value.as_object();
m_node_box_sizing.margin.top = json_object.get_float("margin_top"sv).value_or(0);
m_node_box_sizing.margin.right = json_object.get_float("margin_right"sv).value_or(0);
m_node_box_sizing.margin.bottom = json_object.get_float("margin_bottom"sv).value_or(0);
m_node_box_sizing.margin.left = json_object.get_float("margin_left"sv).value_or(0);
m_node_box_sizing.padding.top = json_object.get_float("padding_top"sv).value_or(0);
m_node_box_sizing.padding.right = json_object.get_float("padding_right"sv).value_or(0);
m_node_box_sizing.padding.bottom = json_object.get_float("padding_bottom"sv).value_or(0);
m_node_box_sizing.padding.left = json_object.get_float("padding_left"sv).value_or(0);
m_node_box_sizing.border.top = json_object.get_float("border_top"sv).value_or(0);
m_node_box_sizing.border.right = json_object.get_float("border_right"sv).value_or(0);
m_node_box_sizing.border.bottom = json_object.get_float("border_bottom"sv).value_or(0);
m_node_box_sizing.border.left = json_object.get_float("border_left"sv).value_or(0);
m_node_box_sizing.margin.top = Web::CSSPixels(json_object.get_float("margin_top"sv).value_or(0));
m_node_box_sizing.margin.right = Web::CSSPixels(json_object.get_float("margin_right"sv).value_or(0));
m_node_box_sizing.margin.bottom = Web::CSSPixels(json_object.get_float("margin_bottom"sv).value_or(0));
m_node_box_sizing.margin.left = Web::CSSPixels(json_object.get_float("margin_left"sv).value_or(0));
m_node_box_sizing.padding.top = Web::CSSPixels(json_object.get_float("padding_top"sv).value_or(0));
m_node_box_sizing.padding.right = Web::CSSPixels(json_object.get_float("padding_right"sv).value_or(0));
m_node_box_sizing.padding.bottom = Web::CSSPixels(json_object.get_float("padding_bottom"sv).value_or(0));
m_node_box_sizing.padding.left = Web::CSSPixels(json_object.get_float("padding_left"sv).value_or(0));
m_node_box_sizing.border.top = Web::CSSPixels(json_object.get_float("border_top"sv).value_or(0));
m_node_box_sizing.border.right = Web::CSSPixels(json_object.get_float("border_right"sv).value_or(0));
m_node_box_sizing.border.bottom = Web::CSSPixels(json_object.get_float("border_bottom"sv).value_or(0));
m_node_box_sizing.border.left = Web::CSSPixels(json_object.get_float("border_left"sv).value_or(0));
m_element_size_view->set_node_content_width(json_object.get_float("content_width"sv).value_or(0));
m_element_size_view->set_node_content_height(json_object.get_float("content_height"sv).value_or(0));

View file

@ -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,

View file

@ -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()
};

View file

@ -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();
}

View file

@ -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);

View file

@ -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));
}
}

View file

@ -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();
}

View file

@ -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) {

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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() };
});

View file

@ -1085,7 +1085,7 @@ void Element::set_scroll_left(double x)
// 11. Scroll the element to x,scrollTop, with the scroll behavior being "auto".
// FIXME: Implement this in terms of calling "scroll the element".
auto scroll_offset = paintable_box()->scroll_offset();
scroll_offset.set_x(static_cast<float>(x));
scroll_offset.set_x(CSSPixels(x));
paintable_box()->set_scroll_offset(scroll_offset);
}
@ -1153,7 +1153,7 @@ void Element::set_scroll_top(double y)
// 11. Scroll the element to scrollLeft,y, with the scroll behavior being "auto".
// FIXME: Implement this in terms of calling "scroll the element".
auto scroll_offset = paintable_box()->scroll_offset();
scroll_offset.set_y(static_cast<float>(y));
scroll_offset.set_y(CSSPixels(y));
paintable_box()->set_scroll_offset(scroll_offset);
}

View file

@ -3993,14 +3993,14 @@ static RefPtr<CSS::StyleValue> parse_current_dimension_value(float value, Utf8Vi
{
// 1. If position is past the end of input, then return value as a length.
if (position == input.end())
return CSS::LengthStyleValue::create(CSS::Length::make_px(value));
return CSS::LengthStyleValue::create(CSS::Length::make_px(CSSPixels(value)));
// 2. If the code point at position within input is U+0025 (%), then return value as a percentage.
if (*position == '%')
return CSS::PercentageStyleValue::create(CSS::Percentage(value));
// 3. Return value as a length.
return CSS::LengthStyleValue::create(CSS::Length::make_px(value));
return CSS::LengthStyleValue::create(CSS::Length::make_px(CSSPixels(value)));
}
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-dimension-values
@ -4065,7 +4065,7 @@ RefPtr<CSS::StyleValue> parse_dimension_value(StringView string)
// 4. If position is past the end of input, then return value as a length.
if (position == input.end())
return CSS::LengthStyleValue::create(CSS::Length::make_px(value));
return CSS::LengthStyleValue::create(CSS::Length::make_px(CSSPixels(value)));
// 5. If the code point at position within input is not an ASCII digit, then break.
if (!is_ascii_digit(*position))

View file

@ -481,12 +481,12 @@ Optional<CSS::MediaFeatureValue> Window::query_media_feature(CSS::MediaFeatureID
// FIXME: device-aspect-ratio
case CSS::MediaFeatureID::DeviceHeight:
if (auto* page = this->page()) {
return CSS::MediaFeatureValue(CSS::Length::make_px(page->web_exposed_screen_area().height().to_double()));
return CSS::MediaFeatureValue(CSS::Length::make_px(page->web_exposed_screen_area().height()));
}
return CSS::MediaFeatureValue(0);
case CSS::MediaFeatureID::DeviceWidth:
if (auto* page = this->page()) {
return CSS::MediaFeatureValue(CSS::Length::make_px(page->web_exposed_screen_area().width().to_double()));
return CSS::MediaFeatureValue(CSS::Length::make_px(page->web_exposed_screen_area().width()));
}
return CSS::MediaFeatureValue(0);
case CSS::MediaFeatureID::DisplayMode:

View file

@ -36,7 +36,7 @@ public:
CSSPixels to_px_or_zero() const
{
if (!is_definite())
return 0.0f;
return 0;
return m_value;
}

View file

@ -1069,7 +1069,7 @@ void BlockFormattingContext::layout_list_item_marker(ListItemBox const& list_ite
marker_state.set_content_width(image_width + default_marker_width);
} else {
auto text_width = marker.font().width(marker.text());
marker_state.set_content_width(image_width + text_width);
marker_state.set_content_width(image_width + CSSPixels(text_width));
}
marker_state.set_content_height(max(image_height, marker.font().pixel_size_rounded_up() + 1));

View file

@ -25,7 +25,7 @@ void ButtonBox::prepare_for_replaced_layout()
// value attribute. This is not the case with <button />, which contains
// its contents normally.
if (is<HTML::HTMLInputElement>(dom_node())) {
set_natural_width(font().width(static_cast<HTML::HTMLInputElement&>(dom_node()).value()));
set_natural_width(CSSPixels(font().width(static_cast<HTML::HTMLInputElement&>(dom_node()).value())));
set_natural_height(font().pixel_size_rounded_up());
}
}

View file

@ -540,15 +540,15 @@ CSS::FlexBasis FlexFormattingContext::used_flex_basis_for_item(FlexItem const& i
CSSPixels FlexFormattingContext::calculate_main_size_from_cross_size_and_aspect_ratio(CSSPixels cross_size, double aspect_ratio) const
{
if (is_row_layout())
return cross_size * aspect_ratio;
return cross_size / aspect_ratio;
return CSSPixels(cross_size * aspect_ratio);
return CSSPixels(cross_size / aspect_ratio);
}
CSSPixels FlexFormattingContext::calculate_cross_size_from_main_size_and_aspect_ratio(CSSPixels main_size, double aspect_ratio) const
{
if (is_row_layout())
return main_size / aspect_ratio;
return main_size * aspect_ratio;
return CSSPixels(main_size / aspect_ratio);
return CSSPixels(main_size * aspect_ratio);
}
// This function takes a size in the main axis and adjusts it according to the aspect ratio of the box
@ -687,7 +687,7 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
// The hypothetical main size is the items flex base size clamped according to its used min and max main sizes (and flooring the content box size at zero).
auto clamp_min = has_main_min_size(child_box) ? specified_main_min_size(child_box) : automatic_minimum_size(item);
auto clamp_max = has_main_max_size(child_box) ? specified_main_max_size(child_box) : NumericLimits<float>::max();
auto clamp_max = has_main_max_size(child_box) ? specified_main_max_size(child_box) : CSSPixels::max();
item.hypothetical_main_size = max(CSSPixels(0), css_clamp(item.flex_base_size, clamp_min, clamp_max));
// NOTE: At this point, we set the hypothetical main size as the flex item's *temporary* main size.
@ -982,7 +982,7 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
// If the sum of the unfrozen flex items flex factors is less than one, multiply the initial free space by this sum.
if (auto sum_of_flex_factor_of_unfrozen_items = line.sum_of_flex_factor_of_unfrozen_items(); sum_of_flex_factor_of_unfrozen_items < 1 && initial_free_space.has_value()) {
auto value = initial_free_space.value() * sum_of_flex_factor_of_unfrozen_items;
auto value = CSSPixels(initial_free_space.value() * sum_of_flex_factor_of_unfrozen_items);
// If the magnitude of this value is less than the magnitude of the remaining free space, use this as the remaining free space.
if (abs(value) < abs(line.remaining_free_space.value()))
line.remaining_free_space = value;
@ -1004,7 +1004,7 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
continue;
double ratio = item.flex_factor.value() / sum_of_flex_factor_of_unfrozen_items;
// Set the items target main size to its flex base size plus a fraction of the remaining free space proportional to the ratio.
item.target_main_size = item.flex_base_size + (remaining_free_space_or_zero_if_infinite * ratio);
item.target_main_size = item.flex_base_size + remaining_free_space_or_zero_if_infinite.scaled(ratio);
}
}
// If using the flex shrink factor
@ -1026,7 +1026,7 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
// Set the items target main size to its flex base size minus a fraction of the absolute value of the remaining free space proportional to the ratio.
// (Note this may result in a negative inner main size; it will be corrected in the next step.)
item.target_main_size = item.flex_base_size - (abs(remaining_free_space_or_zero_if_infinite) * ratio);
item.target_main_size = item.flex_base_size - abs(remaining_free_space_or_zero_if_infinite).scaled(ratio);
}
}
}
@ -1044,7 +1044,7 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
auto used_max_main_size = has_main_max_size(item.box)
? specified_main_max_size(item.box)
: NumericLimits<float>::max();
: CSSPixels::max();
auto original_target_main_size = item.target_main_size;
item.target_main_size = css_clamp(item.target_main_size, used_min_main_size, used_max_main_size);
@ -1123,7 +1123,7 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem&
auto const& computed_max_size = this->computed_cross_max_size(item.box);
auto clamp_min = (!computed_min_size.is_auto() && (resolve_percentage_min_max_sizes || !computed_min_size.contains_percentage())) ? specified_cross_min_size(item.box) : 0;
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : CSSPixels::max();
// If we have a definite cross size, this is easy! No need to perform layout, we can just use it as-is.
if (has_definite_cross_size(item.box)) {
@ -1339,7 +1339,7 @@ void FlexFormattingContext::distribute_any_remaining_free_space()
}
break;
case CSS::JustifyContent::Center:
initial_offset = (inner_main_size(flex_container()) - used_main_space) / 2.0;
initial_offset = (inner_main_size(flex_container()) - used_main_space) / 2;
if (is_direction_reverse()) {
initial_offset = inner_main_size(flex_container()) - initial_offset;
}
@ -1357,9 +1357,9 @@ void FlexFormattingContext::distribute_any_remaining_free_space()
if (flex_line.remaining_free_space.has_value())
space_between_items = flex_line.remaining_free_space.value() / number_of_items;
if (is_direction_reverse()) {
initial_offset = inner_main_size(flex_container()) - space_between_items / 2.0;
initial_offset = inner_main_size(flex_container()) - space_between_items / 2;
} else {
initial_offset = space_between_items / 2.0;
initial_offset = space_between_items / 2;
}
break;
case CSS::JustifyContent::SpaceEvenly:
@ -1496,7 +1496,7 @@ void FlexFormattingContext::align_all_flex_items_along_the_cross_axis()
// FIXME: Take better care of margins
for (auto& flex_line : m_flex_lines) {
for (auto& item : flex_line.items) {
CSSPixels half_line_size = flex_line.cross_size / 2.0;
CSSPixels half_line_size = flex_line.cross_size / 2;
switch (alignment_for_item(item.box)) {
case CSS::AlignItems::Baseline:
// FIXME: Implement this
@ -1512,7 +1512,7 @@ void FlexFormattingContext::align_all_flex_items_along_the_cross_axis()
item.cross_offset = half_line_size - item.cross_size.value() - item.margins.cross_after - item.borders.cross_after - item.padding.cross_after;
break;
case CSS::AlignItems::Center:
item.cross_offset = -(item.cross_size.value() / 2.0);
item.cross_offset = -(item.cross_size.value() / 2);
break;
default:
break;
@ -1573,7 +1573,7 @@ void FlexFormattingContext::align_all_flex_lines()
if (is_single_line()) {
// For single-line flex containers, we only need to center the line along the cross axis.
auto& flex_line = m_flex_lines[0];
CSSPixels center_of_line = cross_size_of_flex_container / 2.0;
CSSPixels center_of_line = cross_size_of_flex_container / 2;
for (auto& item : flex_line.items) {
item.cross_offset += center_of_line;
}
@ -1732,15 +1732,15 @@ CSSPixels FlexFormattingContext::calculate_intrinsic_main_size_of_flex_container
CSSPixels result = contribution - outer_flex_base_size;
if (result > 0) {
if (item.box->computed_values().flex_grow() >= 1) {
result /= item.box->computed_values().flex_grow();
result.scale_by(1 / item.box->computed_values().flex_grow());
} else {
result *= item.box->computed_values().flex_grow();
result.scale_by(item.box->computed_values().flex_grow());
}
} else if (result < 0) {
if (item.scaled_flex_shrink_factor == 0)
result = CSSPixels::min();
else
result /= item.scaled_flex_shrink_factor;
result.scale_by(1 / item.scaled_flex_shrink_factor);
}
item.desired_flex_fraction = result.to_double();
@ -1793,13 +1793,13 @@ CSSPixels FlexFormattingContext::calculate_intrinsic_main_size_of_flex_container
product = flex_line.chosen_flex_fraction * static_cast<double>(item.box->computed_values().flex_grow());
else if (item.desired_flex_fraction < 0)
product = flex_line.chosen_flex_fraction * item.scaled_flex_shrink_factor;
auto result = item.flex_base_size + product;
auto result = item.flex_base_size + CSSPixels(product);
auto const& computed_min_size = this->computed_main_min_size(item.box);
auto const& computed_max_size = this->computed_main_max_size(item.box);
auto clamp_min = (!computed_min_size.is_auto() && !computed_min_size.contains_percentage()) ? specified_main_min_size(item.box) : automatic_minimum_size(item);
auto clamp_max = (!computed_max_size.is_none() && !computed_max_size.contains_percentage()) ? specified_main_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_size.is_none() && !computed_max_size.contains_percentage()) ? specified_main_max_size(item.box) : CSSPixels::max();
result = css_clamp(result, clamp_min, clamp_max);
@ -1906,7 +1906,7 @@ CSSPixels FlexFormattingContext::calculate_main_min_content_contribution(FlexIte
}();
auto clamp_min = has_main_min_size(item.box) ? specified_main_min_size(item.box) : automatic_minimum_size(item);
auto clamp_max = has_main_max_size(item.box) ? specified_main_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = has_main_max_size(item.box) ? specified_main_max_size(item.box) : CSSPixels::max();
auto clamped_inner_size = css_clamp(larger_size, clamp_min, clamp_max);
return item.add_main_margin_box_sizes(clamped_inner_size);
@ -1927,7 +1927,7 @@ CSSPixels FlexFormattingContext::calculate_main_max_content_contribution(FlexIte
}();
auto clamp_min = has_main_min_size(item.box) ? specified_main_min_size(item.box) : automatic_minimum_size(item);
auto clamp_max = has_main_max_size(item.box) ? specified_main_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = has_main_max_size(item.box) ? specified_main_max_size(item.box) : CSSPixels::max();
auto clamped_inner_size = css_clamp(larger_size, clamp_min, clamp_max);
return item.add_main_margin_box_sizes(clamped_inner_size);
@ -1959,7 +1959,7 @@ CSSPixels FlexFormattingContext::calculate_cross_min_content_contribution(FlexIt
auto const& computed_max_size = this->computed_cross_max_size(item.box);
auto clamp_min = (!computed_min_size.is_auto() && (resolve_percentage_min_max_sizes || !computed_min_size.contains_percentage())) ? specified_cross_min_size(item.box) : 0;
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : CSSPixels::max();
auto clamped_inner_size = css_clamp(size, clamp_min, clamp_max);
@ -1978,7 +1978,7 @@ CSSPixels FlexFormattingContext::calculate_cross_max_content_contribution(FlexIt
auto const& computed_max_size = this->computed_cross_max_size(item.box);
auto clamp_min = (!computed_min_size.is_auto() && (resolve_percentage_min_max_sizes || !computed_min_size.contains_percentage())) ? specified_cross_min_size(item.box) : 0;
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_size.is_none() && (resolve_percentage_min_max_sizes || !computed_max_size.contains_percentage())) ? specified_cross_max_size(item.box) : CSSPixels::max();
auto clamped_inner_size = css_clamp(size, clamp_min, clamp_max);
@ -1992,7 +1992,7 @@ CSSPixels FlexFormattingContext::calculate_width_to_use_when_determining_intrins
auto const& computed_min_width = box.computed_values().min_width();
auto const& computed_max_width = box.computed_values().max_width();
auto clamp_min = (!computed_min_width.is_auto() && (!computed_min_width.contains_percentage())) ? specified_cross_min_size(box) : 0;
auto clamp_max = (!computed_max_width.is_none() && (!computed_max_width.contains_percentage())) ? specified_cross_max_size(box) : NumericLimits<float>::max();
auto clamp_max = (!computed_max_width.is_none() && (!computed_max_width.contains_percentage())) ? specified_cross_max_size(box) : CSSPixels::max();
CSSPixels width;
if (should_treat_width_as_auto(box, m_available_space_for_items->space) || computed_width.is_fit_content())
@ -2123,8 +2123,8 @@ void FlexFormattingContext::resolve_cross_axis_auto_margins()
if (outer_cross_size < line.cross_size) {
CSSPixels remainder = line.cross_size - outer_cross_size;
if (item.margins.cross_before_is_auto && item.margins.cross_after_is_auto) {
item.margins.cross_before = remainder / 2.0;
item.margins.cross_after = remainder / 2.0;
item.margins.cross_before = remainder / 2;
item.margins.cross_after = remainder / 2;
} else if (item.margins.cross_before_is_auto) {
item.margins.cross_before = remainder;
} else {
@ -2203,13 +2203,13 @@ CSSPixelPoint FlexFormattingContext::calculate_static_position(Box const& box) c
cross_offset = half_line_size - inner_cross_size(box) - cross_margin_after - cross_border_after - cross_padding_after;
break;
case CSS::AlignItems::Center:
cross_offset = -((inner_cross_size(box) + cross_border_before + cross_border_after) / 2.0);
cross_offset = -((inner_cross_size(box) + cross_border_before + cross_border_after) / 2);
break;
default:
break;
}
cross_offset += inner_cross_size(flex_container()) / 2.0;
cross_offset += inner_cross_size(flex_container()) / 2;
// The main-axis edges of the static-position rectangle are where the margin edges of the child
// would be positioned if it were the sole flex item in the flex container,
@ -2236,7 +2236,7 @@ CSSPixelPoint FlexFormattingContext::calculate_static_position(Box const& box) c
case CSS::JustifyContent::SpaceAround:
case CSS::JustifyContent::SpaceEvenly:
pack_from_end = false;
main_offset = (inner_main_size(flex_container()) - inner_main_size(box) - main_border_before - main_border_after) / 2.0;
main_offset = (inner_main_size(flex_container()) - inner_main_size(box) - main_border_before - main_border_after) / 2;
break;
}

View file

@ -405,7 +405,7 @@ CSSPixels FormattingContext::tentative_width_for_replaced_element(Box const& box
// (used height) * (intrinsic ratio)
if ((computed_height.is_auto() && computed_width.is_auto() && !box.has_natural_width() && box.has_natural_height() && box.has_preferred_aspect_ratio())
|| (computed_width.is_auto() && !computed_height.is_auto() && box.has_preferred_aspect_ratio())) {
return compute_height_for_replaced_element(box, available_space) * static_cast<double>(box.preferred_aspect_ratio().value());
return compute_height_for_replaced_element(box, available_space).scaled(static_cast<double>(box.preferred_aspect_ratio().value()));
}
// If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width,
@ -500,7 +500,7 @@ CSSPixels FormattingContext::tentative_height_for_replaced_element(Box const& bo
//
// (used width) / (intrinsic ratio)
if (computed_height.is_auto() && box.has_preferred_aspect_ratio())
return m_state.get(box).content_width() / static_cast<double>(box.preferred_aspect_ratio().value());
return CSSPixels(m_state.get(box).content_width() / static_cast<double>(box.preferred_aspect_ratio().value()));
// Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'.
if (computed_height.is_auto() && box.has_natural_height())
@ -1051,8 +1051,8 @@ CSSPixelPoint FormattingContext::calculate_static_position(Box const& box) const
// The purpose of this function is to calculate the approximate position that `box`
// would have had if it were position:static.
CSSPixels x = 0.0f;
CSSPixels y = 0.0f;
CSSPixels x = 0;
CSSPixels y = 0;
VERIFY(box.parent());
if (box.parent()->children_are_inline()) {
@ -1403,7 +1403,7 @@ CSSPixels FormattingContext::calculate_min_content_height(Layout::Box const& box
CSSPixels FormattingContext::calculate_max_content_height(Layout::Box const& box, CSSPixels width) const
{
if (box.has_preferred_aspect_ratio())
return width / static_cast<double>(*box.preferred_aspect_ratio());
return CSSPixels(width / static_cast<double>(*box.preferred_aspect_ratio()));
if (box.has_natural_height())
return *box.natural_height();
@ -1711,10 +1711,10 @@ CSSPixels FormattingContext::box_baseline(Box const& box) const
return box_state.content_height() + box_state.margin_box_top();
case CSS::VerticalAlign::TextTop:
// TextTop: Align the top of the box with the top of the parent's content area (see 10.6.1).
return box.computed_values().font_size();
return CSSPixels(box.computed_values().font_size());
case CSS::VerticalAlign::TextBottom:
// TextTop: Align the bottom of the box with the bottom of the parent's content area (see 10.6.1).
return box_state.content_height() - (box.containing_block()->font().pixel_metrics().descent * 2);
return box_state.content_height() - CSSPixels(box.containing_block()->font().pixel_metrics().descent * 2);
default:
break;
}

View file

@ -1245,7 +1245,7 @@ void GridFormattingContext::expand_flexible_tracks(AvailableSpace const& availab
for (auto& track : tracks) {
if (track.max_track_sizing_function.is_flexible_length()) {
if (track.max_track_sizing_function.flex_factor() > 1) {
result = max(result, track.base_size / track.max_track_sizing_function.flex_factor());
result = max(result, CSSPixels(track.base_size / track.max_track_sizing_function.flex_factor()));
} else {
result = max(result, track.base_size);
}
@ -1273,8 +1273,8 @@ void GridFormattingContext::expand_flexible_tracks(AvailableSpace const& availab
// For each flexible track, if the product of the used flex fraction and the tracks flex factor is greater than
// the tracks base size, set its base size to that product.
for (auto& track : tracks_and_gaps) {
if (track.max_track_sizing_function.flex_factor() * flex_fraction > track.base_size) {
track.base_size = track.max_track_sizing_function.flex_factor() * flex_fraction;
if (flex_fraction.scaled(track.max_track_sizing_function.flex_factor()) > track.base_size) {
track.base_size = flex_fraction.scaled(track.max_track_sizing_function.flex_factor());
}
}
}

View file

@ -34,11 +34,11 @@ void ImageBox::prepare_for_replaced_layout()
CSSPixels alt_text_width = 0;
if (!m_cached_alt_text_width.has_value())
m_cached_alt_text_width = font.width(alt);
m_cached_alt_text_width = CSSPixels(font.width(alt));
alt_text_width = m_cached_alt_text_width.value();
set_natural_width(alt_text_width + 16);
set_natural_height(font.pixel_size() + 16);
set_natural_height(CSSPixels(font.pixel_size()) + 16);
}
if (!has_natural_width() && !has_natural_height()) {

View file

@ -180,7 +180,7 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
m_text_node_context->is_last_chunk = true;
auto& chunk = chunk_opt.value();
CSSPixels chunk_width = text_node.font().width(chunk.view) + text_node.font().glyph_spacing();
CSSPixels chunk_width = CSSPixels(text_node.font().width(chunk.view) + text_node.font().glyph_spacing());
if (m_text_node_context->do_respect_linebreaks && chunk.has_breaking_newline) {
return Item {

View file

@ -386,7 +386,7 @@ void LayoutState::UsedValues::set_node(NodeWithStyleAndBoxModelMetrics& node, Us
if (size.is_percentage()) {
if (containing_block_has_definite_size) {
auto containing_block_size = width ? containing_block_used_values->content_width() : containing_block_used_values->content_height();
resolved_definite_size = adjust_for_box_sizing(containing_block_size * static_cast<double>(size.percentage().as_fraction()), size, width);
resolved_definite_size = adjust_for_box_sizing(containing_block_size.scaled(size.percentage().as_fraction()), size, width);
return true;
}
return false;

View file

@ -25,7 +25,7 @@ void LineBox::add_fragment(Node const& layout_node, int start, int length, CSSPi
m_fragments.last().set_width(m_fragments.last().width() + content_width);
} else {
CSSPixels x_offset = leading_margin + leading_size + m_width;
CSSPixels y_offset = 0.0f;
CSSPixels y_offset = 0;
m_fragments.append(LineBoxFragment { layout_node, start, length, CSSPixelPoint(x_offset, y_offset), CSSPixelSize(content_width, content_height), border_box_top, border_box_bottom });
}
m_width += leading_margin + leading_size + content_width + trailing_size + trailing_margin;

View file

@ -51,7 +51,7 @@ int LineBoxFragment::text_index_at(CSSPixels x) const
Utf8View view(text());
CSSPixels relative_x = x - absolute_x();
float glyph_spacing = font.glyph_spacing();
CSSPixels glyph_spacing = CSSPixels(font.glyph_spacing());
if (relative_x < 0)
return 0;
@ -59,9 +59,9 @@ int LineBoxFragment::text_index_at(CSSPixels x) const
CSSPixels width_so_far = 0;
for (auto it = view.begin(); it != view.end(); ++it) {
auto previous_it = it;
CSSPixels glyph_width = font.glyph_or_emoji_width(it);
CSSPixels glyph_width = CSSPixels(font.glyph_or_emoji_width(it));
if ((width_so_far + (glyph_width + glyph_spacing) / 2) > relative_x)
if ((width_so_far + glyph_width + glyph_spacing / 2) > relative_x)
return m_start + view.byte_offset_of(previous_it);
width_so_far += glyph_width + glyph_spacing;
@ -105,8 +105,8 @@ CSSPixelRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
auto selection_start_in_this_fragment = max(0, range->start_offset() - m_start);
auto selection_end_in_this_fragment = min(m_length, range->end_offset() - m_start);
auto pixel_distance_to_first_selected_character = font.width(text.substring_view(0, selection_start_in_this_fragment));
auto pixel_width_of_selection = font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment)) + 1;
auto pixel_distance_to_first_selected_character = CSSPixels(font.width(text.substring_view(0, selection_start_in_this_fragment)));
auto pixel_width_of_selection = CSSPixels(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
auto rect = absolute_rect();
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
@ -121,8 +121,8 @@ CSSPixelRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
auto selection_start_in_this_fragment = max(0, range->start_offset() - m_start);
auto selection_end_in_this_fragment = m_length;
auto pixel_distance_to_first_selected_character = font.width(text.substring_view(0, selection_start_in_this_fragment));
auto pixel_width_of_selection = font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment)) + 1;
auto pixel_distance_to_first_selected_character = CSSPixels(font.width(text.substring_view(0, selection_start_in_this_fragment)));
auto pixel_width_of_selection = CSSPixels(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
auto rect = absolute_rect();
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);
@ -137,8 +137,8 @@ CSSPixelRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
auto selection_start_in_this_fragment = 0;
auto selection_end_in_this_fragment = min(range->end_offset() - m_start, m_length);
auto pixel_distance_to_first_selected_character = font.width(text.substring_view(0, selection_start_in_this_fragment));
auto pixel_width_of_selection = font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment)) + 1;
auto pixel_distance_to_first_selected_character = CSSPixels(font.width(text.substring_view(0, selection_start_in_this_fragment)));
auto pixel_width_of_selection = CSSPixels(font.width(text.substring_view(selection_start_in_this_fragment, selection_end_in_this_fragment - selection_start_in_this_fragment))) + 1;
auto rect = absolute_rect();
rect.set_x(rect.x() + pixel_distance_to_first_selected_character);

View file

@ -195,7 +195,7 @@ void LineBuilder::update_last_line()
auto& font = m_context.containing_block().font();
auto const line_height = m_context.containing_block().line_height();
auto const font_metrics = font.pixel_metrics();
auto const typographic_height = font_metrics.ascent + font_metrics.descent;
auto const typographic_height = CSSPixels(font_metrics.ascent + font_metrics.descent);
auto const leading = line_height - typographic_height;
auto const half_leading = leading / 2;
return CSSPixels(font_metrics.ascent) + half_leading;
@ -230,7 +230,7 @@ void LineBuilder::update_last_line()
if (length_percentage->is_length())
fragment_baseline += length_percentage->length().to_px(fragment.layout_node());
else if (length_percentage->is_percentage())
fragment_baseline += length_percentage->percentage().as_fraction() * line_height.to_double();
fragment_baseline += line_height.scaled(length_percentage->percentage().as_fraction());
}
line_box_baseline = max(line_box_baseline, fragment_baseline);
@ -284,7 +284,7 @@ void LineBuilder::update_last_line()
auto vertical_align_amount = length_percentage->length().to_px(fragment.layout_node());
new_fragment_y = y_value_for_alignment(CSS::VerticalAlign::Baseline) - vertical_align_amount;
} else if (length_percentage->is_percentage()) {
auto vertical_align_amount = length_percentage->percentage().as_fraction() * m_context.containing_block().line_height().to_double();
auto vertical_align_amount = m_context.containing_block().line_height().scaled(length_percentage->percentage().as_fraction());
new_fragment_y = y_value_for_alignment(CSS::VerticalAlign::Baseline) - vertical_align_amount;
}
}
@ -302,17 +302,17 @@ void LineBuilder::update_last_line()
bottom_of_inline_box = (fragment.offset().y() + fragment_box_state.content_height() + fragment_box_state.margin_box_bottom());
} else {
auto font_metrics = fragment.layout_node().font().pixel_metrics();
auto typographic_height = font_metrics.ascent + font_metrics.descent;
auto typographic_height = CSSPixels(font_metrics.ascent + font_metrics.descent);
auto leading = fragment.layout_node().line_height() - typographic_height;
auto half_leading = leading / 2;
top_of_inline_box = (fragment.offset().y() + fragment.baseline() - font_metrics.ascent - half_leading);
bottom_of_inline_box = (fragment.offset().y() + fragment.baseline() + font_metrics.descent + half_leading);
top_of_inline_box = (fragment.offset().y() + fragment.baseline() - CSSPixels(font_metrics.ascent) - half_leading);
bottom_of_inline_box = (fragment.offset().y() + fragment.baseline() + CSSPixels(font_metrics.descent) + half_leading);
}
if (auto const* length_percentage = fragment.layout_node().computed_values().vertical_align().get_pointer<CSS::LengthPercentage>()) {
if (length_percentage->is_length())
bottom_of_inline_box += length_percentage->length().to_px(fragment.layout_node());
else if (length_percentage->is_percentage())
bottom_of_inline_box += length_percentage->percentage().as_fraction() * m_context.containing_block().line_height().to_double();
bottom_of_inline_box += m_context.containing_block().line_height().scaled(length_percentage->percentage().as_fraction());
}
}

View file

@ -300,11 +300,11 @@ static CSSPixels snap_a_length_as_a_border_width(double device_pixels_per_css_pi
// 3. If len is greater than zero, but less than 1 device pixel, round len up to 1 device pixel.
if (device_pixels > 0 && device_pixels < 1)
return 1 / device_pixels_per_css_pixel;
return CSSPixels(1 / device_pixels_per_css_pixel);
// 4. If len is greater than 1 device pixel, round it down to the nearest integer number of device pixels.
if (device_pixels > 1)
return floor(device_pixels) / device_pixels_per_css_pixel;
return CSSPixels(floor(device_pixels) / device_pixels_per_css_pixel);
return length;
}
@ -684,11 +684,11 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
// https://www.w3.org/TR/css-backgrounds-3/#valdef-line-width-thin
switch (value->to_identifier()) {
case CSS::ValueID::Thin:
return 1.0;
return 1;
case CSS::ValueID::Medium:
return 3.0;
return 3;
case CSS::ValueID::Thick:
return 5.0;
return 5;
default:
VERIFY_NOT_REACHED();
}
@ -742,7 +742,7 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
// FIXME: Converting to pixels isn't really correct - values should be in "user units"
// https://svgwg.org/svg2-draft/coords.html#TermUserUnits
if (stroke_width->is_number())
computed_values.set_stroke_width(CSS::Length::make_px(stroke_width->as_number().number()));
computed_values.set_stroke_width(CSS::Length::make_px(CSSPixels(stroke_width->as_number().number())));
else if (stroke_width->is_length())
computed_values.set_stroke_width(stroke_width->as_length().length());
else if (stroke_width->is_percentage())

View file

@ -86,13 +86,13 @@ static ViewBoxTransform scale_and_align_viewbox_content(SVG::PreserveAspectRatio
case SVG::PreserveAspectRatio::Align::xMidYMid:
case SVG::PreserveAspectRatio::Align::xMidYMax:
// Align the midpoint X value of the element's viewBox with the midpoint X value of the SVG viewport.
viewbox_transform.offset.translate_by((svg_box_state.content_width() - (view_box.width * viewbox_transform.scale_factor)) / 2, 0);
viewbox_transform.offset.translate_by((svg_box_state.content_width() - CSSPixels(view_box.width * viewbox_transform.scale_factor)) / 2, 0);
break;
case SVG::PreserveAspectRatio::Align::xMaxYMin:
case SVG::PreserveAspectRatio::Align::xMaxYMid:
case SVG::PreserveAspectRatio::Align::xMaxYMax:
// Align the <min-x>+<width> of the element's viewBox with the maximum X value of the SVG viewport.
viewbox_transform.offset.translate_by((svg_box_state.content_width() - (view_box.width * viewbox_transform.scale_factor)), 0);
viewbox_transform.offset.translate_by((svg_box_state.content_width() - CSSPixels(view_box.width * viewbox_transform.scale_factor)), 0);
break;
default:
VERIFY_NOT_REACHED();
@ -117,13 +117,13 @@ static ViewBoxTransform scale_and_align_viewbox_content(SVG::PreserveAspectRatio
case SVG::PreserveAspectRatio::Align::xMidYMid:
case SVG::PreserveAspectRatio::Align::xMaxYMid:
// Align the midpoint Y value of the element's viewBox with the midpoint Y value of the SVG viewport.
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - (view_box.height * viewbox_transform.scale_factor)) / 2);
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - CSSPixels(view_box.height * viewbox_transform.scale_factor)) / 2);
break;
case SVG::PreserveAspectRatio::Align::xMinYMax:
case SVG::PreserveAspectRatio::Align::xMidYMax:
case SVG::PreserveAspectRatio::Align::xMaxYMax:
// Align the <min-y>+<height> of the element's viewBox with the maximum Y value of the SVG viewport.
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - (view_box.height * viewbox_transform.scale_factor)));
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - CSSPixels(view_box.height * viewbox_transform.scale_factor)));
break;
default:
VERIFY_NOT_REACHED();
@ -197,7 +197,7 @@ void SVGFormattingContext::run(Box const& box, LayoutMode layout_mode, Available
// Stroke increases the path's size by stroke_width/2 per side.
auto path_bounding_box = path_transform.map(path.bounding_box()).to_type<CSSPixels>();
CSSPixels stroke_width = static_cast<double>(geometry_box.dom_node().visible_stroke_width()) * viewbox_scale;
CSSPixels stroke_width = CSSPixels(static_cast<double>(geometry_box.dom_node().visible_stroke_width()) * viewbox_scale);
path_bounding_box.inflate(stroke_width, stroke_width);
geometry_box_state.set_content_offset(path_bounding_box.top_left());
geometry_box_state.set_content_width(path_bounding_box.width());

View file

@ -265,11 +265,11 @@ void TableFormattingContext::compute_intrinsic_percentage(size_t max_cell_span)
auto cell_start_rc_index = cell_index<RowOrColumn>(cell);
auto cell_end_rc_index = cell_start_rc_index + cell_span_value;
// 1. Start with the percentage contribution of the cell.
CSSPixels cell_contribution = cell_percentage_contribution<RowOrColumn>(cell);
CSSPixels cell_contribution = CSSPixels(cell_percentage_contribution<RowOrColumn>(cell));
// 2. Subtract the intrinsic percentage width of the column based on cells of span up to N-1 of all columns
// that the cell spans. If this gives a negative result, change it to 0%.
for (auto rc_index = cell_start_rc_index; rc_index < cell_end_rc_index; rc_index++) {
cell_contribution -= rows_or_columns[rc_index].intrinsic_percentage;
cell_contribution -= CSSPixels(rows_or_columns[rc_index].intrinsic_percentage);
cell_contribution = max(cell_contribution, 0);
}
// Compute the sum of the non-spanning max-content sizes of all rows / columns spanned by the cell that have an intrinsic percentage
@ -297,7 +297,7 @@ void TableFormattingContext::compute_intrinsic_percentage(size_t max_cell_span)
// columns spanned by the cell that have an intrinsic percentage width of the column based on cells of span up to N-1 equal to 0%.
CSSPixels ajusted_cell_contribution;
if (width_sum_of_columns_with_zero_intrinsic_percentage != 0) {
ajusted_cell_contribution = cell_contribution * rows_or_columns[rc_index].max_size / static_cast<double>(width_sum_of_columns_with_zero_intrinsic_percentage);
ajusted_cell_contribution = cell_contribution.scaled(rows_or_columns[rc_index].max_size / static_cast<double>(width_sum_of_columns_with_zero_intrinsic_percentage));
} else {
// However, if this ratio is undefined because the denominator is zero, instead use the 1 divided by the number of columns
// spanned by the cell that have an intrinsic percentage width of the column based on cells of span up to N-1 equal to zero.
@ -380,12 +380,12 @@ void TableFormattingContext::compute_table_measures()
auto clamped_diff_to_baseline_min = min(
max(cell_min_size<RowOrColumn>(cell) - baseline_min_content_size - baseline_border_spacing, 0),
baseline_max_content_size - baseline_min_content_size);
cell_min_contribution += normalized_max_min_diff * clamped_diff_to_baseline_min;
cell_min_contribution += CSSPixels(normalized_max_min_diff * clamped_diff_to_baseline_min);
// the product of:
// - the ratio of the max-content size based on cells of span up to N-1 of the column to the baseline max-content size
// - the outer min-content size of the cell minus the baseline max-content size and baseline border spacing, or 0 if this is negative
if (baseline_max_content_size != 0) {
cell_min_contribution += (rows_or_columns[rc_index].max_size / static_cast<double>(baseline_max_content_size))
cell_min_contribution += CSSPixels(rows_or_columns[rc_index].max_size / static_cast<double>(baseline_max_content_size))
* max(CSSPixels(0), cell_min_size<RowOrColumn>(cell) - baseline_max_content_size - baseline_border_spacing);
}
@ -396,7 +396,7 @@ void TableFormattingContext::compute_table_measures()
// - the ratio of the max-content size based on cells of span up to N-1 of the column to the baseline max-content size
// - the outer max-content size of the cell minus the baseline max-content size and the baseline border spacing, or 0 if this is negative
if (baseline_max_content_size != 0) {
cell_max_contribution += (rows_or_columns[rc_index].max_size / static_cast<double>(baseline_max_content_size))
cell_max_contribution += CSSPixels(rows_or_columns[rc_index].max_size / static_cast<double>(baseline_max_content_size))
* max(CSSPixels(0), cell_max_size<RowOrColumn>(cell) - baseline_max_content_size - baseline_border_spacing);
}
cell_min_contributions_by_rc_index[rc_index].append(cell_min_contribution);
@ -461,7 +461,7 @@ void TableFormattingContext::compute_table_width()
// The row/column-grid width minimum (GRIDMIN) width is the sum of the min-content width
// of all the columns plus cell spacing or borders.
CSSPixels grid_min = 0.0f;
CSSPixels grid_min = 0;
for (auto& column : m_columns) {
grid_min += column.min_size;
}
@ -469,7 +469,7 @@ void TableFormattingContext::compute_table_width()
// The row/column-grid width maximum (GRIDMAX) width is the sum of the max-content width
// of all the columns plus cell spacing or borders.
CSSPixels grid_max = 0.0f;
CSSPixels grid_max = 0;
for (auto& column : m_columns) {
grid_max += column.max_size;
}
@ -496,7 +496,7 @@ void TableFormattingContext::compute_table_width()
for (auto& cell : m_cells) {
auto const& cell_width = cell.box->computed_values().width();
if (cell_width.is_percentage()) {
adjusted_used_width = ceil(100 / cell_width.percentage().value() * cell.outer_max_width.to_double());
adjusted_used_width = CSSPixels(ceil(100 / cell_width.percentage().value() * cell.outer_max_width.to_double()));
if (width_of_table_containing_block.is_definite())
used_width = min(max(used_width, adjusted_used_width), width_of_table_containing_block.to_px_or_zero());
else
@ -555,7 +555,7 @@ void TableFormattingContext::assign_columns_width_linear_combination(Vector<CSSP
auto candidate_weight = (available_width - columns_total_used_width) / static_cast<double>(columns_total_candidate_width - columns_total_used_width);
for (size_t i = 0; i < m_columns.size(); ++i) {
auto& column = m_columns[i];
column.used_width = candidate_weight * candidate_widths[i] + (1 - candidate_weight) * column.used_width;
column.used_width = CSSPixels(candidate_weight * candidate_widths[i] + (1 - candidate_weight) * column.used_width);
}
}
@ -576,7 +576,7 @@ bool TableFormattingContext::distribute_excess_width_proportionally_to_base_widt
VERIFY(total_base_width > 0);
for (auto& column : m_columns) {
if (column_filter(column)) {
column.used_width += excess_width * base_width_getter(column) / static_cast<double>(total_base_width);
column.used_width += CSSPixels(excess_width * base_width_getter(column) / static_cast<double>(total_base_width));
}
}
return true;
@ -618,7 +618,7 @@ bool TableFormattingContext::distribute_excess_width_by_intrinsic_percentage(CSS
}
for (auto& column : m_columns) {
if (column_filter(column)) {
column.used_width += excess_width * column.intrinsic_percentage / total_percentage_width;
column.used_width += CSSPixels(excess_width * column.intrinsic_percentage / total_percentage_width);
}
}
return true;
@ -660,7 +660,7 @@ void TableFormattingContext::distribute_width_to_columns()
for (size_t i = 0; i < m_columns.size(); ++i) {
auto& column = m_columns[i];
if (column.has_intrinsic_percentage) {
candidate_widths[i] = max(column.min_size, column.intrinsic_percentage / 100 * available_width);
candidate_widths[i] = max(column.min_size, CSSPixels(column.intrinsic_percentage / 100 * available_width));
}
}
@ -990,7 +990,7 @@ void TableFormattingContext::distribute_height_to_rows()
for (auto& row : m_rows) {
auto weight = row.reference_height / static_cast<double>(sum_reference_height);
auto final_height = m_table_height * weight;
row.final_height = final_height;
row.final_height = CSSPixels(final_height);
}
} else if (rows_with_auto_height.size() > 0) {
// Else, if the table owns any “auto-height” row (a row whose size is only determined by its content size and
@ -1029,7 +1029,7 @@ void TableFormattingContext::position_row_boxes()
for (size_t y = 0; y < m_rows.size(); y++) {
auto& row = m_rows[y];
auto& row_state = m_state.get_mutable(row.box);
CSSPixels row_width = 0.0f;
CSSPixels row_width = 0;
for (auto& column : m_columns) {
row_width += column.used_width;
}
@ -1044,8 +1044,8 @@ void TableFormattingContext::position_row_boxes()
CSSPixels row_group_top_offset = table_state.border_top + table_state.padding_top;
CSSPixels row_group_left_offset = table_state.border_left + table_state.padding_left;
TableGrid::for_each_child_box_matching(table_box(), TableGrid::is_table_row_group, [&](auto& row_group_box) {
CSSPixels row_group_height = 0.0f;
CSSPixels row_group_width = 0.0f;
CSSPixels row_group_height = 0;
CSSPixels row_group_width = 0;
auto& row_group_box_state = m_state.get_mutable(row_group_box);
row_group_box_state.set_content_x(row_group_left_offset);

View file

@ -38,10 +38,10 @@ HTML::HTMLVideoElement const& VideoBox::dom_node() const
void VideoBox::prepare_for_replaced_layout()
{
auto width = static_cast<float>(dom_node().video_width());
set_natural_width(width);
set_natural_width(CSSPixels(width));
auto height = static_cast<float>(dom_node().video_height());
set_natural_height(height);
set_natural_height(CSSPixels(height));
if (width != 0 && height != 0)
set_natural_aspect_ratio(width / height);

View file

@ -161,14 +161,14 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
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);
image_rect.set_size(natural_image_width.scaled(ratio), natural_image_height.scaled(ratio));
break;
}
case CSS::BackgroundSize::Cover: {
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);
image_rect.set_size(natural_image_width.scaled(ratio), natural_image_height.scaled(ratio));
break;
}
case CSS::BackgroundSize::LengthPercentage: {
@ -263,7 +263,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
repeat_x = false;
} else {
auto space = fmod(background_positioning_area.width().to_double(), image_rect.width().to_double());
x_step = image_rect.width() + (space / static_cast<double>(whole_images - 1));
x_step = image_rect.width() + CSSPixels(space / static_cast<double>(whole_images - 1));
repeat_x = true;
}
break;
@ -294,7 +294,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
repeat_y = false;
} else {
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));
y_step = image_rect.height() + CSSPixels(static_cast<double>(space) / static_cast<double>(whole_images - 1));
repeat_y = true;
}
break;

View file

@ -117,7 +117,7 @@ LinearGradientData resolve_linear_gradient_data(Layout::NodeWithStyleAndBoxModel
auto resolved_color_stops = resolve_color_stop_positions(
node, linear_gradient.color_stop_list(), [&](auto const& length_percentage) {
return length_percentage.to_px(node, gradient_length_px).to_float() / static_cast<float>(gradient_length_px);
return length_percentage.to_px(node, CSSPixels(gradient_length_px)).to_float() / static_cast<float>(gradient_length_px);
},
linear_gradient.is_repeating());

View file

@ -39,7 +39,7 @@ void MarkerPaintable::paint(PaintContext& context, PaintPhase phase) const
CSSPixelRect enclosing = absolute_rect().to_rounded<CSSPixels>();
auto device_enclosing = context.enclosing_device_rect(enclosing);
CSSPixels marker_width = enclosing.height() / 2.0;
CSSPixels marker_width = enclosing.height() / 2;
if (auto const* list_style_image = layout_box().list_style_image()) {
CSSPixelRect image_rect {

View file

@ -96,7 +96,7 @@ DevicePixelSize PaintContext::rounded_device_size(CSSPixelSize size) const
CSSPixels PaintContext::scale_to_css_pixels(DevicePixels device_pixels) const
{
return device_pixels.value() / m_device_pixels_per_css_pixel;
return CSSPixels(device_pixels.value() / m_device_pixels_per_css_pixel);
}
CSSPixelPoint PaintContext::scale_to_css_point(DevicePixelPoint point) const

View file

@ -258,8 +258,8 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
auto size_text_rect = border_rect;
size_text_rect.set_y(border_rect.y() + border_rect.height());
size_text_rect.set_top(size_text_rect.top());
size_text_rect.set_width((float)font.width(size_text) + 4);
size_text_rect.set_height(font.pixel_size() + 4);
size_text_rect.set_width(CSSPixels(font.width(size_text)) + 4);
size_text_rect.set_height(CSSPixels(font.pixel_size()) + 4);
auto size_text_device_rect = context.enclosing_device_rect(size_text_rect).to_type<int>();
context.painter().fill_rect(size_text_device_rect, context.palette().color(Gfx::ColorRole::Tooltip));
context.painter().draw_rect(size_text_device_rect, context.palette().threed_shadow1());
@ -503,7 +503,7 @@ static void paint_cursor_if_needed(PaintContext& context, Layout::TextNode const
auto fragment_rect = fragment.absolute_rect();
CSSPixelRect cursor_rect {
fragment_rect.x() + text_node.font().width(fragment.text().substring_view(0, text_node.browsing_context().cursor_position().offset() - fragment.start())),
fragment_rect.x() + CSSPixels(text_node.font().width(fragment.text().substring_view(0, text_node.browsing_context().cursor_position().offset() - fragment.start()))),
fragment_rect.top(),
1,
fragment_rect.height()
@ -518,7 +518,7 @@ static void paint_text_decoration(PaintContext& context, Gfx::Painter& painter,
{
auto& font = fragment.layout_node().font();
auto fragment_box = fragment.absolute_rect();
CSSPixels glyph_height = font.pixel_size();
CSSPixels glyph_height = CSSPixels(font.pixel_size());
auto baseline = fragment_box.height() / 2 - (glyph_height + 4) / 2 + glyph_height;
auto line_color = text_node.computed_values().text_decoration_color();
@ -526,9 +526,9 @@ 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.1, 1.);
return max(glyph_height.scaled(0.1), 1);
return computed_thickness.to_px(text_node).to_double();
return computed_thickness.to_px(text_node);
}();
auto device_line_thickness = context.rounded_device_pixels(css_line_thickness);
@ -550,8 +550,8 @@ static void paint_text_decoration(PaintContext& context, Gfx::Painter& painter,
break;
case CSS::TextDecorationLine::LineThrough: {
auto x_height = font.x_height();
line_start_point = context.rounded_device_point(fragment_box.top_left().translated(0, baseline - x_height * 0.5f));
line_end_point = context.rounded_device_point(fragment_box.top_right().translated(-1, baseline - x_height * 0.5f));
line_start_point = context.rounded_device_point(fragment_box.top_left().translated(0, baseline - x_height * CSSPixels(0.5f)));
line_end_point = context.rounded_device_point(fragment_box.top_right().translated(-1, baseline - x_height * CSSPixels(0.5f)));
break;
}
case CSS::TextDecorationLine::Blink:

View file

@ -448,12 +448,12 @@ void StackingContext::paint(PaintContext& context) const
// to the size of the source (which could add some artefacts, though just scaling the bitmap already does that).
// We need to copy the background at the destination because a bunch of our rendering effects now rely on
// being able to sample the painter (see border radii, shadows, filters, etc).
CSSPixelPoint destination_clipped_fixup {};
Gfx::FloatPoint destination_clipped_fixup {};
auto try_get_scaled_destination_bitmap = [&]() -> ErrorOr<NonnullRefPtr<Gfx::Bitmap>> {
Gfx::IntRect actual_destination_rect;
auto bitmap = TRY(context.painter().get_region_bitmap(destination_rect, Gfx::BitmapFormat::BGRA8888, actual_destination_rect));
// get_region_bitmap() may clip to a smaller region if the requested rect goes outside the painter, so we need to account for that.
destination_clipped_fixup = CSSPixelPoint { destination_rect.location() - actual_destination_rect.location() };
destination_clipped_fixup = Gfx::FloatPoint { destination_rect.location() - actual_destination_rect.location() };
destination_rect = actual_destination_rect;
if (source_rect.size() != transformed_destination_rect.size()) {
auto sx = static_cast<float>(source_rect.width()) / transformed_destination_rect.width();
@ -469,7 +469,7 @@ void StackingContext::paint(PaintContext& context) const
return;
auto bitmap = bitmap_or_error.release_value_but_fixme_should_propagate_errors();
Gfx::Painter painter(bitmap);
painter.translate(context.rounded_device_point(-paintable_box().absolute_paint_rect().location() + destination_clipped_fixup).to_type<int>());
painter.translate(context.rounded_device_point(-paintable_box().absolute_paint_rect().location() + destination_clipped_fixup.to_type<CSSPixels>()).to_type<int>());
auto paint_context = context.clone(painter);
paint_internal(paint_context);

View file

@ -9,6 +9,7 @@
#pragma once
#include <AK/Concepts.h>
#include <AK/Debug.h>
#include <AK/DistinctNumeric.h>
#include <AK/Math.h>
#include <AK/Traits.h>
@ -74,16 +75,16 @@ public:
m_value = static_cast<int>(value) << fractional_bits;
}
CSSPixels(float value)
{
if (!isnan(value))
m_value = AK::clamp_to_int(value * fixed_point_denominator);
}
CSSPixels(double value)
template<FloatingPoint F>
explicit CSSPixels(F value)
{
if (!isnan(value))
m_value = AK::clamp_to_int(value * fixed_point_denominator);
// Note: The resolution of CSSPixels is 0.015625, so care must be taken when converting
// floats/doubles to CSSPixels as small values (such as scale factors) can underflow to zero,
// or otherwise produce inaccurate results (when scaled back up).
if (m_value == 0 && value != 0)
dbgln_if(LIBWEB_CSS_DEBUG, "CSSPixels: Conversion from float or double underflowed to zero");
}
template<Unsigned U>
@ -217,6 +218,32 @@ public:
constexpr CSSPixels abs() const { return from_raw(::abs(m_value)); }
CSSPixels& scale_by(float value)
{
*this = CSSPixels(to_float() * value);
return *this;
}
CSSPixels& scale_by(double value)
{
*this = CSSPixels(to_double() * value);
return *this;
}
CSSPixels scaled(float value) const
{
auto result = *this;
result.scale_by(value);
return result;
}
CSSPixels scaled(double value) const
{
auto result = *this;
result.scale_by(value);
return result;
}
private:
i32 m_value { 0 };
};

View file

@ -227,7 +227,7 @@ Optional<float> SVGGraphicsElement::stroke_width() const
viewport_height = svg_svg_layout_node->computed_values().height().to_px(*svg_svg_layout_node, 0);
}
}
auto scaled_viewport_size = (viewport_width + viewport_height) * 0.5;
auto scaled_viewport_size = (viewport_width + viewport_height) * CSSPixels(0.5);
return width.to_px(*layout_node(), scaled_viewport_size).to_double();
}