mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-30 22:54:35 +03:00
LibWeb: Consider entire stack of floated boxes when floating new box
If normal flow layout has caused us to progress past the current innermost float in the block axis, we still need to consider the floats stacked outside of it. Fix this by always walking the currently stacked floats from innermost to outermost when placing new floats.
This commit is contained in:
parent
6960a1bb45
commit
92eaad8f2e
Notes:
sideshowbarker
2024-07-17 06:51:48 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/92eaad8f2e
@ -0,0 +1,30 @@
|
||||
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 800x108 children: not-inline
|
||||
BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline
|
||||
TextNode <#text>
|
||||
BlockContainer <body> at (8,8) content-size 784x34.9375 children: not-inline
|
||||
BlockContainer <(anonymous)> at (8,8) content-size 784x17.46875 children: inline
|
||||
line 0 width: 27.640625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
|
||||
frag 0 from TextNode start: 1, length: 3, rect: [137,8 27.640625x17.46875]
|
||||
"bar"
|
||||
BlockContainer <div.big-float> at (8,8) content-size 100x100 floating children: not-inline
|
||||
TextNode <#text>
|
||||
BlockContainer <div.xxx> at (108,8) content-size 29.109375x17.46875 floating children: inline
|
||||
line 0 width: 29.109375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
|
||||
frag 0 from TextNode start: 0, length: 3, rect: [108,8 29.109375x17.46875]
|
||||
"xxx"
|
||||
TextNode <#text>
|
||||
TextNode <#text>
|
||||
BlockContainer <div> at (8,25.46875) content-size 784x17.46875 children: inline
|
||||
line 0 width: 27.203125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
|
||||
frag 0 from TextNode start: 1, length: 3, rect: [130,25.46875 27.203125x17.46875]
|
||||
"baz"
|
||||
TextNode <#text>
|
||||
BlockContainer <div.yyy> at (108,25.46875) content-size 21.515625x17.46875 floating children: inline
|
||||
line 0 width: 21.515625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
|
||||
frag 0 from TextNode start: 0, length: 3, rect: [108,25.46875 21.515625x17.46875]
|
||||
"yyy"
|
||||
TextNode <#text>
|
||||
TextNode <#text>
|
||||
BlockContainer <(anonymous)> at (8,42.9375) content-size 784x0 children: inline
|
||||
TextNode <#text>
|
@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
* {
|
||||
font-family: 'SerenitySans';
|
||||
}
|
||||
.big-float {
|
||||
float: left;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: pink;
|
||||
}
|
||||
.xxx,
|
||||
.yyy {
|
||||
float: left;
|
||||
background-color: orange;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<div class="big-float"></div>
|
||||
<div class="xxx">xxx</div>
|
||||
bar
|
||||
<div>
|
||||
<div class="yyy">yyy</div>
|
||||
baz
|
||||
</div>
|
||||
</html>
|
@ -756,36 +756,48 @@ void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer
|
||||
float_to_edge();
|
||||
side_data.y_offset = 0;
|
||||
} else {
|
||||
auto& previous_box = side_data.current_boxes.last();
|
||||
|
||||
CSSPixels wanted_offset_from_edge = 0;
|
||||
bool fits_on_line = false;
|
||||
// NOTE: If we're in inline layout, the LineBuilder has already provided the right Y offset.
|
||||
// In block layout, we adjust by the side's current Y offset here.
|
||||
if (!line_builder)
|
||||
y_in_root += side_data.y_offset;
|
||||
|
||||
if (side == FloatSide::Left) {
|
||||
wanted_offset_from_edge = side_data.current_width + box_state.margin_box_left();
|
||||
fits_on_line = (wanted_offset_from_edge + box_state.content_width() + box_state.margin_box_right()) <= width_of_containing_block;
|
||||
} else {
|
||||
wanted_offset_from_edge = side_data.current_width + box_state.margin_box_right() + box_state.content_width();
|
||||
fits_on_line = (wanted_offset_from_edge - box_state.margin_box_left()) >= 0;
|
||||
bool did_touch_preceding_float = false;
|
||||
bool did_place_next_to_preceding_float = false;
|
||||
|
||||
// Walk all currently tracked floats on the side we're floating towards.
|
||||
// We're looking for the innermost preceding float that intersects vertically with `box`.
|
||||
for (auto& preceding_float : side_data.current_boxes.in_reverse()) {
|
||||
auto const preceding_float_rect = margin_box_rect_in_ancestor_coordinate_space(preceding_float.box, root(), m_state);
|
||||
if (!preceding_float_rect.contains_vertically(y_in_root))
|
||||
continue;
|
||||
// We found a preceding float that intersects vertically with the current float.
|
||||
// Now we need to find out if there's enough inline-axis space to stack them next to each other.
|
||||
auto const& preceding_float_state = m_state.get(preceding_float.box);
|
||||
CSSPixels tentative_offset_from_edge = 0;
|
||||
bool fits_next_to_preceding_float = false;
|
||||
if (side == FloatSide::Left) {
|
||||
tentative_offset_from_edge = preceding_float.offset_from_edge + preceding_float_state.content_width() + preceding_float_state.margin_box_right() + box_state.margin_box_left();
|
||||
fits_next_to_preceding_float = (tentative_offset_from_edge + box_state.content_width() + box_state.margin_box_right()) <= width_of_containing_block;
|
||||
} else {
|
||||
tentative_offset_from_edge = preceding_float.offset_from_edge + preceding_float_state.margin_box_left() + box_state.margin_box_right() + box_state.content_width();
|
||||
fits_next_to_preceding_float = tentative_offset_from_edge >= 0;
|
||||
}
|
||||
did_touch_preceding_float = true;
|
||||
if (!fits_next_to_preceding_float)
|
||||
continue;
|
||||
offset_from_edge = tentative_offset_from_edge;
|
||||
did_place_next_to_preceding_float = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fits_on_line) {
|
||||
auto const previous_rect = margin_box_rect_in_ancestor_coordinate_space(previous_box.box, root(), m_state);
|
||||
// NOTE: If we're in inline layout, the LineBuilder has already provided the right Y offset.
|
||||
// In block layout, we adjust by the side's current Y offset here.
|
||||
if (!line_builder)
|
||||
y_in_root += side_data.y_offset;
|
||||
if (previous_rect.contains_vertically(y_in_root)) {
|
||||
// This box touches another already floating box. Stack after others.
|
||||
offset_from_edge = wanted_offset_from_edge;
|
||||
} else {
|
||||
// This box does not touch another floating box, go all the way to the edge.
|
||||
float_to_edge();
|
||||
if (!did_touch_preceding_float) {
|
||||
// This box does not touch another floating box, go all the way to the edge.
|
||||
float_to_edge();
|
||||
|
||||
// Also, forget all previous boxes floated to this side while since they're no longer relevant.
|
||||
side_data.clear();
|
||||
}
|
||||
} else {
|
||||
// Also, forget all previous boxes floated to this side while since they're no longer relevant.
|
||||
side_data.clear();
|
||||
} else if (!did_place_next_to_preceding_float) {
|
||||
// We ran out of horizontal space on this "float line", and need to break.
|
||||
float_to_edge();
|
||||
CSSPixels lowest_margin_edge = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user