diff options
-rw-r--r-- | Libraries/LibWeb/Dump.cpp | 5 | ||||
-rw-r--r-- | Libraries/LibWeb/Forward.h | 1 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutBlock.cpp | 239 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutBlock.h | 13 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutBox.h | 2 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutReplaced.cpp | 34 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutReplaced.h | 1 | ||||
-rw-r--r-- | Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp | 3 |
8 files changed, 140 insertions, 158 deletions
diff --git a/Libraries/LibWeb/Dump.cpp b/Libraries/LibWeb/Dump.cpp index 99b12ead93..46d1c2898c 100644 --- a/Libraries/LibWeb/Dump.cpp +++ b/Libraries/LibWeb/Dump.cpp @@ -146,11 +146,6 @@ 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/Forward.h b/Libraries/LibWeb/Forward.h index d3f7b19cf1..ee2a02b7cd 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -53,6 +53,7 @@ class LayoutBlock; class LayoutDocument; class LayoutNode; class LayoutNodeWithStyle; +class LayoutReplaced; class LoadRequest; class MouseEvent; class Node; diff --git a/Libraries/LibWeb/Layout/LayoutBlock.cpp b/Libraries/LibWeb/Layout/LayoutBlock.cpp index dc41250d06..c9667bd1c3 100644 --- a/Libraries/LibWeb/Layout/LayoutBlock.cpp +++ b/Libraries/LibWeb/Layout/LayoutBlock.cpp @@ -59,103 +59,107 @@ LayoutNode& LayoutBlock::inline_wrapper() void LayoutBlock::layout(LayoutMode layout_mode) { compute_width(); - - if (!is_inline()) - compute_position(); - - layout_children(layout_mode); - + layout_inside(layout_mode); compute_height(); - if (layout_mode == LayoutMode::Default) - layout_absolutely_positioned_descendants(); + layout_absolutely_positioned_descendants(); } -void LayoutBlock::layout_absolutely_positioned_descendants() +void LayoutBlock::layout_absolutely_positioned_descendant(LayoutBox& box) { - 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; - } + box.layout(LayoutMode::Default); + auto& box_model = box.box_model(); + auto& style = box.style(); + auto zero_value = Length(0, Length::Type::Px); - Gfx::FloatPoint used_offset; + auto specified_width = style.length_or_fallback(CSS::PropertyID::Width, Length(), width()); - 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; + 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()); - 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; + 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()) { - 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().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; + } - 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)); - } + 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; - box->set_offset(used_offset); + 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)); } -} -void LayoutBlock::add_absolutely_positioned_descendant(LayoutBox& box) -{ - m_absolutely_positioned_descendants.set(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::layout_children(LayoutMode layout_mode) +void LayoutBlock::layout_inside(LayoutMode layout_mode) { if (children_are_inline()) layout_inline_children(layout_mode); else - layout_block_children(layout_mode); + layout_contained_boxes(layout_mode); } -void LayoutBlock::layout_block_children(LayoutMode layout_mode) +void LayoutBlock::layout_absolutely_positioned_descendants() +{ + for_each_in_subtree_of_type<LayoutBox>([&](auto& box) { + if (box.is_absolutely_positioned() && box.containing_block() == this) { + layout_absolutely_positioned_descendant(box); + } + return IterationDecision::Continue; + }); +} + +void LayoutBlock::layout_contained_boxes(LayoutMode layout_mode) { - ASSERT(!children_are_inline()); float content_height = 0; - for_each_child_of_type<LayoutBlock>([&](auto& child) { - child.layout(layout_mode); - if (!child.is_absolutely_positioned()) - content_height = max(content_height, child.effective_offset().y() + child.height() + child.box_model().margin_box(*this).bottom); + float content_width = 0; + for_each_in_subtree_of_type<LayoutBox>([&](auto& box) { + if (box.is_absolutely_positioned() || box.containing_block() != this) + return IterationDecision::Continue; + box.layout(layout_mode); + if (box.is_replaced()) + place_block_level_replaced_element_in_normal_flow(to<LayoutReplaced>(box)); + else if (box.is_block()) + place_block_level_non_replaced_element_in_normal_flow(to<LayoutBlock>(box)); + else { + dbg() << "FIXME: How do I place a " << box.class_name() << "?"; + ASSERT_NOT_REACHED(); + } + content_height = max(content_height, box.effective_offset().y() + box.height() + box.box_model().margin_box(*this).bottom); + content_width = max(content_width, to<LayoutBox>(box).width()); + return IterationDecision::Continue; }); - if (layout_mode != LayoutMode::Default) { - float max_width = 0; - for_each_child([&](auto& child) { - if (child.is_box() && !child.is_absolutely_positioned()) - max_width = max(max_width, to<LayoutBox>(child).width()); - }); - set_width(max_width); - } + + if (layout_mode != LayoutMode::Default) + set_width(content_width); + set_height(content_height); } @@ -165,10 +169,8 @@ void LayoutBlock::layout_inline_children(LayoutMode layout_mode) m_line_boxes.clear(); for_each_child([&](auto& child) { ASSERT(child.is_inline()); - if (child.is_box() && child.is_absolutely_positioned()) { - const_cast<LayoutBlock*>(child.containing_block())->add_absolutely_positioned_descendant((LayoutBox&)child); + if (child.is_absolutely_positioned()) return; - } child.split_into_lines(*this, layout_mode); }); @@ -376,13 +378,13 @@ void LayoutBlock::compute_width() // Calculate the preferred width by formatting the content without breaking lines // other than where explicit line breaks occur. - layout_children(LayoutMode::OnlyRequiredLineBreaks); + layout_inside(LayoutMode::OnlyRequiredLineBreaks); float preferred_width = greatest_child_width(); // Also calculate the preferred minimum width, e.g., by trying all possible line breaks. // CSS 2.2 does not define the exact algorithm. - layout_children(LayoutMode::AllPossibleLineBreaks); + layout_inside(LayoutMode::AllPossibleLineBreaks); float preferred_minimum_width = greatest_child_width(); // Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width). @@ -425,37 +427,58 @@ void LayoutBlock::compute_width() box_model().padding().right = padding_right; } -void LayoutBlock::compute_position() +void LayoutBlock::place_block_level_replaced_element_in_normal_flow(LayoutReplaced& box) { - if (is_absolutely_positioned()) { - const_cast<LayoutBlock*>(containing_block())->add_absolutely_positioned_descendant(*this); - return; - } - - auto& style = this->style(); + ASSERT(!is_absolutely_positioned()); + auto& style = box.style(); auto zero_value = Length(0, Length::Type::Px); - auto& containing_block = *this->containing_block(); + auto& containing_block = *this; + auto& replaced_element_box_model = box.box_model(); + + replaced_element_box_model.margin().top = style.length_or_fallback(CSS::PropertyID::MarginTop, zero_value, containing_block.width()); + replaced_element_box_model.margin().bottom = style.length_or_fallback(CSS::PropertyID::MarginBottom, zero_value, containing_block.width()); + replaced_element_box_model.border().top = style.length_or_fallback(CSS::PropertyID::BorderTopWidth, zero_value); + replaced_element_box_model.border().bottom = style.length_or_fallback(CSS::PropertyID::BorderBottomWidth, zero_value); + replaced_element_box_model.padding().top = style.length_or_fallback(CSS::PropertyID::PaddingTop, zero_value, containing_block.width()); + replaced_element_box_model.padding().bottom = style.length_or_fallback(CSS::PropertyID::PaddingBottom, 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); - box_model().border().bottom = style.length_or_fallback(CSS::PropertyID::BorderBottomWidth, zero_value); - box_model().padding().top = style.length_or_fallback(CSS::PropertyID::PaddingTop, zero_value, containing_block.width()); - box_model().padding().bottom = style.length_or_fallback(CSS::PropertyID::PaddingBottom, zero_value, containing_block.width()); + float x = replaced_element_box_model.margin().left.to_px(*this) + + replaced_element_box_model.border().left.to_px(*this) + + replaced_element_box_model.padding().left.to_px(*this) + + replaced_element_box_model.offset().left.to_px(*this); - float position_x = box_model().margin().left.to_px(*this) - + box_model().border().left.to_px(*this) - + box_model().padding().left.to_px(*this) - + box_model().offset().left.to_px(*this); + float y = replaced_element_box_model.margin_box(*this).top + box_model().offset().top.to_px(*this); - if (parent()->is_block() && parent()->style().text_align() == CSS::ValueID::VendorSpecificCenter) { - position_x = (containing_block.width() / 2) - width() / 2; + box.set_offset(x, y); +} + +void LayoutBlock::place_block_level_non_replaced_element_in_normal_flow(LayoutBlock& block) +{ + auto& style = block.style(); + auto zero_value = Length(0, Length::Type::Px); + auto& containing_block = *this; + auto& box = block.box_model(); + + box.margin().top = style.length_or_fallback(CSS::PropertyID::MarginTop, zero_value, containing_block.width()); + box.margin().bottom = style.length_or_fallback(CSS::PropertyID::MarginBottom, zero_value, containing_block.width()); + box.border().top = style.length_or_fallback(CSS::PropertyID::BorderTopWidth, zero_value); + box.border().bottom = style.length_or_fallback(CSS::PropertyID::BorderBottomWidth, zero_value); + box.padding().top = style.length_or_fallback(CSS::PropertyID::PaddingTop, zero_value, containing_block.width()); + box.padding().bottom = style.length_or_fallback(CSS::PropertyID::PaddingBottom, zero_value, containing_block.width()); + + float x = box.margin().left.to_px(*this) + + box.border().left.to_px(*this) + + box.padding().left.to_px(*this) + + box.offset().left.to_px(*this); + + if (this->style().text_align() == CSS::ValueID::VendorSpecificCenter) { + x = (containing_block.width() / 2) - block.width() / 2; } - float position_y = box_model().margin_box(*this).top - + box_model().offset().top.to_px(*this); + float y = box.margin_box(*this).top + + box.offset().top.to_px(*this); - LayoutBlock* relevant_sibling = previous_sibling(); + auto* relevant_sibling = block.previous_sibling(); while (relevant_sibling != nullptr) { if (relevant_sibling->style().position() != CSS::Position::Absolute) break; @@ -463,26 +486,26 @@ void LayoutBlock::compute_position() } if (relevant_sibling) { - auto& previous_sibling_style = relevant_sibling->box_model(); - position_y += relevant_sibling->effective_offset().y() + relevant_sibling->height(); + auto& sibling_box = relevant_sibling->box_model(); + y += relevant_sibling->effective_offset().y() + relevant_sibling->height(); // Collapse top margin with bottom margin of previous sibling if necessary - float previous_sibling_margin_bottom = previous_sibling_style.margin().bottom.to_px(*relevant_sibling); - float my_margin_top = box_model().margin().top.to_px(*this); + float previous_sibling_margin_bottom = sibling_box.margin().bottom.to_px(*relevant_sibling); + float my_margin_top = box.margin().top.to_px(*this); if (my_margin_top < 0 || previous_sibling_margin_bottom < 0) { // Negative margins present. float largest_negative_margin = -min(my_margin_top, previous_sibling_margin_bottom); float largest_positive_margin = (my_margin_top < 0 && previous_sibling_margin_bottom < 0) ? 0 : max(my_margin_top, previous_sibling_margin_bottom); float final_margin = largest_positive_margin - largest_negative_margin; - position_y += final_margin - my_margin_top; + y += final_margin - my_margin_top; } else if (previous_sibling_margin_bottom > my_margin_top) { // Sibling's margin is larger than mine, adjust so we use sibling's. - position_y += previous_sibling_margin_bottom - my_margin_top; + y += previous_sibling_margin_bottom - my_margin_top; } } - set_offset({ position_x, position_y }); + block.set_offset(x, y); } void LayoutBlock::compute_height() diff --git a/Libraries/LibWeb/Layout/LayoutBlock.h b/Libraries/LibWeb/Layout/LayoutBlock.h index 52e45d5024..da29fca128 100644 --- a/Libraries/LibWeb/Layout/LayoutBlock.h +++ b/Libraries/LibWeb/Layout/LayoutBlock.h @@ -65,26 +65,25 @@ 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_absolutely_positioned_descendants(); private: virtual bool is_block() const override { return true; } + void place_block_level_non_replaced_element_in_normal_flow(LayoutBlock&); + void place_block_level_replaced_element_in_normal_flow(LayoutReplaced&); + void layout_absolutely_positioned_descendant(LayoutBox&); + NonnullRefPtr<StyleProperties> style_for_anonymous_block() const; - void layout_children(LayoutMode); + void layout_inside(LayoutMode); void layout_inline_children(LayoutMode); - void layout_block_children(LayoutMode); + void layout_contained_boxes(LayoutMode); Vector<LineBox> m_line_boxes; - HashTable<RefPtr<LayoutBox>> m_absolutely_positioned_descendants; }; template<typename Callback> diff --git a/Libraries/LibWeb/Layout/LayoutBox.h b/Libraries/LibWeb/Layout/LayoutBox.h index 4303612eb8..516a19b2f3 100644 --- a/Libraries/LibWeb/Layout/LayoutBox.h +++ b/Libraries/LibWeb/Layout/LayoutBox.h @@ -71,7 +71,7 @@ protected: virtual void did_set_rect() { } private: - virtual bool is_box() const override { return true; } + virtual bool is_box() const final { return true; } enum class Edge { Top, diff --git a/Libraries/LibWeb/Layout/LayoutReplaced.cpp b/Libraries/LibWeb/Layout/LayoutReplaced.cpp index dccb63aa97..202e39ca7c 100644 --- a/Libraries/LibWeb/Layout/LayoutReplaced.cpp +++ b/Libraries/LibWeb/Layout/LayoutReplaced.cpp @@ -121,42 +121,10 @@ float LayoutReplaced::calculate_height() const return used_height; } -Gfx::FloatPoint LayoutReplaced::calculate_position() -{ - ASSERT(!is_absolutely_positioned()); - auto& style = this->style(); - auto zero_value = Length(0, Length::Type::Px); - auto& containing_block = *this->containing_block(); - - 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); - box_model().border().bottom = style.length_or_fallback(CSS::PropertyID::BorderBottomWidth, zero_value); - box_model().padding().top = style.length_or_fallback(CSS::PropertyID::PaddingTop, zero_value, containing_block.width()); - box_model().padding().bottom = style.length_or_fallback(CSS::PropertyID::PaddingBottom, zero_value, containing_block.width()); - - float x = box_model().margin().left.to_px(*this) - + box_model().border().left.to_px(*this) - + box_model().padding().left.to_px(*this) - + box_model().offset().left.to_px(*this); - - float y = box_model().margin_box(*this).top + box_model().offset().top.to_px(*this); - - return { x, y }; -} - -void LayoutReplaced::layout(LayoutMode layout_mode) +void LayoutReplaced::layout(LayoutMode) { set_width(calculate_width()); set_height(calculate_height()); - - LayoutBox::layout(layout_mode); - - if (is_absolutely_positioned()) { - const_cast<LayoutBlock*>(containing_block())->add_absolutely_positioned_descendant(*this); - } else { - set_offset(calculate_position()); - } } void LayoutReplaced::split_into_lines(LayoutBlock& container, LayoutMode layout_mode) diff --git a/Libraries/LibWeb/Layout/LayoutReplaced.h b/Libraries/LibWeb/Layout/LayoutReplaced.h index f3e9669f3b..c48102917b 100644 --- a/Libraries/LibWeb/Layout/LayoutReplaced.h +++ b/Libraries/LibWeb/Layout/LayoutReplaced.h @@ -62,7 +62,6 @@ protected: virtual void split_into_lines(LayoutBlock& container, LayoutMode) override; private: - Gfx::FloatPoint calculate_position(); float calculate_width() const; float calculate_height() const; diff --git a/Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp b/Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp index 57db85120b..af1d3b3412 100644 --- a/Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp +++ b/Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp @@ -57,9 +57,6 @@ void LayoutTableRowGroup::layout(LayoutMode) { compute_width(); - if (!is_inline()) - compute_position(); - auto column_count = this->column_count(); Vector<float> column_widths; column_widths.resize(column_count); |