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:
parent
fd86509ef8
commit
62f15f94d2
9 changed files with 78 additions and 8 deletions
|
@ -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>
|
|
@ -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>
|
|
@ -2,7 +2,6 @@
|
||||||
.a {
|
.a {
|
||||||
float: left;
|
float: left;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
br {
|
br {
|
|
@ -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);
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue