1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 22:57:44 +00:00

LibWeb: Rewrite CSS float implementation to use offset-from-edge

The previous implementation used relative X offsets for both left and
right-side floats. This made right-side floats super awkward, since we
could only determine their X position once the width of the BFC root was
known, and for BFC roots with automatic width, this was not even working
at all most of the time.

This patch changes the way we deal with floats so that BFC keeps track
of the offset-from-edge for each float. The offset is the distance from
the BFC root edge (left or right, depending on float direction) to the
"innermost" margin edge of the floating box.

Floating box are now laid out in two passes: while going through the
normal flow layout, we put floats in their *static* position (i.e the
position they would have occupied if they weren't floating) and then
update the Y position value to the final one.

The second pass occurs later on, when the BFC root has had its width
assigned by the parent context. Once we know the root width, we can
set the X position value of floating boxes. (Because the X position of
right-side floats is relative to the right edge of the BFC root.)
This commit is contained in:
Andreas Kling 2022-03-18 14:44:36 +01:00
parent 28642de6ed
commit 39b7fbfeb9
7 changed files with 245 additions and 83 deletions

View file

@ -27,7 +27,7 @@ public:
auto const& right_side_floats() const { return m_right_floats; }
static float compute_theoretical_height(FormattingState const&, Box const&);
void compute_width(Box const&);
void compute_width(Box const&, LayoutMode = LayoutMode::Default);
// https://www.w3.org/TR/css-display/#block-formatting-context-root
BlockContainer const& root() const { return static_cast<BlockContainer const&>(context_box()); }
@ -38,12 +38,14 @@ public:
void add_absolutely_positioned_box(Box const& box) { m_absolutely_positioned_boxes.append(box); }
AvailableSpaceForLineInfo available_space_for_line(float y) const;
SpaceUsedByFloats space_used_by_floats(float y) const;
virtual float greatest_child_width(Box const&) override;
private:
virtual bool is_block_formatting_context() const final { return true; }
void compute_width_for_floating_box(Box const&);
void compute_width_for_floating_box(Box const&, LayoutMode);
void compute_width_for_block_level_replaced_element_in_normal_flow(ReplacedBox const&);
@ -56,7 +58,7 @@ private:
void place_block_level_element_in_normal_flow_horizontally(Box const& child_box, BlockContainer const&);
void place_block_level_element_in_normal_flow_vertically(Box const& child_box, BlockContainer const&);
void layout_floating_child(Box const& child, BlockContainer const& containing_block);
void layout_floating_box(Box const& child, BlockContainer const& containing_block, LayoutMode);
void apply_transformations_to_children(Box const&);
@ -67,9 +69,40 @@ private:
Right,
};
struct FloatingBox {
Box const& box;
// Offset from left/right edge to the left content edge of `box`.
float offset_from_edge { 0 };
// Top margin edge of `box`.
float top_margin_edge { 0 };
// Bottom margin edge of `box`.
float bottom_margin_edge { 0 };
};
struct FloatSideData {
Vector<Box const&> boxes;
// Floating boxes currently accumulating on this side.
Vector<FloatingBox&> current_boxes;
// Combined width of boxes currently accumulating on this side.
// This is the innermost margin of the innermost floating box.
float current_width { 0 };
// Highest value of `m_current_width` we've seen.
float max_width { 0 };
// All floating boxes encountered thus far within this BFC.
Vector<NonnullOwnPtr<FloatingBox>> all_boxes;
// Current Y offset from BFC root top.
float y_offset { 0 };
void clear()
{
current_boxes.clear();
current_width = 0;
}
};
FloatSideData m_left_floats;