ソースを参照

LibWeb: Convert Paintable coordinates to new pixel units

This fixes a few sizing issues too. The page size is now correct in most
cases! \o/

We get to remove some of the `to_type<>()` shenanigans, though it
reappears in some other places.
Sam Atkins 2 年 前
コミット
ab49dbf137
39 ファイル変更200 行追加179 行削除
  1. 4 4
      Userland/Libraries/LibWeb/DOM/Element.cpp
  2. 1 1
      Userland/Libraries/LibWeb/Dump.cpp
  3. 2 2
      Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
  4. 2 2
      Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp
  5. 1 1
      Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp
  6. 3 2
      Userland/Libraries/LibWeb/Layout/Box.cpp
  7. 1 1
      Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
  8. 2 1
      Userland/Libraries/LibWeb/Layout/FrameBox.cpp
  9. 1 1
      Userland/Libraries/LibWeb/Layout/ImageBox.cpp
  10. 1 1
      Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp
  11. 2 2
      Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp
  12. 5 5
      Userland/Libraries/LibWeb/Layout/Label.cpp
  13. 1 1
      Userland/Libraries/LibWeb/Layout/LayoutState.cpp
  14. 2 2
      Userland/Libraries/LibWeb/Layout/LineBox.cpp
  15. 7 7
      Userland/Libraries/LibWeb/Layout/LineBoxFragment.cpp
  16. 32 23
      Userland/Libraries/LibWeb/Layout/LineBoxFragment.h
  17. 8 8
      Userland/Libraries/LibWeb/Layout/LineBuilder.cpp
  18. 3 3
      Userland/Libraries/LibWeb/Layout/Node.cpp
  19. 2 2
      Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp
  20. 6 4
      Userland/Libraries/LibWeb/Painting/ButtonPaintable.cpp
  21. 1 1
      Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp
  22. 1 1
      Userland/Libraries/LibWeb/Painting/CheckBoxPaintable.cpp
  23. 4 3
      Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp
  24. 5 5
      Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp
  25. 2 2
      Userland/Libraries/LibWeb/Painting/LabelablePaintable.cpp
  26. 2 1
      Userland/Libraries/LibWeb/Painting/MarkerPaintable.cpp
  27. 4 3
      Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.cpp
  28. 43 41
      Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
  29. 29 29
      Userland/Libraries/LibWeb/Painting/PaintableBox.h
  30. 7 4
      Userland/Libraries/LibWeb/Painting/ProgressPaintable.cpp
  31. 1 1
      Userland/Libraries/LibWeb/Painting/RadioButtonPaintable.cpp
  32. 1 1
      Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp
  33. 2 2
      Userland/Libraries/LibWeb/Painting/SVGPaintable.cpp
  34. 1 1
      Userland/Libraries/LibWeb/Painting/SVGPaintable.h
  35. 1 1
      Userland/Libraries/LibWeb/Painting/SVGSVGPaintable.cpp
  36. 2 2
      Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp
  37. 4 4
      Userland/Libraries/LibWeb/Painting/StackingContext.cpp
  38. 2 2
      Userland/Services/WebContent/ConnectionFromClient.cpp
  39. 2 2
      Userland/Services/WebContent/PageHost.cpp

+ 4 - 4
Userland/Libraries/LibWeb/DOM/Element.cpp

@@ -593,7 +593,7 @@ JS::NonnullGCPtr<Geometry::DOMRect> Element::get_bounding_client_rect() const
     VERIFY(document().browsing_context());
     auto viewport_offset = document().browsing_context()->viewport_scroll_offset();
 
-    return Geometry::DOMRect::create(realm(), paint_box->absolute_rect().translated(-viewport_offset.x(), -viewport_offset.y()));
+    return Geometry::DOMRect::create(realm(), paint_box->absolute_rect().translated(-viewport_offset.x(), -viewport_offset.y()).to_type<float>());
 }
 
 // https://drafts.csswg.org/cssom-view/#dom-element-getclientrects
@@ -676,7 +676,7 @@ int Element::client_width() const
 
     // 3. Return the width of the padding edge excluding the width of any rendered scrollbar between the padding edge and the border edge,
     // ignoring any transforms that apply to the element and its ancestors.
-    return paint_box()->absolute_padding_box_rect().width();
+    return paint_box()->absolute_padding_box_rect().width().value();
 }
 
 // https://drafts.csswg.org/cssom-view/#dom-element-clientheight
@@ -701,7 +701,7 @@ int Element::client_height() const
 
     // 3. Return the height of the padding edge excluding the height of any rendered scrollbar between the padding edge and the border edge,
     //    ignoring any transforms that apply to the element and its ancestors.
-    return paint_box()->absolute_padding_box_rect().height();
+    return paint_box()->absolute_padding_box_rect().height().value();
 }
 
 void Element::children_changed()
@@ -1212,7 +1212,7 @@ static void scroll_an_element_into_view(DOM::Element& element, Bindings::ScrollB
     if (!layout_node)
         return;
 
-    page->client().page_did_request_scroll_into_view(verify_cast<Layout::Box>(*layout_node).paint_box()->absolute_padding_box_rect().to_type<CSSPixels>());
+    page->client().page_did_request_scroll_into_view(verify_cast<Layout::Box>(*layout_node).paint_box()->absolute_padding_box_rect());
 }
 
 // https://w3c.github.io/csswg-drafts/cssom-view-1/#dom-element-scrollintoview

+ 1 - 1
Userland/Libraries/LibWeb/Dump.cpp

@@ -264,7 +264,7 @@ void dump_tree(StringBuilder& builder, Layout::Node const& layout_node, bool sho
                 builder.appendff("start: {}, length: {}, rect: {}\n",
                     fragment.start(),
                     fragment.length(),
-                    fragment.absolute_rect().to_deprecated_string());
+                    fragment.absolute_rect());
                 if (is<Layout::TextNode>(fragment.layout_node())) {
                     for (size_t i = 0; i < indent; ++i)
                         builder.append("  "sv);

+ 2 - 2
Userland/Libraries/LibWeb/HTML/HTMLElement.cpp

@@ -199,7 +199,7 @@ int HTMLElement::offset_width() const
     // 2. Return the width of the axis-aligned bounding box of the border boxes of all fragments generated by the element’s principal box,
     //    ignoring any transforms that apply to the element and its ancestors.
     // FIXME: Account for inline boxes.
-    return paint_box()->border_box_width();
+    return paint_box()->border_box_width().value();
 }
 
 // https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetheight
@@ -215,7 +215,7 @@ int HTMLElement::offset_height() const
     // 2. Return the height of the axis-aligned bounding box of the border boxes of all fragments generated by the element’s principal box,
     //    ignoring any transforms that apply to the element and its ancestors.
     // FIXME: Account for inline boxes.
-    return paint_box()->border_box_height();
+    return paint_box()->border_box_height().value();
 }
 
 // https://html.spec.whatwg.org/multipage/links.html#cannot-navigate

+ 2 - 2
Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp

@@ -102,7 +102,7 @@ unsigned HTMLImageElement::width() const
 
     // Return the rendered width of the image, in CSS pixels, if the image is being rendered.
     if (auto* paint_box = this->paint_box())
-        return paint_box->content_width();
+        return paint_box->content_width().value();
 
     // NOTE: This step seems to not be in the spec, but all browsers do it.
     auto width_attr = get_attribute(HTML::AttributeNames::width);
@@ -130,7 +130,7 @@ unsigned HTMLImageElement::height() const
 
     // Return the rendered height of the image, in CSS pixels, if the image is being rendered.
     if (auto* paint_box = this->paint_box())
-        return paint_box->content_height();
+        return paint_box->content_height().value();
 
     // NOTE: This step seems to not be in the spec, but all browsers do it.
     auto height_attr = get_attribute(HTML::AttributeNames::height);

+ 1 - 1
Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp

