diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 6727d9444b..e492ef57b1 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -571,20 +571,24 @@ void BlockFormattingContext::layout_initial_containing_block(LayoutMode layout_m icb.build_stacking_context_tree(); icb.set_width(viewport_rect.width()); - - layout_block_level_children(root(), layout_mode); + icb.set_height(viewport_rect.height()); VERIFY(!icb.children_are_inline()); + layout_block_level_children(root(), layout_mode); - // FIXME: The ICB should have the height of the viewport. - // Instead of auto-sizing the ICB, we should spill into overflow. + // Compute scrollable overflow. float lowest_bottom = 0; icb.for_each_child_of_type([&](auto& child) { lowest_bottom = max(lowest_bottom, child.absolute_rect().bottom()); }); - // FIXME: This is a hack and should be managed by an overflow mechanism. - icb.set_height(max(static_cast(viewport_rect.height()), lowest_bottom)); + if (lowest_bottom >= viewport_rect.height()) { + auto& overflow_data = icb.ensure_overflow_data(); + overflow_data.scrollable_overflow_rect = viewport_rect.to_type(); + overflow_data.scrollable_overflow_rect.set_height(lowest_bottom); + } else { + icb.clear_overflow_data(); + } } static Gfx::FloatRect rect_in_coordinate_space(const Box& box, const Box& context_box) diff --git a/Userland/Libraries/LibWeb/Layout/Box.h b/Userland/Libraries/LibWeb/Layout/Box.h index 1841af67c1..914157c42d 100644 --- a/Userland/Libraries/LibWeb/Layout/Box.h +++ b/Userland/Libraries/LibWeb/Layout/Box.h @@ -16,6 +16,11 @@ namespace Web::Layout { class Box : public NodeWithStyleAndBoxModelMetrics { public: + struct OverflowData { + Gfx::FloatRect scrollable_overflow_rect; + Gfx::FloatPoint scroll_offset; + }; + const Gfx::FloatRect absolute_rect() const; Gfx::FloatPoint effective_offset() const; @@ -129,6 +134,24 @@ public: bool has_intrinsic_height() const { return intrinsic_height().has_value(); } bool has_intrinsic_aspect_ratio() const { return intrinsic_aspect_ratio().has_value(); } + bool has_overflow() const { return m_overflow_data; } + + Optional scrollable_overflow_rect() const + { + if (!m_overflow_data) + return {}; + return m_overflow_data->scrollable_overflow_rect; + } + + OverflowData& ensure_overflow_data() + { + if (!m_overflow_data) + m_overflow_data = make(); + return *m_overflow_data; + } + + void clear_overflow_data() { m_overflow_data = nullptr; } + protected: Box(DOM::Document& document, DOM::Node* node, NonnullRefPtr style) : NodeWithStyleAndBoxModelMetrics(document, node, move(style)) @@ -152,6 +175,8 @@ private: WeakPtr m_containing_line_box_fragment; OwnPtr m_stacking_context; + + OwnPtr m_overflow_data; }; template<> diff --git a/Userland/Services/WebContent/PageHost.cpp b/Userland/Services/WebContent/PageHost.cpp index 0414a88044..31cccb5ac1 100644 --- a/Userland/Services/WebContent/PageHost.cpp +++ b/Userland/Services/WebContent/PageHost.cpp @@ -102,7 +102,11 @@ void PageHost::page_did_layout() { auto* layout_root = this->layout_root(); VERIFY(layout_root); - auto content_size = enclosing_int_rect(layout_root->absolute_rect()).size(); + Gfx::IntSize content_size; + if (layout_root->has_overflow()) + content_size = enclosing_int_rect(layout_root->scrollable_overflow_rect().value()).size(); + else + content_size = enclosing_int_rect(layout_root->absolute_rect()).size(); m_client.async_did_layout(content_size); }