diff options
-rw-r--r-- | Base/home/anon/www/position-absolute-from-edges.html | 48 | ||||
-rw-r--r-- | Base/home/anon/www/welcome.html | 1 | ||||
-rw-r--r-- | Libraries/LibWeb/Dump.cpp | 5 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/BoxModelMetrics.cpp | 20 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/BoxModelMetrics.h | 2 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutBlock.cpp | 103 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutBlock.h | 5 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutDocument.cpp | 2 |
8 files changed, 164 insertions, 22 deletions
diff --git a/Base/home/anon/www/position-absolute-from-edges.html b/Base/home/anon/www/position-absolute-from-edges.html new file mode 100644 index 0000000000..e04ddf71cc --- /dev/null +++ b/Base/home/anon/www/position-absolute-from-edges.html @@ -0,0 +1,48 @@ +<style> +#container { + position: absolute; + width: 500px; + height: 400px; + border: 1px solid black; +} +#red { + position: absolute; + left: 20px; + top: 20px; + background: red; + width: 100px; + height: 100px; + border: 10px solid gray; +} +#green { + position: absolute; + right: 20px; + top: 20px; + background: green; + width: 100px; + height: 100px; + margin: 50px; +} +#blue { + position: absolute; + left: 20px; + bottom: 20px; + background: blue; + width: 100px; + height: 100px; +} +#yellow { + position: absolute; + right: 20px; + bottom: 20px; + background: yellow; + width: 100px; + height: 100px; +} +</style> +<div id=container> + <div id=red></div> + <div id=green></div> + <div id=blue></div> + <div id=yellow></div> +</div> diff --git a/Base/home/anon/www/welcome.html b/Base/home/anon/www/welcome.html index cfbaca3176..19306ae8cd 100644 --- a/Base/home/anon/www/welcome.html +++ b/Base/home/anon/www/welcome.html @@ -28,6 +28,7 @@ span#ua { <p>Your user agent is: <b><span id="ua"></span></b></p> <p>Some small test pages:</p> <ul> + <li><a href="position-absolute-from-edges.html">position: absolute, offset from edges</a></li> <li><a href="iframe.html">iframe</a></li> <li><a href="many-buggies.html">many buggies</a></li> <li><a href="palette.html">system palette color css extension</a></li> diff --git a/Libraries/LibWeb/Dump.cpp b/Libraries/LibWeb/Dump.cpp index eba734220e..46f2c74302 100644 --- a/Libraries/LibWeb/Dump.cpp +++ b/Libraries/LibWeb/Dump.cpp @@ -145,6 +145,11 @@ void dump_tree(const LayoutNode& layout_node) if (layout_node.is_block() && static_cast<const LayoutBlock&>(layout_node).children_are_inline()) { auto& block = static_cast<const LayoutBlock&>(layout_node); + if (block.absolutely_positioned_descendant_count()) { + for (size_t i = 0; i < indent; ++i) + dbgprintf(" "); + dbgprintf(" %zu absolutely positioned descendant(s) tracked here\n", block.absolutely_positioned_descendant_count()); + } for (size_t i = 0; i < indent; ++i) dbgprintf(" "); dbgprintf(" Line boxes (%d):\n", block.line_boxes().size()); diff --git a/Libraries/LibWeb/Layout/BoxModelMetrics.cpp b/Libraries/LibWeb/Layout/BoxModelMetrics.cpp index c937918eaf..5843783ae7 100644 --- a/Libraries/LibWeb/Layout/BoxModelMetrics.cpp +++ b/Libraries/LibWeb/Layout/BoxModelMetrics.cpp @@ -46,4 +46,24 @@ BoxModelMetrics::PixelBox BoxModelMetrics::full_margin(const LayoutNode& layout_ }; } +BoxModelMetrics::PixelBox BoxModelMetrics::padding_box(const LayoutNode& layout_node) const +{ + return { + m_padding.top.to_px(layout_node), + m_padding.right.to_px(layout_node), + m_padding.bottom.to_px(layout_node), + m_padding.left.to_px(layout_node), + }; +} + +BoxModelMetrics::PixelBox BoxModelMetrics::border_box(const LayoutNode& layout_node) const +{ + return { + m_border.top.to_px(layout_node) + m_padding.top.to_px(layout_node), + m_border.right.to_px(layout_node) + m_padding.right.to_px(layout_node), + m_border.bottom.to_px(layout_node) + m_padding.bottom.to_px(layout_node), + m_border.left.to_px(layout_node) + m_padding.left.to_px(layout_node), + }; +} + } diff --git a/Libraries/LibWeb/Layout/BoxModelMetrics.h b/Libraries/LibWeb/Layout/BoxModelMetrics.h index 3a699c0f4a..40bc014cf6 100644 --- a/Libraries/LibWeb/Layout/BoxModelMetrics.h +++ b/Libraries/LibWeb/Layout/BoxModelMetrics.h @@ -54,6 +54,8 @@ public: }; PixelBox full_margin(const LayoutNode&) const; + PixelBox padding_box(const LayoutNode&) const; + PixelBox border_box(const LayoutNode&) const; private: LengthBox m_margin; diff --git a/Libraries/LibWeb/Layout/LayoutBlock.cpp b/Libraries/LibWeb/Layout/LayoutBlock.cpp index ff43ca236e..bc7d7f3191 100644 --- a/Libraries/LibWeb/Layout/LayoutBlock.cpp +++ b/Libraries/LibWeb/Layout/LayoutBlock.cpp @@ -27,6 +27,7 @@ #include <LibGUI/Painter.h> #include <LibWeb/CSS/StyleResolver.h> #include <LibWeb/DOM/Element.h> +#include <LibWeb/Dump.h> #include <LibWeb/Layout/LayoutBlock.h> #include <LibWeb/Layout/LayoutInline.h> #include <LibWeb/Layout/LayoutReplaced.h> @@ -64,6 +65,69 @@ void LayoutBlock::layout(LayoutMode layout_mode) layout_children(layout_mode); compute_height(); + + if (layout_mode == LayoutMode::Default) + layout_absolute_descendants(); +} + +void LayoutBlock::layout_absolute_descendants() +{ + for (auto& box : m_absolutely_positioned_descendants) { + box->layout(LayoutMode::Default); + auto& box_model = box->box_model(); + auto& style = box->style(); + auto zero_value = Length(0, Length::Type::Px); + + auto specified_width = style.length_or_fallback(CSS::PropertyID::Width, Length(), width()); + + box_model.margin().top = style.length_or_fallback(CSS::PropertyID::MarginTop, {}, height()); + box_model.margin().right = style.length_or_fallback(CSS::PropertyID::MarginRight, {}, width()); + box_model.margin().bottom = style.length_or_fallback(CSS::PropertyID::MarginBottom, {}, height()); + box_model.margin().left = style.length_or_fallback(CSS::PropertyID::MarginLeft, {}, width()); + + box_model.offset().top = style.length_or_fallback(CSS::PropertyID::Top, {}, height()); + box_model.offset().right = style.length_or_fallback(CSS::PropertyID::Right, {}, width()); + box_model.offset().bottom = style.length_or_fallback(CSS::PropertyID::Bottom, {}, height()); + box_model.offset().left = style.length_or_fallback(CSS::PropertyID::Left, {}, width()); + + if (box_model.offset().left.is_auto() && specified_width.is_auto() && box_model.offset().right.is_auto()) { + if (box_model.margin().left.is_auto()) + box_model.margin().left = zero_value; + if (box_model.margin().right.is_auto()) + box_model.margin().right = zero_value; + } + + Gfx::FloatPoint used_offset; + + float x_offset = box_model.offset().left.to_px(*box) + + box_model.border_box(*box).left + - box_model.offset().right.to_px(*box) + - box_model.border_box(*box).right; + + float y_offset = box_model.offset().top.to_px(*box) + + box_model.border_box(*box).top + - box_model.offset().bottom.to_px(*box) + - box_model.border_box(*box).bottom; + + if (!box_model.offset().left.is_auto()) { + used_offset.set_x(x_offset + box_model.margin().left.to_px(*box)); + } else if (!box_model.offset().right.is_auto()) { + used_offset.set_x(width() + x_offset - box->width() - box_model.margin().right.to_px(*box)); + } + + if (!box_model.offset().top.is_auto()) { + used_offset.set_y(y_offset + box_model.margin().top.to_px(*box)); + } else if (!box_model.offset().bottom.is_auto()) { + used_offset.set_y(height() + y_offset - box->height() - box_model.margin().bottom.to_px(*box)); + } + + box->set_offset(used_offset); + } +} + +void LayoutBlock::add_absolutely_positioned_descendant(LayoutBox& box) +{ + m_absolutely_positioned_descendants.set(box); } void LayoutBlock::layout_children(LayoutMode layout_mode) @@ -377,19 +441,17 @@ void LayoutBlock::compute_width() void LayoutBlock::compute_position() { - auto& style = this->style(); + // 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<LayoutBlock*>(containing_block())->add_absolutely_positioned_descendant(*this); + return; + } + auto& style = this->style(); auto zero_value = Length(0, Length::Type::Px); - auto& containing_block = *this->containing_block(); - if (style.position() == CSS::Position::Absolute) { - box_model().offset().top = style.length_or_fallback(CSS::PropertyID::Top, zero_value, containing_block.height()); - box_model().offset().right = style.length_or_fallback(CSS::PropertyID::Right, zero_value, containing_block.width()); - box_model().offset().bottom = style.length_or_fallback(CSS::PropertyID::Bottom, zero_value, containing_block.height()); - box_model().offset().left = style.length_or_fallback(CSS::PropertyID::Left, zero_value, containing_block.width()); - } - box_model().margin().top = style.length_or_fallback(CSS::PropertyID::MarginTop, zero_value, containing_block.width()); box_model().margin().bottom = style.length_or_fallback(CSS::PropertyID::MarginBottom, zero_value, containing_block.width()); box_model().border().top = style.length_or_fallback(CSS::PropertyID::BorderTopWidth, zero_value); @@ -405,19 +467,17 @@ void LayoutBlock::compute_position() float position_y = box_model().full_margin(*this).top + box_model().offset().top.to_px(*this); - if (style.position() != CSS::Position::Absolute || containing_block.style().position() == CSS::Position::Absolute) { - LayoutBlock* relevant_sibling = previous_sibling(); - while (relevant_sibling != nullptr) { - if (relevant_sibling->style().position() != CSS::Position::Absolute) - break; - relevant_sibling = relevant_sibling->previous_sibling(); - } + LayoutBlock* relevant_sibling = previous_sibling(); + while (relevant_sibling != nullptr) { + if (relevant_sibling->style().position() != CSS::Position::Absolute) + break; + relevant_sibling = relevant_sibling->previous_sibling(); + } - if (relevant_sibling) { - auto& previous_sibling_style = relevant_sibling->box_model(); - position_y += relevant_sibling->effective_offset().y() + relevant_sibling->height(); - position_y += previous_sibling_style.full_margin(*this).bottom; - } + if (relevant_sibling) { + auto& previous_sibling_style = relevant_sibling->box_model(); + position_y += relevant_sibling->effective_offset().y() + relevant_sibling->height(); + position_y += previous_sibling_style.full_margin(*this).bottom; } set_offset({ position_x, position_y }); @@ -430,7 +490,6 @@ void LayoutBlock::compute_height() auto specified_height = style.length_or_fallback(CSS::PropertyID::Height, Length(), containing_block()->height()); auto specified_max_height = style.length_or_fallback(CSS::PropertyID::MaxHeight, Length(), containing_block()->height()); - if (!specified_height.is_auto()) { float used_height = specified_height.to_px(*this); if (!specified_max_height.is_auto()) diff --git a/Libraries/LibWeb/Layout/LayoutBlock.h b/Libraries/LibWeb/Layout/LayoutBlock.h index af1ab548bf..a55dff6fdb 100644 --- a/Libraries/LibWeb/Layout/LayoutBlock.h +++ b/Libraries/LibWeb/Layout/LayoutBlock.h @@ -65,10 +65,14 @@ public: virtual void split_into_lines(LayoutBlock& container, LayoutMode) override; + void add_absolutely_positioned_descendant(LayoutBox&); + size_t absolutely_positioned_descendant_count() const { return m_absolutely_positioned_descendants.size(); } + protected: void compute_width(); void compute_position(); void compute_height(); + void layout_absolute_descendants(); private: virtual bool is_block() const override { return true; } @@ -80,6 +84,7 @@ private: void layout_block_children(LayoutMode); Vector<LineBox> m_line_boxes; + HashTable<RefPtr<LayoutBox>> m_absolutely_positioned_descendants; }; template<typename Callback> diff --git a/Libraries/LibWeb/Layout/LayoutDocument.cpp b/Libraries/LibWeb/Layout/LayoutDocument.cpp index ea81093724..6bc016940f 100644 --- a/Libraries/LibWeb/Layout/LayoutDocument.cpp +++ b/Libraries/LibWeb/Layout/LayoutDocument.cpp @@ -58,6 +58,8 @@ void LayoutDocument::layout(LayoutMode layout_mode) }); set_height(lowest_bottom); + layout_absolute_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. for_each_in_subtree_of_type<LayoutWidget>([&](auto& widget) { |