@@ -539,7 +539,7 @@ void BlockFormattingContext::layout_initial_containing_block(LayoutMode layout_m
     if (bottom_edge >= viewport_rect.height() || right_edge >= viewport_rect.width()) {
         // FIXME: Move overflow data to LayoutState!
         auto& overflow_data = icb_state.ensure_overflow_data();
-        overflow_data.scrollable_overflow_rect = viewport_rect.to_type<float>();
+        overflow_data.scrollable_overflow_rect = viewport_rect.to_type<CSSPixels>();
         // NOTE: The edges are *within* the rectangle, so we add 1 to get the width and height.
         overflow_data.scrollable_overflow_rect.set_size(right_edge + 1, bottom_edge + 1);
     }

+ 3 - 2
Userland/Libraries/LibWeb/Layout/Box.cpp

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
+ * Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -31,8 +31,9 @@ Box::~Box()
 
 void Box::set_needs_display()
 {
+    // FIXME: Make `set_needs_display` take CSSPixels
     if (paint_box())
-        browsing_context().set_needs_display(enclosing_int_rect(paint_box()->absolute_rect()));
+        browsing_context().set_needs_display(enclosing_int_rect(paint_box()->absolute_rect().to_type<float>()));
 }
 
 bool Box::is_body() const

+ 1 - 1
Userland/Libraries/LibWeb/Layout/FormattingContext.cpp

@@ -919,7 +919,7 @@ Gfx::FloatPoint FormattingContext::calculate_static_position(Box const& box) con
                 }
             }
             if (last_fragment) {
-                y = last_fragment->offset().y() + last_fragment->height();
+                y = (last_fragment->offset().y() + last_fragment->height()).value();
             }
         } else {
             // Easy case: no previous sibling, we're at the top of the containing block.

+ 2 - 1
Userland/Libraries/LibWeb/Layout/FrameBox.cpp

@@ -33,7 +33,8 @@ void FrameBox::did_set_rect()
     ReplacedBox::did_set_rect();
 
     VERIFY(dom_node().nested_browsing_context());
-    dom_node().nested_browsing_context()->set_size(paint_box()->content_size().to_type<int>());
+    // FIXME: Pass CSSPixels here instead of int.
+    dom_node().nested_browsing_context()->set_size(paint_box()->content_size().to_type<float>().to_type<int>());
 }
 
 RefPtr<Painting::Paintable> FrameBox::create_paintable() const

+ 1 - 1
Userland/Libraries/LibWeb/Layout/ImageBox.cpp

@@ -94,7 +94,7 @@ bool ImageBox::renders_as_alt_text() const
 
 void ImageBox::browsing_context_did_set_viewport_rect(Gfx::IntRect const& viewport_rect)
 {
-    m_image_loader.set_visible_in_viewport(paint_box() && viewport_rect.to_type<float>().intersects(paint_box()->absolute_rect()));
+    m_image_loader.set_visible_in_viewport(paint_box() && viewport_rect.to_type<CSSPixels>().intersects(paint_box()->absolute_rect()));
 }
 
 RefPtr<Painting::Paintable> ImageBox::create_paintable() const

+ 1 - 1
Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp

@@ -49,7 +49,7 @@ void InitialContainingBlock::build_stacking_context_tree()
 void InitialContainingBlock::paint_all_phases(PaintContext& context)
 {
     build_stacking_context_tree_if_needed();
-    context.painter().fill_rect(enclosing_int_rect(paint_box()->absolute_rect()), document().background_color(context.palette()));
+    context.painter().fill_rect(context.enclosing_device_rect(paint_box()->absolute_rect()).to_type<int>(), document().background_color(context.palette()));
     context.painter().translate(-context.device_viewport_rect().location().to_type<int>());
     paint_box()->stacking_context()->paint(context);
 }

+ 2 - 2
Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp

