From 71ca857b67550c93a9c035301cef0a9d75f1bf67 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 11 Sep 2022 22:39:01 +0200 Subject: [PATCH] LibWeb: Break lines until we have enough space between floats Before this change, we'd always insert one line box fragment, even when a float was taking up too much space on the line, and the fragment didn't actually fit. We now perform line breaks until we have enough space between floats. This fixes many page layouts where we'd previously see small fragments of inline content outside the right edge of the containing block. --- .../LibWeb/Layout/InlineFormattingContext.cpp | 8 ++++++ .../LibWeb/Layout/InlineFormattingContext.h | 1 + .../Libraries/LibWeb/Layout/LineBuilder.cpp | 27 +++++++++++++------ .../Libraries/LibWeb/Layout/LineBuilder.h | 4 +-- 4 files changed, 30 insertions(+), 10 deletions(-) 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;