1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:17:36 +00:00

LibWeb: Better handling of floating boxes from inline formatting context

Handle the clear property for floating boxes and add tracking for
vertical clearence within an inline formatting context.
This commit is contained in:
Andi Gallo 2023-07-29 04:05:45 +00:00 committed by Andreas Kling
parent fd86509ef8
commit 62f15f94d2
9 changed files with 78 additions and 8 deletions

View file

@ -0,0 +1,23 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x0 children: not-inline
BlockContainer <div> at (8,8) content-size 784x0 children: inline
TextNode <#text>
BlockContainer <h1.left> at (8,29.4375) content-size 28.53125x34.9375 floating [BFC] children: inline
line 0 width: 28.53125, height: 34.9375, bottom: 34.9375, baseline: 27.0625
frag 0 from TextNode start: 0, length: 1, rect: [8,29.4375 28.53125x34.9375]
"A"
TextNode <#text>
TextNode <#text>
BlockContainer <h1.right> at (773.3125,29.4375) content-size 18.6875x34.9375 floating [BFC] children: inline
line 0 width: 18.6875, height: 34.9375, bottom: 34.9375, baseline: 27.0625
frag 0 from TextNode start: 0, length: 1, rect: [773.3125,29.4375 18.6875x34.9375]
"B"
TextNode <#text>
TextNode <#text>
BlockContainer <div.c> at (8,155.8125) content-size 11.5625x17.46875 floating [BFC] children: inline
line 0 width: 11.5625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 1, rect: [8,155.8125 11.5625x17.46875]
"X"
TextNode <#text>
TextNode <#text>

View file

@ -0,0 +1,21 @@
<style>
.left {
float: left;
}
.right {
float: right;
}
.c {
margin-top: 70px;
clear: both;
float: left;
}
</style>
<div>
<h1 class="left">A</h1>
<h1 class="right">B</h1>
<div class="c">X</div>
</div>

View file

