summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/Layout
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-03-08 22:49:34 +0100
committerAndreas Kling <kling@serenityos.org>2021-03-08 22:53:28 +0100
commit968ad0f8d11bc7c2e2df1f34e8fe96cb165f87ac (patch)
tree0dd610f2f53ab7bab5a8a0d1548a0a6edad6463d /Userland/Libraries/LibWeb/Layout
parent0918dd0460b40be080f5f36dc368e7449a5a8fcb (diff)
downloadserenity-968ad0f8d11bc7c2e2df1f34e8fe96cb165f87ac.zip
LibWeb: Some improvements to CSS height:auto computation for blocks
Auto block heights are now computed according to something that kinda resembles the specification. Blocks with inline children and height:auto have their height computed based on the top of the first line box and the bottom of the last line box. Very straightforward. Blocks with block children and height:auto have their height computed based on the top of the first in-flow block child's margin box, and the bottom of the last in-flow block child's margin box.
Diffstat (limited to 'Userland/Libraries/LibWeb/Layout')
-rw-r--r--Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp91
-rw-r--r--Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h3
2 files changed, 66 insertions, 28 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp
index 2f1c1e96b4..cffd2a20e6 100644
--- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp
+++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp
@@ -267,31 +267,53 @@ void BlockFormattingContext::compute_width_for_block_level_replaced_element_in_n
box.set_width(compute_width_for_replaced_element(box));
}
-void BlockFormattingContext::compute_height_for_block_level_replaced_element_in_normal_flow(ReplacedBox& box)
+float BlockFormattingContext::compute_auto_height_for_block_level_element(const Box& box)
{
- box.set_height(compute_height_for_replaced_element(box));
-}
+ Optional<float> top;
+ Optional<float> bottom;
-void BlockFormattingContext::compute_height(Box& box)
-{
- if (is<ReplacedBox>(box)) {
- compute_height_for_block_level_replaced_element_in_normal_flow(downcast<ReplacedBox>(box));
- return;
- }
+ if (box.children_are_inline()) {
+ // If it only has inline-level children, the height is the distance between
+ // the top of the topmost line box and the bottom of the bottommost line box.
+ if (!box.line_boxes().is_empty()) {
+ for (auto& fragment : box.line_boxes().first().fragments()) {
+ if (!top.has_value() || fragment.offset().y() < top.value())
+ top = fragment.offset().y();
+ }
+ for (auto& fragment : box.line_boxes().last().fragments()) {
+ if (!bottom.has_value() || (fragment.offset().y() + fragment.height()) > bottom.value())
+ bottom = fragment.offset().y() + fragment.height();
+ }
+ }
+ } else {
+ // If it has block-level children, the height is the distance between
+ // the top margin-edge of the topmost block-level child box
+ // and the bottom margin-edge of the bottommost block-level child box.
+ box.for_each_child_of_type<Box>([&](Layout::Box& child_box) {
+ if (box.is_absolutely_positioned() || box.is_floating())
+ return IterationDecision::Continue;
- auto& computed_values = box.computed_values();
- auto& containing_block = *box.containing_block();
+ float child_box_top = child_box.effective_offset().y() - child_box.box_model().margin_box().top;
+ float child_box_bottom = child_box.effective_offset().y() + child_box.height() + child_box.box_model().margin_box().bottom;
- CSS::Length specified_height;
+ if (!top.has_value() || child_box_top < top.value())
+ top = child_box_top;
- if (computed_values.height().is_percentage() && !containing_block.computed_values().height().is_absolute()) {
- specified_height = CSS::Length::make_auto();
- } else {
- specified_height = computed_values.height().resolved_or_auto(box, containing_block.height());
+ if (!bottom.has_value() || child_box_bottom > bottom.value())
+ bottom = child_box_bottom;
+
+ return IterationDecision::Continue;
+ });
}
+ return bottom.value_or(0) - top.value_or(0);
+}
- auto specified_max_height = computed_values.max_height().resolved_or_auto(box, containing_block.height());
+void BlockFormattingContext::compute_height(Box& box)
+{
+ auto& computed_values = box.computed_values();
+ auto& containing_block = *box.containing_block();
+ // First, resolve the top/bottom parts of the surrounding box model.
box.box_model().margin.top = computed_values.margin().top.resolved_or_zero(box, containing_block.width()).to_px(box);
box.box_model().margin.bottom = computed_values.margin().bottom.resolved_or_zero(box, containing_block.width()).to_px(box);
box.box_model().border.top = computed_values.border_top().width;
@@ -299,12 +321,32 @@ void BlockFormattingContext::compute_height(Box& box)
box.box_model().padding.top = computed_values.padding().top.resolved_or_zero(box, containing_block.width()).to_px(box);
box.box_model().padding.bottom = computed_values.padding().bottom.resolved_or_zero(box, containing_block.width()).to_px(box);
- if (!specified_height.is_auto()) {
- float used_height = specified_height.to_px(box);
- if (!specified_max_height.is_auto())
- used_height = min(used_height, specified_max_height.to_px(box));
- box.set_height(used_height);
+ // Then work out what the height is, based on box type and CSS properties.
+ float height = 0;
+ if (is<ReplacedBox>(box)) {
+ height = compute_height_for_replaced_element(downcast<ReplacedBox>(box));
+ } else {
+ if (box.computed_values().height().is_undefined_or_auto()) {
+ height = compute_auto_height_for_block_level_element(box);
+ } else {
+ CSS::Length specified_height;
+ if (computed_values.height().is_percentage() && !containing_block.computed_values().height().is_absolute()) {
+ specified_height = CSS::Length::make_auto();
+ } else {
+ specified_height = computed_values.height().resolved_or_auto(box, containing_block.height());
+ }
+
+ auto specified_max_height = computed_values.max_height().resolved_or_auto(box, containing_block.height());
+ if (!specified_height.is_auto()) {
+ float used_height = specified_height.to_px(box);
+ if (!specified_max_height.is_auto())
+ used_height = min(used_height, specified_max_height.to_px(box));
+ height = used_height;
+ }
+ }
}
+
+ box.set_height(height);
}
void BlockFormattingContext::layout_inline_children(Box& box, LayoutMode layout_mode)
@@ -350,11 +392,6 @@ void BlockFormattingContext::layout_block_level_children(Box& box, LayoutMode la
if (box.computed_values().width().is_undefined() || box.computed_values().width().is_auto())
box.set_width(content_width);
}
-
- if (box.computed_values().height().is_undefined_or_auto())
- box.set_height(content_height);
- else
- box.set_height(box.computed_values().height().resolved_or_zero(box, context_box().height()).to_px(box));
}
void BlockFormattingContext::place_block_level_replaced_element_in_normal_flow(Box& child_box, Box& containing_block)
diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h
index efaa9ab0b7..c5b73c20fa 100644
--- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h
+++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h
@@ -54,7 +54,8 @@ private:
void compute_width_for_floating_box(Box&);
void compute_width_for_block_level_replaced_element_in_normal_flow(ReplacedBox&);
- void compute_height_for_block_level_replaced_element_in_normal_flow(ReplacedBox&);
+
+ [[nodiscard]] static float compute_auto_height_for_block_level_element(const Box&);
void layout_initial_containing_block(LayoutMode);