at (8,8) content-size 61x39.40625 table-row children: not-inline
+ BlockContainer <(anonymous)> (not painted) children: inline
+ TextNode <#text>
+ BlockContainer at (10,18.96875) content-size 14.296875x17.46875 table-cell [BFC] children: inline
+ line 0 width: 14.265625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+ frag 0 from TextNode start: 0, length: 1, rect: [10,18.96875 14.265625x17.46875]
+ "A"
+ TextNode <#text>
+ BlockContainer <(anonymous)> (not painted) children: inline
+ TextNode <#text>
+ BlockContainer | at (28.296875,10) content-size 20.40625x35.40625 table-cell [BFC] children: inline
+ line 0 width: 9.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+ frag 0 from TextNode start: 1, length: 1, rect: [28.296875,10 9.34375x17.46875]
+ "B"
+ line 1 width: 10.3125, height: 17.9375, bottom: 35.40625, baseline: 13.53125
+ frag 0 from TextNode start: 0, length: 1, rect: [28.296875,27 10.3125x17.46875]
+ "C"
+ TextNode <#text>
+ BreakNode
+ TextNode <#text>
+ BlockContainer <(anonymous)> (not painted) children: inline
+ TextNode <#text>
+ BlockContainer | at (52.703125,18.96875) content-size 14.296875x17.46875 table-cell [BFC] children: inline
+ line 0 width: 11.140625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+ frag 0 from TextNode start: 1, length: 1, rect: [52.703125,18.96875 11.140625x17.46875]
+ "D"
+ TextNode <#text>
+ BlockContainer <(anonymous)> (not painted) children: inline
+ TextNode <#text>
+ BlockContainer <(anonymous)> (not painted) children: inline
+ TextNode <#text>
+ BlockContainer <(anonymous)> (not painted) children: inline
+ TextNode <#text>
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [8,8 784x39.40625]
+ PaintableWithLines (TableWrapper(anonymous)) [8,8 61x39.40625]
+ PaintableBox (Box) [8,8 61x39.40625]
+ PaintableBox (Box) [8,8 61x39.40625]
+ PaintableBox (Box) [8,8 61x39.40625]
+ PaintableWithLines (BlockContainer) [8,8 18.296875x39.40625]
+ TextPaintable (TextNode<#text>)
+ PaintableWithLines (BlockContainer | ) [26.296875,8 24.40625x39.40625]
+ TextPaintable (TextNode<#text>)
+ TextPaintable (TextNode<#text>)
+ PaintableWithLines (BlockContainer | ) [50.703125,8 18.296875x39.40625]
+ TextPaintable (TextNode<#text>)
diff --git a/Tests/LibWeb/Layout/input/nowrap-and-no-line-break-opportunity.html b/Tests/LibWeb/Layout/input/nowrap-and-no-line-break-opportunity.html
new file mode 100644
index 0000000000..3895659553
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/nowrap-and-no-line-break-opportunity.html
@@ -0,0 +1,13 @@
+
+
+ ABCXABC
+
\ No newline at end of file
diff --git a/Tests/LibWeb/Layout/input/space-is-soft-line-break-opportunity.html b/Tests/LibWeb/Layout/input/space-is-soft-line-break-opportunity.html
new file mode 100644
index 0000000000..f6831a013a
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/space-is-soft-line-break-opportunity.html
@@ -0,0 +1,13 @@
+
+
+ ABC ABC
+
\ No newline at end of file
diff --git a/Tests/LibWeb/Layout/input/table/line-breaking-in-cells.html b/Tests/LibWeb/Layout/input/table/line-breaking-in-cells.html
new file mode 100644
index 0000000000..b9cb8242af
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/table/line-breaking-in-cells.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+ A
+ |
+
+ B
+ C
+ |
+
+ D
+ |
+
+
+
\ No newline at end of file
diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp
index ef211d7efd..1a544056f4 100644
--- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp
+++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp
@@ -250,8 +250,14 @@ void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
auto& item = item_opt.value();
// Ignore collapsible whitespace chunks at the start of line, and if the last fragment already ends in whitespace.
- if (item.is_collapsible_whitespace && (line_boxes.is_empty() || line_boxes.last().is_empty_or_ends_in_whitespace()))
+ if (item.is_collapsible_whitespace && (line_boxes.is_empty() || line_boxes.last().is_empty_or_ends_in_whitespace())) {
+ if (item.node->computed_values().white_space() != CSS::WhiteSpace::Nowrap) {
+ auto next_width = iterator.next_non_whitespace_sequence_width();
+ if (next_width > 0)
+ line_builder.break_if_needed(next_width);
+ }
continue;
+ }
switch (item.type) {
case InlineLevelIterator::Item::Type::ForcedBreak: {
@@ -287,17 +293,24 @@ void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
case InlineLevelIterator::Item::Type::Text: {
auto& text_node = verify_cast(*item.node);
- if (text_node.computed_values().white_space() != CSS::WhiteSpace::Nowrap && line_builder.break_if_needed(item.border_box_width())) {
+ if (text_node.computed_values().white_space() != CSS::WhiteSpace::Nowrap) {
+ bool is_whitespace = false;
+ CSSPixels next_width = 0;
+ // If we're in a whitespace-collapsing context, we can simply check the flag.
+ if (item.is_collapsible_whitespace) {
+ is_whitespace = true;
+ next_width = iterator.next_non_whitespace_sequence_width();
+ } else {
+ // In whitespace-preserving contexts (white-space: pre*), we have to check manually.
+ auto view = text_node.text_for_rendering().substring_view(item.offset_in_node, item.length_in_node);
+ is_whitespace = view.is_whitespace();
+ if (is_whitespace)
+ next_width = iterator.next_non_whitespace_sequence_width();
+ }
+
// If whitespace caused us to break, we swallow the whitespace instead of
// putting it on the next line.
-
- // If we're in a whitespace-collapsing context, we can simply check the flag.
- if (item.is_collapsible_whitespace)
- break;
-
- // In whitespace-preserving contexts (white-space: pre*), we have to check manually.
- auto view = text_node.text_for_rendering().substring_view(item.offset_in_node, item.length_in_node);
- if (view.is_whitespace())
+ if (is_whitespace && next_width > 0 && line_builder.break_if_needed(item.border_box_width() + next_width))
break;
}
line_builder.append_text_chunk(
diff --git a/Userland/Libraries/LibWeb/Layout/InlineLevelIterator.cpp b/Userland/Libraries/LibWeb/Layout/InlineLevelIterator.cpp
index 368df00247..daaf49664c 100644
--- a/Userland/Libraries/LibWeb/Layout/InlineLevelIterator.cpp
+++ b/Userland/Libraries/LibWeb/Layout/InlineLevelIterator.cpp
@@ -125,6 +125,37 @@ void InlineLevelIterator::skip_to_next()
}
Optional InlineLevelIterator::next()
+{
+ if (m_lookahead_items.is_empty())
+ return next_without_lookahead();
+ return m_lookahead_items.dequeue();
+}
+
+CSSPixels InlineLevelIterator::next_non_whitespace_sequence_width()
+{
+ CSSPixels next_width = 0;
+ for (;;) {
+ auto next_item_opt = next_without_lookahead();
+ if (!next_item_opt.has_value())
+ break;
+ m_lookahead_items.enqueue(next_item_opt.release_value());
+ auto& next_item = m_lookahead_items.tail();
+ if (next_item.node->computed_values().white_space() != CSS::WhiteSpace::Nowrap) {
+ if (next_item.type != InlineLevelIterator::Item::Type::Text)
+ break;
+ if (next_item.is_collapsible_whitespace)
+ break;
+ auto& next_text_node = verify_cast(*(next_item.node));
+ auto next_view = next_text_node.text_for_rendering().substring_view(next_item.offset_in_node, next_item.length_in_node);
+ if (next_view.is_whitespace())
+ break;
+ }
+ next_width += next_item.border_box_width();
+ }
+ return next_width;
+}
+
+Optional InlineLevelIterator::next_without_lookahead()
{
if (!m_current_node)
return {};
@@ -139,7 +170,7 @@ Optional InlineLevelIterator::next()
if (!chunk_opt.has_value()) {
m_text_node_context = {};
skip_to_next();
- return next();
+ return next_without_lookahead();
}
m_text_node_context->next_chunk = m_text_node_context->chunk_iterator.next();
@@ -200,12 +231,12 @@ Optional InlineLevelIterator::next()
if (is(*m_current_node)) {
skip_to_next();
- return next();
+ return next_without_lookahead();
}
if (!is(*m_current_node)) {
skip_to_next();
- return next();
+ return next_without_lookahead();
}
if (is(*m_current_node)) {
diff --git a/Userland/Libraries/LibWeb/Layout/InlineLevelIterator.h b/Userland/Libraries/LibWeb/Layout/InlineLevelIterator.h
index a8f15f48fb..0f194923c0 100644
--- a/Userland/Libraries/LibWeb/Layout/InlineLevelIterator.h
+++ b/Userland/Libraries/LibWeb/Layout/InlineLevelIterator.h
@@ -52,8 +52,10 @@ public:
InlineLevelIterator(Layout::InlineFormattingContext&, LayoutState&, Layout::BlockContainer const&, LayoutMode);
Optional- next();
+ CSSPixels next_non_whitespace_sequence_width();
private:
+ Optional
- next_without_lookahead();
void skip_to_next();
void compute_next();
@@ -96,6 +98,7 @@ private:
Optional m_extra_trailing_metrics;
Vector> m_box_model_node_stack;
+ Queue m_lookahead_items;
};
}
| |