@@ -202,7 +202,7 @@ void InlineFormattingContext::apply_justification_to_fragments(CSS::TextJustify
     for (auto& fragment : line_box.fragments()) {
         if (fragment.is_justifiable_whitespace()) {
             ++whitespace_count;
-            excess_horizontal_space_including_whitespace += fragment.width();
+            excess_horizontal_space_including_whitespace += fragment.width().value();
         }
     }
 
@@ -221,7 +221,7 @@ void InlineFormattingContext::apply_justification_to_fragments(CSS::TextJustify
 
         if (fragment.is_justifiable_whitespace()
             && fragment.width() != justified_space_width) {
-            running_diff += justified_space_width - fragment.width();
+            running_diff += justified_space_width - fragment.width().value();
             fragment.set_width(justified_space_width);
         }
     }

+ 5 - 5
Userland/Libraries/LibWeb/Layout/Label.cpp

@@ -39,8 +39,8 @@ void Label::handle_mouseup_on_label(Badge<Painting::TextPaintable>, CSSPixelPoin
         return;
 
     if (auto* control = labeled_control(); control) {
-        bool is_inside_control = enclosing_int_rect(control->paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
-        bool is_inside_label = enclosing_int_rect(paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
+        bool is_inside_control = control->paint_box()->absolute_rect().contains(position);
+        bool is_inside_label = paint_box()->absolute_rect().contains(position);
 
         if (is_inside_control || is_inside_label)
             control->paintable()->handle_associated_label_mouseup({});
@@ -55,8 +55,8 @@ void Label::handle_mousemove_on_label(Badge<Painting::TextPaintable>, CSSPixelPo
         return;
 
     if (auto* control = labeled_control(); control) {
-        bool is_inside_control = enclosing_int_rect(control->paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
-        bool is_inside_label = enclosing_int_rect(paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
+        bool is_inside_control = control->paint_box()->absolute_rect().contains(position);
+        bool is_inside_label = paint_box()->absolute_rect().contains(position);
 
         control->paintable()->handle_associated_label_mousemove({}, is_inside_control || is_inside_label);
     }
@@ -65,7 +65,7 @@ void Label::handle_mousemove_on_label(Badge<Painting::TextPaintable>, CSSPixelPo
 bool Label::is_inside_associated_label(LabelableNode const& control, CSSPixelPoint position)
 {
     if (auto* label = label_for_control_node(control); label)
-        return enclosing_int_rect(label->paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
+        return label->paint_box()->absolute_rect().contains(position);
     return false;
 }
 

+ 1 - 1
Userland/Libraries/LibWeb/Layout/LayoutState.cpp

@@ -76,7 +76,7 @@ void LayoutState::commit()
         if (is<Layout::Box>(node)) {
             auto& box = static_cast<Layout::Box const&>(node);
             auto& paint_box = const_cast<Painting::PaintableBox&>(*box.paint_box());
-            paint_box.set_offset(used_values.offset);
+            paint_box.set_offset(used_values.offset.to_type<CSSPixels>());
             paint_box.set_content_size(used_values.content_width(), used_values.content_height());
             paint_box.set_overflow_data(move(used_values.overflow_data));
             paint_box.set_containing_line_box_fragment(used_values.containing_line_box_fragment);

+ 2 - 2
Userland/Libraries/LibWeb/Layout/LineBox.cpp

@@ -26,7 +26,7 @@ void LineBox::add_fragment(Node const& layout_node, int start, int length, float
     } else {
         float x_offset = leading_margin + leading_size + m_width;
         float y_offset = 0.0f;
-        m_fragments.append(LineBoxFragment { layout_node, start, length, Gfx::FloatPoint(x_offset, y_offset), Gfx::FloatSize(content_width, content_height), border_box_top, border_box_bottom, fragment_type });
+        m_fragments.append(LineBoxFragment { layout_node, start, length, CSSPixelPoint(x_offset, y_offset), CSSPixelSize(content_width, content_height), border_box_top, border_box_bottom, fragment_type });
     }
     m_width += leading_margin + leading_size + content_width + trailing_size + trailing_margin;
 }
@@ -35,7 +35,7 @@ void LineBox::trim_trailing_whitespace()
 {
     while (!m_fragments.is_empty() && m_fragments.last().is_justifiable_whitespace()) {
         auto fragment = m_fragments.take_last();
-        m_width -= fragment.width();
+        m_width -= fragment.width().value();
     }
 
     if (m_fragments.is_empty())

+ 7 - 7
Userland/Libraries/LibWeb/Layout/LineBoxFragment.cpp

@@ -33,15 +33,15 @@ StringView LineBoxFragment::text() const
     return verify_cast<TextNode>(layout_node()).text_for_rendering().substring_view(m_start, m_length);
 }
 
-const Gfx::FloatRect LineBoxFragment::absolute_rect() const
+CSSPixelRect const LineBoxFragment::absolute_rect() const
 {
-    Gfx::FloatRect rect { {}, size() };
+    CSSPixelRect rect { {}, size() };
     rect.set_location(m_layout_node.containing_block()->paint_box()->absolute_position());
     rect.translate_by(offset());
     return rect;
 }
 
-int LineBoxFragment::text_index_at(float x) const
+int LineBoxFragment::text_index_at(CSSPixels x) const
 {
     if (!is<TextNode>(layout_node()))
         return 0;
@@ -49,15 +49,15 @@ int LineBoxFragment::text_index_at(float x) const
     auto& font = layout_text.font();
     Utf8View view(text());
 
-    float relative_x = x - absolute_x();
+    CSSPixels relative_x = x - absolute_x();
     float glyph_spacing = font.glyph_spacing();
 
     if (relative_x < 0)
         return 0;
 
-    float width_so_far = 0;
+    CSSPixels width_so_far = 0;
     for (auto it = view.begin(); it != view.end(); ++it) {
-        float glyph_width = font.glyph_or_emoji_width(*it);
+        CSSPixels glyph_width = font.glyph_or_emoji_width(*it);
         if ((width_so_far + (glyph_width + glyph_spacing) / 2) > relative_x)
             return m_start + view.byte_offset_of(it);
         width_so_far += glyph_width + glyph_spacing;
@@ -65,7 +65,7 @@ int LineBoxFragment::text_index_at(float x) const
     return m_start + m_length;
 }
 
-Gfx::FloatRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
+CSSPixelRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
 {
     if (layout_node().selection_state() == Node::SelectionState::None)
         return {};

+ 32 - 23
Userland/Libraries/LibWeb/Layout/LineBoxFragment.h

@@ -6,9 +6,9 @@
 
 #pragma once
 
-#include <LibGfx/Forward.h>
 #include <LibGfx/Rect.h>
 #include <LibWeb/Forward.h>
+#include <LibWeb/PixelUnits.h>
 
 namespace Web::Layout {
 
@@ -22,7 +22,7 @@ public:
         Trailing,
     };
 
-    LineBoxFragment(Node const& layout_node, int start, int length, Gfx::FloatPoint offset, Gfx::FloatSize size, float border_box_top, float border_box_bottom, Type type)
+    LineBoxFragment(Node const& layout_node, int start, int length, CSSPixelPoint offset, CSSPixelSize size, CSSPixels border_box_top, CSSPixels border_box_bottom, Type type)
         : m_layout_node(layout_node)
         , m_start(start)
         , m_length(length)
@@ -37,45 +37,54 @@ public:
     Node const& layout_node() const { return m_layout_node; }
     int start() const { return m_start; }
     int length() const { return m_length; }
-    const Gfx::FloatRect absolute_rect() const;
+    CSSPixelRect const absolute_rect() const;
     Type type() const { return m_type; }
 
-    Gfx::FloatPoint offset() const { return m_offset; }
-    void set_offset(Gfx::FloatPoint offset) { m_offset = offset; }
+    CSSPixelPoint offset() const
+    {
+        return m_offset;
+    }
+    void set_offset(CSSPixelPoint offset) { m_offset = offset; }
 
     // The baseline of a fragment is the number of pixels from the top to the text baseline.
-    void set_baseline(float y) { m_baseline = y; }
-    float baseline() const { return m_baseline; }
+    void set_baseline(CSSPixels y) { m_baseline = y; }
+    CSSPixels baseline() const { return m_baseline; }
 
-    Gfx::FloatSize size() const { return m_size; }
-    void set_width(float width) { m_size.set_width(width); }
-    void set_height(float height) { m_size.set_height(height); }
-    float width() const { return m_size.width(); }
-    float height() const { return m_size.height(); }
+    CSSPixelSize size() const
+    {
+        return m_size;
+    }
+    void set_width(CSSPixels width) { m_size.set_width(width); }
+    void set_height(CSSPixels height) { m_size.set_height(height); }
+    CSSPixels width() const { return m_size.width(); }
+    CSSPixels height() const { return m_size.height(); }
 
-    float border_box_height() const { return m_border_box_top + height() + m_border_box_bottom; }
-    float border_box_top() const { return m_border_box_top; }
-    float border_box_bottom() const { return m_border_box_bottom; }
+    CSSPixels border_box_height() const
+    {
+        return m_border_box_top + height() + m_border_box_bottom;
+    }
+    CSSPixels border_box_top() const { return m_border_box_top; }
+    CSSPixels border_box_bottom() const { return m_border_box_bottom; }
 
-    float absolute_x() const { return absolute_rect().x(); }
+    CSSPixels absolute_x() const { return absolute_rect().x(); }
 
     bool ends_in_whitespace() const;
     bool is_justifiable_whitespace() const;
     StringView text() const;
 
-    int text_index_at(float x) const;
+    int text_index_at(CSSPixels x) const;
 
-    Gfx::FloatRect selection_rect(Gfx::Font const&) const;
+    CSSPixelRect selection_rect(Gfx::Font const&) const;
 
 private:
     Node const& m_layout_node;
     int m_start { 0 };
     int m_length { 0 };
-    Gfx::FloatPoint m_offset;
-    Gfx::FloatSize m_size;
-    float m_border_box_top { 0 };
-    float m_border_box_bottom { 0 };
-    float m_baseline { 0 };
+    CSSPixelPoint m_offset;
+    CSSPixelSize m_size;
+    CSSPixels m_border_box_top { 0 };
+    CSSPixels m_border_box_bottom { 0 };
+    CSSPixels m_baseline { 0 };
     Type m_type { Type::Normal };
 };
 

+ 8 - 8
Userland/Libraries/LibWeb/Layout/LineBuilder.cpp

@@ -227,15 +227,15 @@ void LineBuilder::update_last_line()
     for (size_t i = 0; i < line_box.fragments().size(); ++i) {
         auto& fragment = line_box.fragments()[i];
 
-        float new_fragment_x = roundf(x_offset + fragment.offset().x());
+        float new_fragment_x = roundf(x_offset + fragment.offset().x().value());
         float new_fragment_y = 0;
 
         auto y_value_for_alignment = [&](CSS::VerticalAlign vertical_align) {
             switch (vertical_align) {
             case CSS::VerticalAlign::Baseline:
-                return m_current_y + line_box_baseline - fragment.baseline() + fragment.border_box_top();
+                return m_current_y + line_box_baseline - fragment.baseline().value() + fragment.border_box_top().value();
             case CSS::VerticalAlign::Top:
-                return m_current_y + fragment.border_box_top();
+                return m_current_y + fragment.border_box_top().value();
             case CSS::VerticalAlign::Middle:
             case CSS::VerticalAlign::Bottom:
             case CSS::VerticalAlign::Sub:
@@ -243,7 +243,7 @@ void LineBuilder::update_last_line()
             case CSS::VerticalAlign::TextBottom:
             case CSS::VerticalAlign::TextTop:
                 // FIXME: These are all 'baseline'
-                return m_current_y + line_box_baseline - fragment.baseline() + fragment.border_box_top();
+                return m_current_y + line_box_baseline - fragment.baseline().value() + fragment.border_box_top().value();
             }
             VERIFY_NOT_REACHED();
         };
@@ -266,15 +266,15 @@ void LineBuilder::update_last_line()
             // FIXME: Support inline-table elements.
             if (fragment.layout_node().is_replaced_box() || (fragment.layout_node().display().is_inline_outside() && !fragment.layout_node().display().is_flow_inside())) {
                 auto const& fragment_box_state = m_layout_state.get(static_cast<Box const&>(fragment.layout_node()));
-                top_of_inline_box = fragment.offset().y() - fragment_box_state.margin_box_top();
-                bottom_of_inline_box = fragment.offset().y() + fragment_box_state.content_height() + fragment_box_state.margin_box_bottom();
+                top_of_inline_box = (fragment.offset().y() - fragment_box_state.margin_box_top()).value();
+                bottom_of_inline_box = (fragment.offset().y() + fragment_box_state.content_height() + fragment_box_state.margin_box_bottom()).value();
             } else {
                 auto font_metrics = fragment.layout_node().font().pixel_metrics();
                 auto typographic_height = 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() - font_metrics.ascent - half_leading).value();
+                bottom_of_inline_box = (fragment.offset().y() + fragment.baseline() + font_metrics.descent + half_leading).value();
             }
             if (auto length_percentage = fragment.layout_node().computed_values().vertical_align().template get_pointer<CSS::LengthPercentage>(); length_percentage && length_percentage->is_length())
                 bottom_of_inline_box += length_percentage->length().to_px(fragment.layout_node());

+ 3 - 3
Userland/Libraries/LibWeb/Layout/Node.cpp

@@ -158,7 +158,7 @@ void Node::set_needs_display()
         return;
     containing_block->paint_box()->for_each_fragment([&](auto& fragment) {
         if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
-            browsing_context().set_needs_display(enclosing_int_rect(fragment.absolute_rect()));
+            browsing_context().set_needs_display(fragment.absolute_rect().template to_type<float>().template to_type<int>());
         }
         return IterationDecision::Continue;
     });
@@ -167,13 +167,13 @@ void Node::set_needs_display()
 Gfx::FloatPoint Node::box_type_agnostic_position() const
 {
     if (is<Box>(*this))
-        return verify_cast<Box>(*this).paint_box()->absolute_position();
+        return verify_cast<Box>(*this).paint_box()->absolute_position().to_type<float>();
     VERIFY(is_inline());
     Gfx::FloatPoint position;
     if (auto* block = containing_block()) {
         block->paint_box()->for_each_fragment([&](auto& fragment) {
             if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
-                position = fragment.absolute_rect().location();
+                position = fragment.absolute_rect().location().template to_type<float>();
                 return IterationDecision::Break;
             }
             return IterationDecision::Continue;

+ 2 - 2
Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp

@@ -27,10 +27,10 @@ float SVGGeometryBox::viewbox_scaling() const
     auto view_box = svg_box->view_box().value();
 
     bool has_specified_width = svg_box->has_attribute(HTML::AttributeNames::width);
-    auto specified_width = paint_box()->content_width();
+    auto specified_width = paint_box()->content_width().value();
 
     bool has_specified_height = svg_box->has_attribute(HTML::AttributeNames::height);
-    auto specified_height = paint_box()->content_height();
+    auto specified_height = paint_box()->content_height().value();
 
     auto scale_width = has_specified_width ? specified_width / view_box.width : 1;
     auto scale_height = has_specified_height ? specified_height / view_box.height : 1;

+ 6 - 4
Userland/Libraries/LibWeb/Painting/ButtonPaintable.cpp

@@ -42,10 +42,12 @@ void ButtonPaintable::paint(PaintContext& context, PaintPhase phase) const
 
     auto const& dom_node = layout_box().dom_node();
     if (is<HTML::HTMLInputElement>(dom_node) && phase == PaintPhase::Foreground) {
-        auto text_rect = enclosing_int_rect(absolute_rect());
-        if (being_pressed())
-            text_rect.translate_by(1, 1);
-        context.painter().draw_text(text_rect, static_cast<HTML::HTMLInputElement const&>(dom_node).value(), layout_box().font(), Gfx::TextAlignment::Center, computed_values().color());
+        auto text_rect = context.enclosing_device_rect(absolute_rect());
+        if (being_pressed()) {
+            auto offset = context.rounded_device_pixels(1);
+            text_rect.translate_by(offset, offset);
+        }
+        context.painter().draw_text(text_rect.to_type<int>(), static_cast<HTML::HTMLInputElement const&>(dom_node).value(), layout_box().font(), Gfx::TextAlignment::Center, computed_values().color());
     }
 }
 

+ 1 - 1
Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp

@@ -31,7 +31,7 @@ void CanvasPaintable::paint(PaintContext& context, PaintPhase phase) const
     PaintableBox::paint(context, phase);
 
     if (phase == PaintPhase::Foreground) {
-        auto canvas_rect = context.rounded_device_rect(absolute_rect().to_type<CSSPixels>());
+        auto canvas_rect = context.rounded_device_rect(absolute_rect());
         ScopedCornerRadiusClip corner_clip { context, context.painter(), canvas_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) };
 
         // FIXME: This should be done at a different level.

+ 1 - 1
Userland/Libraries/LibWeb/Painting/CheckBoxPaintable.cpp

@@ -43,7 +43,7 @@ void CheckBoxPaintable::paint(PaintContext& context, PaintPhase phase) const
 
     auto const& checkbox = static_cast<HTML::HTMLInputElement const&>(layout_box().dom_node());
     if (phase == PaintPhase::Foreground)
-        Gfx::StylePainter::paint_check_box(context.painter(), enclosing_int_rect(absolute_rect()), context.palette(), layout_box().dom_node().enabled(), checkbox.checked(), being_pressed());
+        Gfx::StylePainter::paint_check_box(context.painter(), context.enclosing_device_rect(absolute_rect()).to_type<int>(), context.palette(), layout_box().dom_node().enabled(), checkbox.checked(), being_pressed());
 }
 
 }

+ 4 - 3
Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp

@@ -42,14 +42,15 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const
     if (phase == PaintPhase::Foreground) {
         if (layout_box().renders_as_alt_text()) {
             auto& image_element = verify_cast<HTML::HTMLImageElement>(*dom_node());
+            auto enclosing_rect = context.enclosing_device_rect(absolute_rect()).to_type<int>();
             context.painter().set_font(Platform::FontPlugin::the().default_font());
-            Gfx::StylePainter::paint_frame(context.painter(), enclosing_int_rect(absolute_rect()), context.palette(), Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2);
+            Gfx::StylePainter::paint_frame(context.painter(), enclosing_rect, context.palette(), Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2);
             auto alt = image_element.alt();
             if (alt.is_empty())
                 alt = image_element.src();
-            context.painter().draw_text(enclosing_int_rect(absolute_rect()), alt, Gfx::TextAlignment::Center, computed_values().color(), Gfx::TextElision::Right);
+            context.painter().draw_text(enclosing_rect, alt, Gfx::TextAlignment::Center, computed_values().color(), Gfx::TextElision::Right);
         } else if (auto bitmap = layout_box().image_loader().bitmap(layout_box().image_loader().current_frame_index())) {
-            auto image_rect = context.rounded_device_rect(absolute_rect().to_type<CSSPixels>());
+            auto image_rect = context.rounded_device_rect(absolute_rect());
             ScopedCornerRadiusClip corner_clip { context, context.painter(), image_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) };
             context.painter().draw_scaled_bitmap(image_rect.to_type<int>(), *bitmap, bitmap->rect(), 1.0f, to_gfx_scaling_mode(computed_values().image_rendering()));
         }

+ 5 - 5
Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp

@@ -41,7 +41,7 @@ void InlinePaintable::paint(PaintContext& context, Painting::PaintPhase phase) c
         auto containing_block_position_in_absolute_coordinates = containing_block()->paint_box()->absolute_position();
 
         for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) {
-            Gfx::FloatRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() };
+            CSSPixelRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() };
 
             if (is_first_fragment) {
                 float extra_start_width = box_model().padding.left;
@@ -54,8 +54,8 @@ void InlinePaintable::paint(PaintContext& context, Painting::PaintPhase phase) c
                 absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_end_width);
             }
 
-            auto border_radii_data = Painting::normalized_border_radii_data(layout_node(), absolute_fragment_rect.to_type<CSSPixels>(), top_left_border_radius, top_right_border_radius, bottom_right_border_radius, bottom_left_border_radius);
-            Painting::paint_background(context, layout_node(), absolute_fragment_rect.to_type<CSSPixels>(), computed_values().background_color(), computed_values().image_rendering(), &computed_values().background_layers(), border_radii_data);
+            auto border_radii_data = Painting::normalized_border_radii_data(layout_node(), absolute_fragment_rect, top_left_border_radius, top_right_border_radius, bottom_right_border_radius, bottom_left_border_radius);
+            Painting::paint_background(context, layout_node(), absolute_fragment_rect, computed_values().background_color(), computed_values().image_rendering(), &computed_values().background_layers(), border_radii_data);
 
             if (auto computed_box_shadow = computed_values().box_shadow(); !computed_box_shadow.is_empty()) {
                 Vector<Painting::ShadowData> resolved_box_shadow_data;
@@ -69,7 +69,7 @@ void InlinePaintable::paint(PaintContext& context, Painting::PaintPhase phase) c
                         layer.spread_distance.to_px(layout_node()),
                         layer.placement == CSS::ShadowPlacement::Outer ? Painting::ShadowPlacement::Outer : Painting::ShadowPlacement::Inner);
                 }
-                Painting::paint_box_shadow(context, absolute_fragment_rect.to_type<CSSPixels>(), border_radii_data, resolved_box_shadow_data);
+                Painting::paint_box_shadow(context, absolute_fragment_rect, border_radii_data, resolved_box_shadow_data);
             }
 
             return IterationDecision::Continue;
@@ -121,7 +121,7 @@ void InlinePaintable::paint(PaintContext& context, Painting::PaintPhase phase) c
         //        would be none. Once we implement non-rectangular outlines for the `outline` CSS
         //        property, we can use that here instead.
         for_each_fragment([&](auto const& fragment, bool, bool) {
-            painter.draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Magenta);
+            painter.draw_rect(context.enclosing_device_rect(fragment.absolute_rect()).template to_type<int>(), Color::Magenta);
             return IterationDecision::Continue;
         });
     }

+ 2 - 2
Userland/Libraries/LibWeb/Painting/LabelablePaintable.cpp

@@ -51,7 +51,7 @@ LabelablePaintable::DispatchEventOfSameName LabelablePaintable::handle_mouseup(B
     if (!m_tracking_mouse || button != GUI::MouseButton::Primary || !layout_box().dom_node().enabled())
         return DispatchEventOfSameName::No;
 
-    bool is_inside_node_or_label = absolute_rect().to_type<CSSPixels>().contains(position);
+    bool is_inside_node_or_label = absolute_rect().contains(position);
     if (!is_inside_node_or_label)
         is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
 
@@ -66,7 +66,7 @@ LabelablePaintable::DispatchEventOfSameName LabelablePaintable::handle_mousemove
     if (!m_tracking_mouse || !layout_box().dom_node().enabled())
         return DispatchEventOfSameName::No;
 
-    bool is_inside_node_or_label = absolute_rect().to_type<CSSPixels>().contains(position);
+    bool is_inside_node_or_label = absolute_rect().contains(position);
     if (!is_inside_node_or_label)
         is_inside_node_or_label = Layout::Label::is_inside_associated_label(layout_box(), position);
 

+ 2 - 1
Userland/Libraries/LibWeb/Painting/MarkerPaintable.cpp

@@ -31,7 +31,8 @@ void MarkerPaintable::paint(PaintContext& context, PaintPhase phase) const
     if (phase != PaintPhase::Foreground)
         return;
 
-    CSSPixelRect enclosing = absolute_rect().to_rounded<float>().to_type<CSSPixels>();
+    // FIXME: All this does is round to the nearest whole CSS pixel, but it's goofy.
+    CSSPixelRect enclosing = absolute_rect().to_type<float>().to_rounded<float>().to_type<CSSPixels>();
     auto device_enclosing = context.enclosing_device_rect(enclosing);
 
     CSSPixels marker_width = enclosing.height() / 2.0f;

+ 4 - 3
Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.cpp

@@ -36,7 +36,8 @@ void NestedBrowsingContextPaintable::paint(PaintContext& context, PaintPhase pha
     PaintableBox::paint(context, phase);
 
     if (phase == PaintPhase::Foreground) {
-        auto clip_rect = context.rounded_device_rect(absolute_rect().to_type<CSSPixels>());
+        auto absolute_rect = this->absolute_rect();
+        auto clip_rect = context.rounded_device_rect(absolute_rect);
         ScopedCornerRadiusClip corner_clip { context, context.painter(), clip_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) };
 
         auto* hosted_document = layout_box().dom_node().content_document_without_origin_check();
@@ -50,7 +51,7 @@ void NestedBrowsingContextPaintable::paint(PaintContext& context, PaintPhase pha
         auto old_viewport_rect = context.device_viewport_rect();
 
         context.painter().add_clip_rect(clip_rect.to_type<int>());
-        context.painter().translate(absolute_x(), absolute_y());
+        context.painter().translate(absolute_rect.x().value(), absolute_rect.y().value());
 
         context.set_device_viewport_rect({ {}, layout_box().dom_node().nested_browsing_context()->size() });
         const_cast<Layout::InitialContainingBlock*>(hosted_layout_tree)->paint_all_phases(context);
@@ -60,7 +61,7 @@ void NestedBrowsingContextPaintable::paint(PaintContext& context, PaintPhase pha
 
         if constexpr (HIGHLIGHT_FOCUSED_FRAME_DEBUG) {
             if (layout_box().dom_node().nested_browsing_context()->is_focused_context()) {
-                context.painter().draw_rect(absolute_rect().to_type<int>(), Color::Cyan);
+                context.painter().draw_rect(clip_rect.to_type<int>(), Color::Cyan);
             }
         }
     }

+ 43 - 41
Userland/Libraries/LibWeb/Painting/PaintableBox.cpp

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -39,7 +40,8 @@ void PaintableBox::invalidate_stacking_context()
 
 bool PaintableBox::is_out_of_view(PaintContext& context) const
 {
-    return !enclosing_int_rect(absolute_paint_rect())
+    return !context.enclosing_device_rect(absolute_paint_rect())
+                .to_type<int>()
                 .translated(context.painter().translation())
                 .intersects(context.painter().clip_rect());
 }
@@ -53,23 +55,23 @@ PaintableWithLines::~PaintableWithLines()
 {
 }
 
-void PaintableBox::set_offset(Gfx::FloatPoint offset)
+void PaintableBox::set_offset(CSSPixelPoint offset)
 {
     m_offset = offset;
     // FIXME: This const_cast is gross.
     const_cast<Layout::Box&>(layout_box()).did_set_rect();
 }
 
-void PaintableBox::set_content_size(Gfx::FloatSize size)
+void PaintableBox::set_content_size(CSSPixelSize size)
 {
     m_content_size = size;
     // FIXME: This const_cast is gross.
     const_cast<Layout::Box&>(layout_box()).did_set_rect();
 }
 
-Gfx::FloatPoint PaintableBox::effective_offset() const
+CSSPixelPoint PaintableBox::effective_offset() const
 {
-    Gfx::FloatPoint offset;
+    CSSPixelPoint offset;
     if (m_containing_line_box_fragment.has_value()) {
 
         // FIXME: This is a hack to deal with situations where the layout tree has been garbage collected.
@@ -89,22 +91,22 @@ Gfx::FloatPoint PaintableBox::effective_offset() const
     return offset;
 }
 
-Gfx::FloatRect PaintableBox::compute_absolute_rect() const
+CSSPixelRect PaintableBox::compute_absolute_rect() const
 {
-    Gfx::FloatRect rect { effective_offset(), content_size() };
+    CSSPixelRect rect { effective_offset(), content_size() };
     for (auto const* block = containing_block(); block && block->paintable(); block = block->paintable()->containing_block())
         rect.translate_by(block->paint_box()->effective_offset());
     return rect;
 }
 
-Gfx::FloatRect PaintableBox::absolute_rect() const
+CSSPixelRect PaintableBox::absolute_rect() const
 {
     if (!m_absolute_rect.has_value())
         m_absolute_rect = compute_absolute_rect();
     return *m_absolute_rect;
 }
 
-Gfx::FloatRect PaintableBox::compute_absolute_paint_rect() const
+CSSPixelRect PaintableBox::compute_absolute_paint_rect() const
 {
     // FIXME: This likely incomplete:
     auto rect = absolute_border_box_rect();
@@ -112,14 +114,14 @@ Gfx::FloatRect PaintableBox::compute_absolute_paint_rect() const
     for (auto const& shadow : resolved_box_shadow_data) {
         if (shadow.placement == ShadowPlacement::Inner)
             continue;
-        auto inflate = shadow.spread_distance.value() + shadow.blur_radius.value();
-        auto shadow_rect = rect.inflated(inflate, inflate, inflate, inflate).translated(shadow.offset_x.value(), shadow.offset_y.value());
+        auto inflate = shadow.spread_distance + shadow.blur_radius;
+        auto shadow_rect = rect.inflated(inflate, inflate, inflate, inflate).translated(shadow.offset_x, shadow.offset_y);
         rect = rect.united(shadow_rect);
     }
     return rect;
 }
 
-Gfx::FloatRect PaintableBox::absolute_paint_rect() const
+CSSPixelRect PaintableBox::absolute_paint_rect() const
 {
     if (!m_absolute_paint_rect.has_value())
         m_absolute_paint_rect = compute_absolute_paint_rect();
@@ -156,7 +158,7 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
         if (should_clip_rect) {
             context.painter().save();
             auto border_box = absolute_border_box_rect();
-            context.painter().add_clip_rect(context.rounded_device_rect(clip_rect.to_rect().resolved(Paintable::layout_node(), border_box).to_type<CSSPixels>()).to_type<int>());
+            context.painter().add_clip_rect(context.rounded_device_rect(clip_rect.to_rect().resolved(Paintable::layout_node(), border_box.to_type<float>()).to_type<CSSPixels>()).to_type<int>());
         }
         paint_backdrop_filter(context);
         paint_background(context);
@@ -171,7 +173,7 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
         context.painter().restore();
 
     if (phase == PaintPhase::Overlay && layout_box().dom_node() && layout_box().document().inspected_node() == layout_box().dom_node()) {
-        auto content_rect = absolute_rect().to_type<CSSPixels>();
+        auto content_rect = absolute_rect();
 
         auto margin_box = box_model().margin_box();
         CSSPixelRect margin_rect;
@@ -180,8 +182,8 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
         margin_rect.set_y(absolute_y() - margin_box.top);
         margin_rect.set_height(content_height() + margin_box.top + margin_box.bottom);
 
-        auto border_rect = absolute_border_box_rect().to_type<CSSPixels>();
-        auto padding_rect = absolute_padding_box_rect().to_type<CSSPixels>();
+        auto border_rect = absolute_border_box_rect();
+        auto padding_rect = absolute_padding_box_rect();
 
         auto paint_inspector_rect = [&](CSSPixelRect const& rect, Color color) {
             auto device_rect = context.enclosing_device_rect(rect).to_type<int>();
@@ -216,7 +218,7 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
 
     if (phase == PaintPhase::FocusOutline && layout_box().dom_node() && layout_box().dom_node()->is_element() && verify_cast<DOM::Element>(*layout_box().dom_node()).is_focused()) {
         // FIXME: Implement this as `outline` using :focus-visible in the default UA stylesheet to make it possible to override/disable.
-        auto focus_outline_rect = context.enclosing_device_rect(absolute_border_box_rect().to_type<CSSPixels>()).inflated(4, 4);
+        auto focus_outline_rect = context.enclosing_device_rect(absolute_border_box_rect()).inflated(4, 4);
         context.painter().draw_focus_rect(focus_outline_rect.to_type<int>(), context.palette().focus_outline());
     }
 }
@@ -229,14 +231,14 @@ void PaintableBox::paint_border(PaintContext& context) const
         .bottom = computed_values().border_bottom(),
         .left = computed_values().border_left(),
     };
-    paint_all_borders(context, absolute_border_box_rect().to_type<CSSPixels>(), normalized_border_radii_data(), borders_data);
+    paint_all_borders(context, absolute_border_box_rect(), normalized_border_radii_data(), borders_data);
 }
 
 void PaintableBox::paint_backdrop_filter(PaintContext& context) const
 {
     auto& backdrop_filter = computed_values().backdrop_filter();
     if (!backdrop_filter.is_none())
-        Painting::apply_backdrop_filter(context, layout_node(), absolute_border_box_rect().to_type<CSSPixels>(), normalized_border_radii_data(), backdrop_filter);
+        Painting::apply_backdrop_filter(context, layout_node(), absolute_border_box_rect(), normalized_border_radii_data(), backdrop_filter);
 }
 
 void PaintableBox::paint_background(PaintContext& context) const
@@ -260,13 +262,13 @@ void PaintableBox::paint_background(PaintContext& context) const
             background_color = document().background_color(context.palette());
         }
     } else {
-        background_rect = absolute_padding_box_rect().to_type<CSSPixels>();
+        background_rect = absolute_padding_box_rect();
     }
 
     // HACK: If the Box has a border, use the bordered_rect to paint the background.
     //       This way if we have a border-radius there will be no gap between the filling and actual border.
     if (computed_values().border_top().width || computed_values().border_right().width || computed_values().border_bottom().width || computed_values().border_left().width)
-        background_rect = absolute_border_box_rect().to_type<CSSPixels>();
+        background_rect = absolute_border_box_rect();
 
     Painting::paint_background(context, layout_box(), background_rect, background_color, computed_values().image_rendering(), background_layers, normalized_border_radii_data());
 }
@@ -297,13 +299,13 @@ void PaintableBox::paint_box_shadow(PaintContext& context) const
     auto resolved_box_shadow_data = resolve_box_shadow_data();
     if (resolved_box_shadow_data.is_empty())
         return;
-    Painting::paint_box_shadow(context, absolute_border_box_rect().to_type<CSSPixels>(), normalized_border_radii_data(), resolved_box_shadow_data);
+    Painting::paint_box_shadow(context, absolute_border_box_rect(), normalized_border_radii_data(), resolved_box_shadow_data);
 }
 
 BorderRadiiData PaintableBox::normalized_border_radii_data(ShrinkRadiiForBorders shrink) const
 {
     auto border_radius_data = Painting::normalized_border_radii_data(layout_box(),
-        absolute_border_box_rect().to_type<CSSPixels>(),
+        absolute_border_box_rect(),
         computed_values().border_top_left_radius(),
         computed_values().border_top_right_radius(),
         computed_values().border_bottom_right_radius(),
@@ -324,9 +326,9 @@ Optional<Gfx::IntRect> PaintableBox::clip_rect() const
 
         if (overflow_x == CSS::Overflow::Hidden && overflow_y == CSS::Overflow::Hidden) {
             if (m_clip_rect.has_value()) {
-                m_clip_rect->intersect(absolute_padding_box_rect().to_rounded<int>());
+                m_clip_rect->intersect(absolute_padding_box_rect().to_type<float>().to_rounded<int>());
             } else {
-                m_clip_rect = absolute_padding_box_rect().to_rounded<int>();
+                m_clip_rect = absolute_padding_box_rect().to_type<float>().to_rounded<int>();
             }
         }
     }
@@ -407,7 +409,7 @@ static void paint_cursor_if_needed(PaintContext& context, Layout::TextNode const
     if (!fragment.layout_node().dom_node() || !fragment.layout_node().dom_node()->is_editable())
         return;
 
-    auto fragment_rect = fragment.absolute_rect().to_type<CSSPixels>();
+    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())),
@@ -424,7 +426,7 @@ static void paint_cursor_if_needed(PaintContext& context, Layout::TextNode const
 static void paint_text_decoration(PaintContext& context, Gfx::Painter& painter, Layout::Node const& text_node, Layout::LineBoxFragment const& fragment)
 {
     auto& font = fragment.layout_node().font();
-    auto fragment_box = fragment.absolute_rect().to_type<CSSPixels>();
+    auto fragment_box = fragment.absolute_rect();
     CSSPixels glyph_height = font.pixel_size();
     auto baseline = fragment_box.height() / 2 - (glyph_height + 4) / 2 + glyph_height;
 
@@ -507,7 +509,7 @@ static void paint_text_fragment(PaintContext& context, Layout::TextNode const& t
     auto& painter = context.painter();
 
     if (phase == Painting::PaintPhase::Foreground) {
-        auto fragment_absolute_rect = fragment.absolute_rect().to_type<CSSPixels>();
+        auto fragment_absolute_rect = fragment.absolute_rect();
         auto fragment_absolute_device_rect = context.enclosing_device_rect(fragment_absolute_rect);
 
         if (text_node.document().inspected_node() == &text_node.dom_node())
@@ -521,16 +523,16 @@ static void paint_text_fragment(PaintContext& context, Layout::TextNode const& t
         if (text_transform == CSS::TextTransform::Lowercase)
             text = Unicode::to_unicode_lowercase_full(text_node.text_for_rendering());
 
-        DevicePixelPoint baseline_start { fragment_absolute_device_rect.x(), fragment_absolute_device_rect.y() + fragment.baseline() };
+        DevicePixelPoint baseline_start { fragment_absolute_device_rect.x(), fragment_absolute_device_rect.y() + context.rounded_device_pixels(fragment.baseline()) };
         Utf8View view { text.substring_view(fragment.start(), fragment.length()) };
 
         painter.draw_text_run(baseline_start.to_type<int>(), view, fragment.layout_node().font(), text_node.computed_values().color());
 
-        auto selection_rect = fragment.selection_rect(text_node.font());
+        auto selection_rect = context.enclosing_device_rect(fragment.selection_rect(text_node.font())).to_type<int>();
         if (!selection_rect.is_empty()) {
-            painter.fill_rect(enclosing_int_rect(selection_rect), context.palette().selection());
+            painter.fill_rect(selection_rect, context.palette().selection());
             Gfx::PainterStateSaver saver(painter);
-            painter.add_clip_rect(enclosing_int_rect(selection_rect));
+            painter.add_clip_rect(selection_rect);
             painter.draw_text_run(baseline_start.to_type<int>(), view, fragment.layout_node().font(), context.palette().selection_text());
         }
 
@@ -555,7 +557,7 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const
     if (should_clip_overflow) {
         context.painter().save();
         // FIXME: Handle overflow-x and overflow-y being different values.
-        auto clip_box = context.rounded_device_rect(absolute_padding_box_rect().to_type<CSSPixels>());
+        auto clip_box = context.rounded_device_rect(absolute_padding_box_rect());
         context.painter().add_clip_rect(clip_box.to_type<int>());
         auto scroll_offset = static_cast<Layout::BlockContainer const&>(layout_box()).scroll_offset();
         context.painter().translate(-scroll_offset.to_type<int>());
@@ -603,10 +605,10 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const
         for (auto& fragment : line_box.fragments()) {
             if (context.should_show_line_box_borders()) {
                 auto fragment_absolute_rect = fragment.absolute_rect();
-                context.painter().draw_rect(enclosing_int_rect(fragment_absolute_rect), Color::Green);
+                context.painter().draw_rect(context.enclosing_device_rect(fragment_absolute_rect).to_type<int>(), Color::Green);
                 context.painter().draw_line(
-                    fragment_absolute_rect.top_left().translated(0, fragment.baseline()).to_rounded<int>(),
-                    fragment_absolute_rect.top_right().translated(0, fragment.baseline()).to_rounded<int>(), Color::Red);
+                    context.rounded_device_point(fragment_absolute_rect.top_left().translated(0, fragment.baseline())).to_type<int>(),
+                    context.rounded_device_point(fragment_absolute_rect.top_right().translated(0, fragment.baseline())).to_type<int>(), Color::Red);
             }
             if (is<Layout::TextNode>(fragment.layout_node()))
                 paint_text_fragment(context, static_cast<Layout::TextNode const&>(fragment.layout_node()), fragment, phase);
@@ -631,7 +633,7 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const
                     continue;
                 if (parent->is_focused()) {
                     // FIXME: Implement this as `outline` using :focus-visible in the default UA stylesheet to make it possible to override/disable.
-                    auto focus_outline_rect = enclosing_int_rect(fragment.absolute_rect()).inflated(4, 4);
+                    auto focus_outline_rect = context.enclosing_device_rect(fragment.absolute_rect()).to_type<int>().inflated(4, 4);
                     context.painter().draw_focus_rect(focus_outline_rect, context.palette().focus_outline());
                 }
             }
@@ -674,7 +676,7 @@ Optional<HitTestResult> PaintableBox::hit_test(CSSPixelPoint position, HitTestTy
         return stacking_context()->hit_test(position, type);
     }
 
-    if (!absolute_border_box_rect().contains(position.x().value(), position.y().value()))
+    if (!absolute_border_box_rect().contains(position.x(), position.y()))
         return {};
 
     for (auto* child = first_child(); child; child = child->next_sibling()) {
@@ -702,11 +704,11 @@ Optional<HitTestResult> PaintableWithLines::hit_test(CSSPixelPoint position, Hit
                 dbgln("FIXME: PaintableWithLines::hit_test(): Missing containing block on {}", fragment.layout_node().debug_description());
                 continue;
             }
-            auto fragment_absolute_rect = fragment.absolute_rect().to_type<CSSPixels>();
+            auto fragment_absolute_rect = fragment.absolute_rect();
             if (fragment_absolute_rect.contains(position)) {
                 if (is<Layout::BlockContainer>(fragment.layout_node()) && fragment.layout_node().paintable())
                     return fragment.layout_node().paintable()->hit_test(position, type);
-                return HitTestResult { *fragment.layout_node().paintable(), fragment.text_index_at(position.x().value()) };
+                return HitTestResult { *fragment.layout_node().paintable(), fragment.text_index_at(position.x()) };
             }
 
             // If we reached this point, the position is not within the fragment. However, the fragment start or end might be the place to place the cursor.
@@ -730,7 +732,7 @@ Optional<HitTestResult> PaintableWithLines::hit_test(CSSPixelPoint position, Hit
 
     if (type == HitTestType::TextCursor && last_good_candidate.has_value())
         return last_good_candidate;
-    if (is_visible() && absolute_border_box_rect().contains(position.x().value(), position.y().value()))
+    if (is_visible() && absolute_border_box_rect().contains(position.x(), position.y()))
         return HitTestResult { *this };
     return {};
 }

+ 29 - 29
Userland/Libraries/LibWeb/Painting/PaintableBox.h

@@ -28,29 +28,29 @@ public:
     auto const& box_model() const { return layout_box().box_model(); }
 
     struct OverflowData {
-        Gfx::FloatRect scrollable_overflow_rect;
-        Gfx::FloatPoint scroll_offset;
+        CSSPixelRect scrollable_overflow_rect;
+        CSSPixelPoint scroll_offset;
     };
 
-    Gfx::FloatRect absolute_rect() const;
-    Gfx::FloatPoint effective_offset() const;
+    CSSPixelRect absolute_rect() const;
+    CSSPixelPoint effective_offset() const;
 
-    void set_offset(Gfx::FloatPoint);
+    void set_offset(CSSPixelPoint);
     void set_offset(float x, float y) { set_offset({ x, y }); }
 
-    Gfx::FloatSize content_size() const { return m_content_size; }
-    void set_content_size(Gfx::FloatSize);
-    void set_content_size(float width, float height) { set_content_size({ width, height }); }
+    CSSPixelSize const& content_size() const { return m_content_size; }
+    void set_content_size(CSSPixelSize);
+    void set_content_size(CSSPixels width, CSSPixels height) { set_content_size({ width, height }); }
 
-    void set_content_width(float width) { set_content_size(width, content_height()); }
-    void set_content_height(float height) { set_content_size(content_width(), height); }
-    float content_width() const { return m_content_size.width(); }
-    float content_height() const { return m_content_size.height(); }
+    void set_content_width(CSSPixels width) { set_content_size(width, content_height()); }
+    void set_content_height(CSSPixels height) { set_content_size(content_width(), height); }
+    CSSPixels content_width() const { return m_content_size.width(); }
+    CSSPixels content_height() const { return m_content_size.height(); }
 
-    Gfx::FloatRect absolute_padding_box_rect() const
+    CSSPixelRect absolute_padding_box_rect() const
     {
         auto absolute_rect = this->absolute_rect();
-        Gfx::FloatRect rect;
+        CSSPixelRect rect;
         rect.set_x(absolute_rect.x() - box_model().padding.left);
         rect.set_width(content_width() + box_model().padding.left + box_model().padding.right);
         rect.set_y(absolute_rect.y() - box_model().padding.top);
@@ -58,10 +58,10 @@ public:
         return rect;
     }
 
-    Gfx::FloatRect absolute_border_box_rect() const
+    CSSPixelRect absolute_border_box_rect() const
     {
         auto padded_rect = this->absolute_padding_box_rect();
-        Gfx::FloatRect rect;
+        CSSPixelRect rect;
         rect.set_x(padded_rect.x() - box_model().border.left);
         rect.set_width(padded_rect.width() + box_model().border.left + box_model().border.right);
         rect.set_y(padded_rect.y() - box_model().border.top);
@@ -69,27 +69,27 @@ public:
         return rect;
     }
 
-    Gfx::FloatRect absolute_paint_rect() const;
+    CSSPixelRect absolute_paint_rect() const;
 
-    float border_box_width() const
+    CSSPixels border_box_width() const
     {
         auto border_box = box_model().border_box();
         return content_width() + border_box.left + border_box.right;
     }
 
-    float border_box_height() const
+    CSSPixels border_box_height() const
     {
         auto border_box = box_model().border_box();
         return content_height() + border_box.top + border_box.bottom;
     }
 
-    float absolute_x() const { return absolute_rect().x(); }
-    float absolute_y() const { return absolute_rect().y(); }
-    Gfx::FloatPoint absolute_position() const { return absolute_rect().location(); }
+    CSSPixels absolute_x() const { return absolute_rect().x(); }
+    CSSPixels absolute_y() const { return absolute_rect().y(); }
+    CSSPixelPoint absolute_position() const { return absolute_rect().location(); }
 
     bool has_overflow() const { return m_overflow_data.has_value(); }
 
-    Optional<Gfx::FloatRect> scrollable_overflow_rect() const
+    Optional<CSSPixelRect> scrollable_overflow_rect() const
     {
         if (!m_overflow_data.has_value())
             return {};
@@ -129,8 +129,8 @@ protected:
     virtual void paint_background(PaintContext&) const;
     virtual void paint_box_shadow(PaintContext&) const;
 
-    virtual Gfx::FloatRect compute_absolute_rect() const;
-    virtual Gfx::FloatRect compute_absolute_paint_rect() const;
+    virtual CSSPixelRect compute_absolute_rect() const;
+    virtual CSSPixelRect compute_absolute_paint_rect() const;
 
     enum class ShrinkRadiiForBorders {
         Yes,
@@ -144,16 +144,16 @@ protected:
 private:
     Optional<OverflowData> m_overflow_data;
 
-    Gfx::FloatPoint m_offset;
-    Gfx::FloatSize m_content_size;
+    CSSPixelPoint m_offset;
+    CSSPixelSize m_content_size;
 
     // Some boxes hang off of line box fragments. (inline-block, inline-table, replaced, etc)
     Optional<Layout::LineBoxFragmentCoordinate> m_containing_line_box_fragment;
 
     OwnPtr<Painting::StackingContext> m_stacking_context;
 
-    Optional<Gfx::FloatRect> mutable m_absolute_rect;
-    Optional<Gfx::FloatRect> mutable m_absolute_paint_rect;
+    Optional<CSSPixelRect> mutable m_absolute_rect;
+    Optional<CSSPixelRect> mutable m_absolute_paint_rect;
 
     Optional<Gfx::IntRect> mutable m_clip_rect;
 

+ 7 - 4
Userland/Libraries/LibWeb/Painting/ProgressPaintable.cpp

@@ -30,10 +30,13 @@ void ProgressPaintable::paint(PaintContext& context, PaintPhase phase) const
         return;
 
     if (phase == PaintPhase::Foreground) {
-        auto progress_rect = absolute_rect().to_rounded<int>();
-        auto frame_thickness = min(min(progress_rect.width(), progress_rect.height()) / 6, 3);
-        Gfx::StylePainter::paint_progressbar(context.painter(), progress_rect.shrunken(frame_thickness, frame_thickness), context.palette(), 0, round_to<int>(layout_box().dom_node().max()), round_to<int>(layout_box().dom_node().value()), ""sv);
-        Gfx::StylePainter::paint_frame(context.painter(), progress_rect, context.palette(), Gfx::FrameShape::Box, Gfx::FrameShadow::Raised, frame_thickness);
+        auto progress_rect = context.rounded_device_rect(absolute_rect());
+        auto min_frame_thickness = context.rounded_device_pixels(3);
+        auto frame_thickness = min(min(progress_rect.width(), progress_rect.height()) / 6, min_frame_thickness);
+
+        Gfx::StylePainter::paint_progressbar(context.painter(), progress_rect.shrunken(frame_thickness, frame_thickness).to_type<int>(), context.palette(), 0, round_to<int>(layout_box().dom_node().max()), round_to<int>(layout_box().dom_node().value()), ""sv);
+
+        Gfx::StylePainter::paint_frame(context.painter(), progress_rect.to_type<int>(), context.palette(), Gfx::FrameShape::Box, Gfx::FrameShadow::Raised, frame_thickness.value());
     }
 }
 

+ 1 - 1
Userland/Libraries/LibWeb/Painting/RadioButtonPaintable.cpp

@@ -34,7 +34,7 @@ void RadioButtonPaintable::paint(PaintContext& context, PaintPhase phase) const
 
     auto const& radio_box = static_cast<HTML::HTMLInputElement const&>(layout_box().dom_node());
     if (phase == PaintPhase::Foreground)
-        Gfx::StylePainter::paint_radio_button(context.painter(), enclosing_int_rect(absolute_rect()), context.palette(), radio_box.checked(), being_pressed());
+        Gfx::StylePainter::paint_radio_button(context.painter(), context.enclosing_device_rect(absolute_rect()).to_type<int>(), context.palette(), radio_box.checked(), being_pressed());
 }
 
 }

+ 1 - 1
Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp

@@ -47,7 +47,7 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const
     auto const* svg_element = geometry_element.first_ancestor_of_type<SVG::SVGSVGElement>();
     auto maybe_view_box = svg_element->view_box();
 
-    context.painter().add_clip_rect(enclosing_int_rect(absolute_rect()));
+    context.painter().add_clip_rect(context.enclosing_device_rect(absolute_rect()).to_type<int>());
 
     Gfx::Path path = const_cast<SVG::SVGGeometryElement&>(geometry_element).get_path();
 

+ 2 - 2
Userland/Libraries/LibWeb/Painting/SVGPaintable.cpp

@@ -36,10 +36,10 @@ void SVGPaintable::after_children_paint(PaintContext& context, PaintPhase phase)
     context.svg_context().restore();
 }
 
-Gfx::FloatRect SVGPaintable::compute_absolute_rect() const
+CSSPixelRect SVGPaintable::compute_absolute_rect() const
 {
     if (auto* svg_svg_box = layout_box().first_ancestor_of_type<Layout::SVGSVGBox>()) {
-        Gfx::FloatRect rect { effective_offset(), content_size() };
+        CSSPixelRect rect { effective_offset(), content_size() };
         for (Layout::Box const* ancestor = svg_svg_box; ancestor && ancestor->paintable(); ancestor = ancestor->paintable()->containing_block())
             rect.translate_by(ancestor->paint_box()->effective_offset());
         return rect;

+ 1 - 1
Userland/Libraries/LibWeb/Painting/SVGPaintable.h

@@ -21,7 +21,7 @@ public:
 protected:
     SVGPaintable(Layout::SVGBox const&);
 
-    virtual Gfx::FloatRect compute_absolute_rect() const override;
+    virtual CSSPixelRect compute_absolute_rect() const override;
 };
 
 }

+ 1 - 1
Userland/Libraries/LibWeb/Painting/SVGSVGPaintable.cpp

@@ -30,7 +30,7 @@ void SVGSVGPaintable::before_children_paint(PaintContext& context, PaintPhase ph
         return;
 
     if (!context.has_svg_context())
-        context.set_svg_context(SVGContext(absolute_rect()));
+        context.set_svg_context(SVGContext(absolute_rect().to_type<float>()));
 
     PaintableBox::before_children_paint(context, phase);
 }

+ 2 - 2
Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp

@@ -371,14 +371,14 @@ void paint_text_shadow(PaintContext& context, Layout::LineBoxFragment const& fra
         Gfx::Painter shadow_painter { *shadow_bitmap };
         shadow_painter.set_font(context.painter().font());
         // FIXME: "Spread" the shadow somehow.
-        DevicePixelPoint baseline_start(text_rect.x(), text_rect.y() + fragment.baseline());
+        DevicePixelPoint baseline_start(text_rect.x(), text_rect.y() + context.rounded_device_pixels(fragment.baseline()));
         shadow_painter.draw_text_run(baseline_start.to_type<int>(), Utf8View(fragment.text()), context.painter().font(), layer.color);
 
         // Blur
         Gfx::StackBlurFilter filter(*shadow_bitmap);
         filter.process_rgba(blur_radius.value(), layer.color);
 
-        auto draw_rect = context.enclosing_device_rect(fragment.absolute_rect().to_type<CSSPixels>());
+        auto draw_rect = context.enclosing_device_rect(fragment.absolute_rect());
         DevicePixelPoint draw_location {
             draw_rect.x() + offset_x - margin,
             draw_rect.y() + offset_y - margin

+ 4 - 4
Userland/Libraries/LibWeb/Painting/StackingContext.cpp

@@ -357,7 +357,7 @@ void StackingContext::paint(PaintContext& context) const
 
     if (opacity < 1.0f || !affine_transform.is_identity_or_translation()) {
         auto transform_origin = this->transform_origin();
-        auto source_rect = paintable().absolute_paint_rect().translated(-transform_origin);
+        auto source_rect = paintable().absolute_paint_rect().to_type<float>().translated(-transform_origin);
         auto transformed_destination_rect = affine_transform.map(source_rect).translated(transform_origin);
         auto destination_rect = transformed_destination_rect.to_rounded<int>();
 
@@ -366,12 +366,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).
-        Gfx::FloatPoint destination_clipped_fixup {};
+        CSSPixelPoint 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 = Gfx::FloatPoint { destination_rect.location() - actual_destination_rect.location() };
+            destination_clipped_fixup = CSSPixelPoint { 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();
@@ -387,7 +387,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((-paintable().absolute_paint_rect().location() + destination_clipped_fixup).to_rounded<int>());
+        painter.translate(context.rounded_device_point(-paintable().absolute_paint_rect().location() + destination_clipped_fixup).to_type<int>());
         auto paint_context = context.clone(painter);
         paint_internal(paint_context);
 

+ 2 - 2
Userland/Services/WebContent/ConnectionFromClient.cpp

@@ -355,8 +355,8 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect
             MUST(serializer.add("border_bottom"sv, box_model.border.bottom));
             MUST(serializer.add("border_left"sv, box_model.border.left));
             if (auto* paint_box = box->paint_box()) {
-                MUST(serializer.add("content_width"sv, paint_box->content_width()));
-                MUST(serializer.add("content_height"sv, paint_box->content_height()));
+                MUST(serializer.add("content_width"sv, paint_box->content_width().value()));
+                MUST(serializer.add("content_height"sv, paint_box->content_height().value()));
             } else {
                 MUST(serializer.add("content_width"sv, 0));
                 MUST(serializer.add("content_height"sv, 0));

+ 2 - 2
Userland/Services/WebContent/PageHost.cpp

@@ -152,9 +152,9 @@ void PageHost::page_did_layout()
     auto* layout_root = this->layout_root();
     VERIFY(layout_root);
     if (layout_root->paint_box()->has_overflow())
-        m_content_size = page().enclosing_device_rect(layout_root->paint_box()->scrollable_overflow_rect().value().to_type<Web::CSSPixels>()).size();
+        m_content_size = page().enclosing_device_rect(layout_root->paint_box()->scrollable_overflow_rect().value()).size();
     else
-        m_content_size = page().enclosing_device_rect(layout_root->paint_box()->absolute_rect().to_type<Web::CSSPixels>()).size();
+        m_content_size = page().enclosing_device_rect(layout_root->paint_box()->absolute_rect()).size();
     m_client.async_did_layout(m_content_size.to_type<int>());
 }