From 137f6d44ec43706c987eb5933b95458f407c3b42 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 12 Jun 2020 14:19:03 +0200 Subject: [PATCH] LibWeb: Add basic support for position:fixed Fixed position elements have the ICB as their containing block. The magic of fixed positioning is implemented at the rendering stage, where we temporarily translate painting by the current scroll offset. Note that "absolutely positioned" includes both position:absolute and position:fixed. --- Libraries/LibWeb/Layout/LayoutBlock.cpp | 7 +++---- Libraries/LibWeb/Layout/LayoutBlock.h | 2 +- Libraries/LibWeb/Layout/LayoutBox.cpp | 4 ++++ Libraries/LibWeb/Layout/LayoutDocument.cpp | 2 +- Libraries/LibWeb/Layout/LayoutNode.cpp | 14 +++++++++++--- Libraries/LibWeb/Layout/LayoutNode.h | 1 + Libraries/LibWeb/PageView.cpp | 2 +- Libraries/LibWeb/RenderingContext.h | 6 +++++- 8 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Libraries/LibWeb/Layout/LayoutBlock.cpp b/Libraries/LibWeb/Layout/LayoutBlock.cpp index e1a2b66a30d..fb5125a6c55 100644 --- a/Libraries/LibWeb/Layout/LayoutBlock.cpp +++ b/Libraries/LibWeb/Layout/LayoutBlock.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -67,10 +68,10 @@ void LayoutBlock::layout(LayoutMode layout_mode) compute_height(); if (layout_mode == LayoutMode::Default) - layout_absolute_descendants(); + layout_absolutely_positioned_descendants(); } -void LayoutBlock::layout_absolute_descendants() +void LayoutBlock::layout_absolutely_positioned_descendants() { for (auto& box : m_absolutely_positioned_descendants) { box->layout(LayoutMode::Default); @@ -441,9 +442,7 @@ void LayoutBlock::compute_width() void LayoutBlock::compute_position() { - // Absolutely positioned blocks are positioned by position_absolute_boxes() if (is_absolutely_positioned()) { - dbg() << "Is abspos, adding to containing block " << containing_block()->node()->tag_name(); const_cast(containing_block())->add_absolutely_positioned_descendant(*this); return; } diff --git a/Libraries/LibWeb/Layout/LayoutBlock.h b/Libraries/LibWeb/Layout/LayoutBlock.h index a55dff6fdb7..52e45d50245 100644 --- a/Libraries/LibWeb/Layout/LayoutBlock.h +++ b/Libraries/LibWeb/Layout/LayoutBlock.h @@ -72,7 +72,7 @@ protected: void compute_width(); void compute_position(); void compute_height(); - void layout_absolute_descendants(); + void layout_absolutely_positioned_descendants(); private: virtual bool is_block() const override { return true; } diff --git a/Libraries/LibWeb/Layout/LayoutBox.cpp b/Libraries/LibWeb/Layout/LayoutBox.cpp index 3f6223da30c..2f642b437b4 100644 --- a/Libraries/LibWeb/Layout/LayoutBox.cpp +++ b/Libraries/LibWeb/Layout/LayoutBox.cpp @@ -194,6 +194,10 @@ void LayoutBox::render(RenderingContext& context) if (!is_visible()) return; + Gfx::PainterStateSaver saver(context.painter()); + if (is_fixed_position()) + context.painter().translate(context.scroll_offset()); + #ifdef DRAW_BOXES_AROUND_LAYOUT_NODES context.painter().draw_rect(m_rect, Color::Blue); #endif diff --git a/Libraries/LibWeb/Layout/LayoutDocument.cpp b/Libraries/LibWeb/Layout/LayoutDocument.cpp index 6bc016940f6..646344b054a 100644 --- a/Libraries/LibWeb/Layout/LayoutDocument.cpp +++ b/Libraries/LibWeb/Layout/LayoutDocument.cpp @@ -58,7 +58,7 @@ void LayoutDocument::layout(LayoutMode layout_mode) }); set_height(lowest_bottom); - layout_absolute_descendants(); + layout_absolutely_positioned_descendants(); // FIXME: This is a total hack. Make sure any GUI::Widgets are moved into place after layout. // We should stop embedding GUI::Widgets entirely, since that won't work out-of-process. diff --git a/Libraries/LibWeb/Layout/LayoutNode.cpp b/Libraries/LibWeb/Layout/LayoutNode.cpp index b19e064616b..95c0ef31055 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.cpp +++ b/Libraries/LibWeb/Layout/LayoutNode.cpp @@ -72,7 +72,9 @@ const LayoutBlock* LayoutNode::containing_block() const if (is_text()) return nearest_block_ancestor(); - if (is_absolutely_positioned()) { + auto position = style().position(); + + if (position == CSS::Position::Absolute) { auto* ancestor = parent(); while (ancestor && !ancestor->can_contain_boxes_with_position_absolute()) ancestor = ancestor->parent(); @@ -81,7 +83,7 @@ const LayoutBlock* LayoutNode::containing_block() const return to(ancestor); } - if (style().position() == CSS::Position::Fixed) + if (position == CSS::Position::Fixed) return &root(); return nearest_block_ancestor(); @@ -189,7 +191,13 @@ Gfx::FloatPoint LayoutNode::box_type_agnostic_position() const bool LayoutNode::is_absolutely_positioned() const { - return style().position() == CSS::Position::Absolute; + auto position = style().position(); + return position == CSS::Position::Absolute || position == CSS::Position::Fixed; +} + +bool LayoutNode::is_fixed_position() const +{ + return style().position() == CSS::Position::Fixed; } } diff --git a/Libraries/LibWeb/Layout/LayoutNode.h b/Libraries/LibWeb/Layout/LayoutNode.h index 2c4357b9bcf..4fb6b03076b 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.h +++ b/Libraries/LibWeb/Layout/LayoutNode.h @@ -171,6 +171,7 @@ public: virtual void render(RenderingContext&); bool is_absolutely_positioned() const; + bool is_fixed_position() const; const LayoutBlock* containing_block() const; diff --git a/Libraries/LibWeb/PageView.cpp b/Libraries/LibWeb/PageView.cpp index f660940c5ea..273ad024b31 100644 --- a/Libraries/LibWeb/PageView.cpp +++ b/Libraries/LibWeb/PageView.cpp @@ -207,7 +207,7 @@ void PageView::paint_event(GUI::PaintEvent& event) painter.translate(frame_thickness(), frame_thickness()); painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); - RenderingContext context(painter, palette()); + RenderingContext context(painter, palette(), { horizontal_scrollbar().value(), vertical_scrollbar().value() }); context.set_should_show_line_box_borders(m_should_show_line_box_borders); context.set_viewport_rect(viewport_rect_in_content_coordinates()); layout_root()->render(context); diff --git a/Libraries/LibWeb/RenderingContext.h b/Libraries/LibWeb/RenderingContext.h index 2c6e69c9df0..283b634fec4 100644 --- a/Libraries/LibWeb/RenderingContext.h +++ b/Libraries/LibWeb/RenderingContext.h @@ -34,9 +34,10 @@ namespace Web { class RenderingContext { public: - explicit RenderingContext(GUI::Painter& painter, const Palette& palette) + explicit RenderingContext(GUI::Painter& painter, const Palette& palette, const Gfx::IntPoint& scroll_offset) : m_painter(painter) , m_palette(palette) + , m_scroll_offset(scroll_offset) { } @@ -49,10 +50,13 @@ public: Gfx::IntRect viewport_rect() const { return m_viewport_rect; } void set_viewport_rect(const Gfx::IntRect& rect) { m_viewport_rect = rect; } + const Gfx::IntPoint& scroll_offset() const { return m_scroll_offset; } + private: GUI::Painter& m_painter; Palette m_palette; Gfx::IntRect m_viewport_rect; + Gfx::IntPoint m_scroll_offset; bool m_should_show_line_box_borders { false }; };