@ -2,7 +2,6 @@
.a { .a {
float: left; float: left;
width: 100px; width: 100px;
margin-bottom: 4px;
} }
br { br {

View file

@ -601,7 +601,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
} }
m_margin_state.add_margin(box_state.margin_top); m_margin_state.add_margin(box_state.margin_top);
auto introduce_clearance = clear_floating_boxes(box); auto introduce_clearance = clear_floating_boxes(box, {});
if (introduce_clearance == DidIntroduceClearance::Yes) if (introduce_clearance == DidIntroduceClearance::Yes)
m_margin_state.reset(); m_margin_state.reset();
@ -752,7 +752,7 @@ CSSPixels BlockFormattingContext::BlockMarginState::current_collapsed_margin() c
return collapsed_margin; return collapsed_margin;
} }
BlockFormattingContext::DidIntroduceClearance BlockFormattingContext::clear_floating_boxes(Node const& child_box) BlockFormattingContext::DidIntroduceClearance BlockFormattingContext::clear_floating_boxes(Node const& child_box, Optional<InlineFormattingContext&> inline_formatting_context)
{ {
auto const& computed_values = child_box.computed_values(); auto const& computed_values = child_box.computed_values();
auto result = DidIntroduceClearance::No; auto result = DidIntroduceClearance::No;
@ -777,7 +777,12 @@ BlockFormattingContext::DidIntroduceClearance BlockFormattingContext::clear_floa
for (auto* containing_block = child_box.containing_block(); containing_block && containing_block != &root(); containing_block = containing_block->containing_block()) for (auto* containing_block = child_box.containing_block(); containing_block && containing_block != &root(); containing_block = containing_block->containing_block())
clearance_y_in_containing_block -= m_state.get(*containing_block).offset.y(); clearance_y_in_containing_block -= m_state.get(*containing_block).offset.y();
if (clearance_y_in_containing_block > m_y_offset_of_current_block_container.value()) { if (inline_formatting_context.has_value()) {
if (clearance_y_in_containing_block > inline_formatting_context->vertical_float_clearance()) {
result = DidIntroduceClearance::Yes;
inline_formatting_context->set_vertical_float_clearance(clearance_y_in_containing_block);
}
} else if (clearance_y_in_containing_block > m_y_offset_of_current_block_container.value()) {
result = DidIntroduceClearance::Yes; result = DidIntroduceClearance::Yes;
m_y_offset_of_current_block_container = clearance_y_in_containing_block; m_y_offset_of_current_block_container = clearance_y_in_containing_block;
} }
@ -879,7 +884,7 @@ void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer
// First we place the box normally (to get the right y coordinate.) // First we place the box normally (to get the right y coordinate.)
// If we have a LineBuilder, we're in the middle of inline layout, otherwise this is block layout. // If we have a LineBuilder, we're in the middle of inline layout, otherwise this is block layout.
if (line_builder) { if (line_builder) {
auto y = line_builder->y_for_float_to_be_inserted_here(box); auto y = max(line_builder->y_for_float_to_be_inserted_here(box), line_builder->inline_formatting_context().vertical_float_clearance());
box_state.set_content_y(y + box_state.margin_box_top()); box_state.set_content_y(y + box_state.margin_box_top());
} else { } else {
place_block_level_element_in_normal_flow_vertically(box, y + box_state.margin_top); place_block_level_element_in_normal_flow_vertically(box, y + box_state.margin_top);

View file

@ -10,6 +10,7 @@
#include <LibWeb/Forward.h> #include <LibWeb/Forward.h>
#include <LibWeb/Layout/BlockContainer.h> #include <LibWeb/Layout/BlockContainer.h>
#include <LibWeb/Layout/FormattingContext.h> #include <LibWeb/Layout/FormattingContext.h>
#include <LibWeb/Layout/InlineFormattingContext.h>
namespace Web::Layout { namespace Web::Layout {
@ -59,7 +60,7 @@ public:
No, No,
}; };
[[nodiscard]] DidIntroduceClearance clear_floating_boxes(Node const& child_box); [[nodiscard]] DidIntroduceClearance clear_floating_boxes(Node const& child_box, Optional<InlineFormattingContext&> inline_formatting_context);
void reset_margin_state() { m_margin_state.reset(); } void reset_margin_state() { m_margin_state.reset(); }

View file

@ -249,7 +249,7 @@ void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
case InlineLevelIterator::Item::Type::ForcedBreak: { case InlineLevelIterator::Item::Type::ForcedBreak: {
line_builder.break_line(LineBuilder::ForcedBreak::Yes); line_builder.break_line(LineBuilder::ForcedBreak::Yes);
if (item.node) { if (item.node) {
auto introduce_clearance = parent().clear_floating_boxes(*item.node); auto introduce_clearance = parent().clear_floating_boxes(*item.node, *this);
if (introduce_clearance == BlockFormattingContext::DidIntroduceClearance::Yes) if (introduce_clearance == BlockFormattingContext::DidIntroduceClearance::Yes)
parent().reset_margin_state(); parent().reset_margin_state();
} }
@ -268,8 +268,12 @@ void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
break; break;
case InlineLevelIterator::Item::Type::FloatingElement: case InlineLevelIterator::Item::Type::FloatingElement:
if (is<Box>(*item.node)) if (is<Box>(*item.node)) {
auto introduce_clearance = parent().clear_floating_boxes(*item.node, *this);
if (introduce_clearance == BlockFormattingContext::DidIntroduceClearance::Yes)
parent().reset_margin_state();
parent().layout_floating_box(static_cast<Layout::Box const&>(*item.node), containing_block(), layout_mode, *m_available_space, 0, &line_builder); parent().layout_floating_box(static_cast<Layout::Box const&>(*item.node), containing_block(), layout_mode, *m_available_space, 0, &line_builder);
}
break; break;
case InlineLevelIterator::Item::Type::Text: { case InlineLevelIterator::Item::Type::Text: {
@ -369,4 +373,14 @@ void InlineFormattingContext::determine_height_of_child(Box const& box, Availabl
return parent().determine_height_of_child(box, available_space); return parent().determine_height_of_child(box, available_space);
} }
CSSPixels InlineFormattingContext::vertical_float_clearance() const
{
return m_vertical_float_clearance;
}
void InlineFormattingContext::set_vertical_float_clearance(CSSPixels vertical_float_clearance)
{
m_vertical_float_clearance = vertical_float_clearance;
}
} }

View file

@ -38,6 +38,9 @@ public:
virtual void determine_width_of_child(Box const&, AvailableSpace const&) override; virtual void determine_width_of_child(Box const&, AvailableSpace const&) override;
virtual void determine_height_of_child(Box const&, AvailableSpace const&) override; virtual void determine_height_of_child(Box const&, AvailableSpace const&) override;
CSSPixels vertical_float_clearance() const;
void set_vertical_float_clearance(CSSPixels);
private: private:
void generate_line_boxes(LayoutMode); void generate_line_boxes(LayoutMode);
void apply_justification_to_fragments(CSS::TextJustify, LineBox&, bool is_last_line); void apply_justification_to_fragments(CSS::TextJustify, LineBox&, bool is_last_line);
@ -48,6 +51,8 @@ private:
CSSPixels m_automatic_content_width { 0 }; CSSPixels m_automatic_content_width { 0 };
CSSPixels m_automatic_content_height { 0 }; CSSPixels m_automatic_content_height { 0 };
CSSPixels m_vertical_float_clearance { 0 };
}; };
} }

View file

@ -49,6 +49,8 @@ public:
void recalculate_available_space(); void recalculate_available_space();
CSSPixels y_for_float_to_be_inserted_here(Box const&); CSSPixels y_for_float_to_be_inserted_here(Box const&);
auto& inline_formatting_context() { return m_context; }
private: private:
void begin_new_line(bool increment_y, bool is_first_break_in_sequence = true); void begin_new_line(bool increment_y, bool is_first_break_in_sequence = true);