diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index 812039770e..eb500e4621 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -297,4 +297,12 @@ void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode) } } +bool InlineFormattingContext::any_floats_intrude_at_y(float y) const +{ + auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(containing_block(), parent().root(), m_state); + float y_in_root = box_in_root_rect.y() + y; + auto space = parent().space_used_by_floats(y_in_root); + return space.left > 0 || space.right > 0; +} + } diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h index a164a96b2a..525f968144 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.h @@ -29,6 +29,7 @@ public: float leftmost_x_offset_at(float y) const; float available_space_for_line(float y) const; + bool any_floats_intrude_at_y(float y) const; float effective_containing_block_width() const { return m_effective_containing_block_width; } diff --git a/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp b/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp index 8167527490..e1176ecc99 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include @@ -23,11 +24,15 @@ LineBuilder::~LineBuilder() update_last_line(); } -void LineBuilder::break_line() +void LineBuilder::break_line(Optional next_item_width) { update_last_line(); - m_containing_block_state.line_boxes.append(LineBox()); - begin_new_line(true); + do { + m_containing_block_state.line_boxes.append(LineBox()); + begin_new_line(true); + } while (next_item_width.has_value() + && next_item_width.value() > m_available_width_for_current_line + && m_context.any_floats_intrude_at_y(m_current_y)); } void LineBuilder::begin_new_line(bool increment_y) @@ -68,11 +73,18 @@ void LineBuilder::append_text_chunk(TextNode const& text_node, size_t offset_in_ bool LineBuilder::should_break(float next_item_width) { - auto const& line_boxes = m_containing_block_state.line_boxes; - if (line_boxes.is_empty() || line_boxes.last().is_empty()) + if (!isfinite(m_available_width_for_current_line)) return false; - auto current_line_width = line_boxes.last().width(); - return (current_line_width + next_item_width) > m_available_width_for_current_line; + + auto const& line_boxes = m_containing_block_state.line_boxes; + if (line_boxes.is_empty() || line_boxes.last().is_empty()) { + // If we don't have a single line box yet *and* there are no floats intruding + // at this Y coordinate, we don't need to break before inserting anything. + if (!m_context.any_floats_intrude_at_y(m_current_y)) + return false; + } + auto current_line_width = ensure_last_line_box().width(); + return roundf(current_line_width + next_item_width) > m_available_width_for_current_line; } static float box_baseline(LayoutState const& state, Box const& box) @@ -255,7 +267,6 @@ void LineBuilder::adjust_last_line_after_inserting_floating_box(Badge next_item_width = {}); void append_box(Box const&, float leading_size, float trailing_size, float leading_margin, float trailing_margin); void append_text_chunk(TextNode const&, size_t offset_in_node, size_t length_in_node, float leading_size, float trailing_size, float leading_margin, float trailing_margin, float content_width, float content_height); @@ -26,7 +26,7 @@ public: bool break_if_needed(float next_item_width) { if (should_break(next_item_width)) { - break_line(); + break_line(next_item_width); return true; } return false;