From 7fcf61be358180365fb950fe7ba4f68314e39cad Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 5 Jun 2020 16:54:28 +0200 Subject: [PATCH] LibWeb: Improve computation of a layout node's containing block In particular, we now compute the containing block of boxes with position:absolute and position:fixed (more) correctly. --- Libraries/LibWeb/Layout/LayoutDocument.h | 2 ++ Libraries/LibWeb/Layout/LayoutNode.cpp | 39 +++++++++++++++++++++--- Libraries/LibWeb/Layout/LayoutNode.h | 7 ++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/Libraries/LibWeb/Layout/LayoutDocument.h b/Libraries/LibWeb/Layout/LayoutDocument.h index c89353b8ca..542b415818 100644 --- a/Libraries/LibWeb/Layout/LayoutDocument.h +++ b/Libraries/LibWeb/Layout/LayoutDocument.h @@ -45,6 +45,8 @@ public: void did_set_viewport_rect(Badge, const Gfx::Rect&); + virtual bool is_root() const override { return true; } + private: LayoutRange m_selection; }; diff --git a/Libraries/LibWeb/Layout/LayoutNode.cpp b/Libraries/LibWeb/Layout/LayoutNode.cpp index 678e49b8b9..cbcfd4d7f6 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.cpp +++ b/Libraries/LibWeb/Layout/LayoutNode.cpp @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include namespace Web { @@ -53,13 +55,36 @@ void LayoutNode::layout(LayoutMode layout_mode) }); } +bool LayoutNode::can_contain_boxes_with_position_absolute() const +{ + return style().position() != CSS::Position::Static || is_root(); +} + const LayoutBlock* LayoutNode::containing_block() const { - for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { - if (is(*ancestor)) - return to(ancestor); + if (is_text()) { + auto* ancestor = parent(); + while (ancestor && ((ancestor->is_inline() && !is(*ancestor)) || !is(*ancestor))) + ancestor = ancestor->parent(); + return to(ancestor); } - return nullptr; + + if (is_absolutely_positioned()) { + auto* ancestor = parent(); + while (ancestor && !ancestor->can_contain_boxes_with_position_absolute()) + ancestor = ancestor->parent(); + while (ancestor && (!is(ancestor) || ancestor->is_anonymous())) + ancestor = ancestor->containing_block(); + return to(ancestor); + } + + if (style().position() == CSS::Position::Fixed) + return &root(); + + auto* ancestor = parent(); + while (ancestor && ((ancestor->is_inline() && !is(*ancestor)) || !is(*ancestor))) + ancestor = ancestor->parent(); + return to(ancestor); } void LayoutNode::render(RenderingContext& context) @@ -155,4 +180,10 @@ Gfx::FloatPoint LayoutNode::box_type_agnostic_position() const return position; } +bool LayoutNode::is_absolutely_positioned() const +{ + return style().position() == CSS::Position::Absolute; +} + + } diff --git a/Libraries/LibWeb/Layout/LayoutNode.h b/Libraries/LibWeb/Layout/LayoutNode.h index b9a5adbb13..8c31244e9c 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.h +++ b/Libraries/LibWeb/Layout/LayoutNode.h @@ -81,7 +81,8 @@ public: callback(*node); } - virtual const char* class_name() const { return "LayoutNode"; } + virtual const char* class_name() const = 0; + virtual bool is_root() const { return false; } virtual bool is_text() const { return false; } virtual bool is_block() const { return false; } virtual bool is_replaced() const { return false; } @@ -108,8 +109,12 @@ public: virtual void layout(LayoutMode); virtual void render(RenderingContext&); + bool is_absolutely_positioned() const; + const LayoutBlock* containing_block() const; + bool can_contain_boxes_with_position_absolute() const; + virtual LayoutNode& inline_wrapper() { return *this; } const StyleProperties& style() const;