summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Libraries/LibWeb/Dump.cpp5
-rw-r--r--Libraries/LibWeb/Forward.h1
-rw-r--r--Libraries/LibWeb/Layout/LayoutBlock.cpp239
-rw-r--r--Libraries/LibWeb/Layout/LayoutBlock.h13
-rw-r--r--Libraries/LibWeb/Layout/LayoutBox.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutReplaced.cpp34
-rw-r--r--Libraries/LibWeb/Layout/LayoutReplaced.h1
-rw-r--r--Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp3
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);