diff options
Diffstat (limited to 'Libraries/LibWeb')
24 files changed, 182 insertions, 95 deletions
diff --git a/Libraries/LibWeb/Layout/LayoutBlock.cpp b/Libraries/LibWeb/Layout/LayoutBlock.cpp index 4d83f405be..aa525c186a 100644 --- a/Libraries/LibWeb/Layout/LayoutBlock.cpp +++ b/Libraries/LibWeb/Layout/LayoutBlock.cpp @@ -53,22 +53,27 @@ LayoutNode& LayoutBlock::inline_wrapper() return *last_child(); } -void LayoutBlock::layout() +void LayoutBlock::layout(LayoutMode line_break_policy) { compute_width(); if (!is_inline()) compute_position(); - if (children_are_inline()) - layout_inline_children(); - else - layout_block_children(); + layout_children(line_break_policy); compute_height(); } -void LayoutBlock::layout_block_children() +void LayoutBlock::layout_children(LayoutMode line_break_policy) +{ + if (children_are_inline()) + layout_inline_children(line_break_policy); + else + layout_block_children(line_break_policy); +} + +void LayoutBlock::layout_block_children(LayoutMode line_break_policy) { ASSERT(!children_are_inline()); float content_height = 0; @@ -77,19 +82,27 @@ void LayoutBlock::layout_block_children() if (child.is_inline()) return; auto& child_block = static_cast<LayoutBlock&>(child); - child_block.layout(); + child_block.layout(line_break_policy); content_height = child_block.rect().bottom() + child_block.box_model().full_margin().bottom - rect().top(); }); + if (line_break_policy != LayoutMode::Default) { + float max_width = 0; + for_each_child([&](auto& child) { + if (child.is_box()) + max_width = max(max_width, to<LayoutBox>(child).width()); + }); + rect().set_width(max_width); + } rect().set_height(content_height); } -void LayoutBlock::layout_inline_children() +void LayoutBlock::layout_inline_children(LayoutMode line_break_policy) { ASSERT(children_are_inline()); m_line_boxes.clear(); for_each_child([&](auto& child) { ASSERT(child.is_inline()); - child.split_into_lines(*this); + child.split_into_lines(*this, line_break_policy); }); for (auto& line_box : m_line_boxes) { @@ -112,6 +125,8 @@ void LayoutBlock::layout_inline_children() else if (text_align_string == "justify") text_align = CSS::ValueID::Justify; + float max_linebox_width = 0; + for (auto& line_box : m_line_boxes) { float max_height = min_line_height; for (auto& fragment : line_box.fragments()) { @@ -173,18 +188,24 @@ void LayoutBlock::layout_inline_children() if (fragment.layout_node().is_inline_block()) { auto& inline_block = const_cast<LayoutBlock&>(to<LayoutBlock>(fragment.layout_node())); inline_block.set_rect(fragment.rect()); - inline_block.layout(); + inline_block.layout(line_break_policy); } float final_line_box_width = 0; for (auto& fragment : line_box.fragments()) final_line_box_width += fragment.rect().width(); line_box.m_width = final_line_box_width; + + max_linebox_width = max(max_linebox_width, final_line_box_width); } content_height += max_height; } + if (line_break_policy != LayoutMode::Default) { + rect().set_width(max_linebox_width); + } + rect().set_height(content_height); } @@ -226,42 +247,94 @@ void LayoutBlock::compute_width() dbg() << "Total: " << total_px; #endif - // 10.3.3 Block-level, non-replaced elements in normal flow - // If 'width' is not 'auto' and 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larger than the width of the containing block, then any 'auto' values for 'margin-left' or 'margin-right' are, for the following rules, treated as zero. - if (width.is_auto() && total_px > containing_block.width()) { - if (margin_left.is_auto()) - margin_left = zero_value; - if (margin_right.is_auto()) - margin_right = zero_value; - } + if (!is_replaced() && !is_inline()) { + // 10.3.3 Block-level, non-replaced elements in normal flow + // If 'width' is not 'auto' and 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larger than the width of the containing block, then any 'auto' values for 'margin-left' or 'margin-right' are, for the following rules, treated as zero. + if (width.is_auto() && total_px > containing_block.width()) { + if (margin_left.is_auto()) + margin_left = zero_value; + if (margin_right.is_auto()) + margin_right = zero_value; + } - // 10.3.3 cont'd. - auto underflow_px = containing_block.width() - total_px; + // 10.3.3 cont'd. + auto underflow_px = containing_block.width() - total_px; + + if (width.is_auto()) { + if (margin_left.is_auto()) + margin_left = zero_value; + if (margin_right.is_auto()) + margin_right = zero_value; + if (underflow_px >= 0) { + width = Length(underflow_px, Length::Type::Absolute); + } else { + width = zero_value; + margin_right = Length(margin_right.to_px() + underflow_px, Length::Type::Absolute); + } + } else { + if (!margin_left.is_auto() && !margin_right.is_auto()) { + margin_right = Length(margin_right.to_px() + underflow_px, Length::Type::Absolute); + } else if (!margin_left.is_auto() && margin_right.is_auto()) { + margin_right = Length(underflow_px, Length::Type::Absolute); + } else if (margin_left.is_auto() && !margin_right.is_auto()) { + margin_left = Length(underflow_px, Length::Type::Absolute); + } else { // margin_left.is_auto() && margin_right.is_auto() + auto half_of_the_underflow = Length(underflow_px / 2, Length::Type::Absolute); + margin_left = half_of_the_underflow; + margin_right = half_of_the_underflow; + } + } + } else if (!is_replaced() && is_inline_block()) { + + // 10.3.9 'Inline-block', non-replaced elements in normal flow - if (width.is_auto()) { + // A computed value of 'auto' for 'margin-left' or 'margin-right' becomes a used value of '0'. if (margin_left.is_auto()) margin_left = zero_value; if (margin_right.is_auto()) margin_right = zero_value; - if (underflow_px >= 0) { - width = Length(underflow_px, Length::Type::Absolute); - } else { - width = zero_value; - margin_right = Length(margin_right.to_px() + underflow_px, Length::Type::Absolute); - } - } else { - if (!margin_left.is_auto() && !margin_right.is_auto()) { - margin_right = Length(margin_right.to_px() + underflow_px, Length::Type::Absolute); - } else if (!margin_left.is_auto() && margin_right.is_auto()) { - margin_right = Length(underflow_px, Length::Type::Absolute); - } else if (margin_left.is_auto() && !margin_right.is_auto()) { - margin_left = Length(underflow_px, Length::Type::Absolute); - } else { // margin_left.is_auto() && margin_right.is_auto() - auto half_of_the_underflow = Length(underflow_px / 2, Length::Type::Absolute); - margin_left = half_of_the_underflow; - margin_right = half_of_the_underflow; + + // If 'width' is 'auto', the used value is the shrink-to-fit width as for floating elements. + if (width.is_auto()) { + auto greatest_child_width = [&] { + float max_width = 0; + if (children_are_inline()) { + for (auto& box : line_boxes()) { + max_width = max(max_width, box.width()); + } + } else { + for_each_child([&](auto& child) { + if (child.is_box()) + max_width = max(max_width, to<LayoutBox>(child).width()); + }); + } + return max_width; + }; + + // Find the available width: in this case, this is the width of the containing + // block minus the used values of 'margin-left', 'border-left-width', 'padding-left', + // 'padding-right', 'border-right-width', 'margin-right', and the widths of any relevant scroll bars. + + float available_width = containing_block.width() + - margin_left.to_px() - border_left.to_px() - padding_left.to_px() + - padding_right.to_px() - border_right.to_px() - margin_right.to_px(); + + // Calculate the preferred width by formatting the content without breaking lines + // other than where explicit line breaks occur. + layout_children(LayoutMode::OnlyRequiredLineBreaks); + float preferred_width = greatest_child_width(); + + // Also calculate the preferred minimum width, e.g., by trying all possible line breaks. + // CSS 2.2 does not define the exact algorithm. + + layout_children(LayoutMode::AllPossibleLineBreaks); + float preferred_minimum_width = greatest_child_width(); + + // Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width). + width = Length(min(max(preferred_minimum_width, available_width), preferred_width), Length::Type::Absolute); } } + return width; }; @@ -428,11 +501,11 @@ LineBox& LayoutBlock::add_line_box() return m_line_boxes.last(); } -void LayoutBlock::split_into_lines(LayoutBlock& container) +void LayoutBlock::split_into_lines(LayoutBlock& container, LayoutMode line_break_policy) { ASSERT(is_inline()); - layout(); + layout(line_break_policy); auto* line_box = &container.ensure_last_line_box(); if (line_box->width() > 0 && line_box->width() + width() > container.width()) diff --git a/Libraries/LibWeb/Layout/LayoutBlock.h b/Libraries/LibWeb/Layout/LayoutBlock.h index 269eb2b6aa..597a3ac9b2 100644 --- a/Libraries/LibWeb/Layout/LayoutBlock.h +++ b/Libraries/LibWeb/Layout/LayoutBlock.h @@ -40,7 +40,7 @@ public: virtual const char* class_name() const override { return "LayoutBlock"; } - virtual void layout() override; + virtual void layout(LayoutMode = LayoutMode::Default) override; virtual void render(RenderingContext&) override; virtual LayoutNode& inline_wrapper() override; @@ -63,15 +63,17 @@ public: template<typename Callback> void for_each_fragment(Callback) const; - virtual void split_into_lines(LayoutBlock& container) override; + virtual void split_into_lines(LayoutBlock& container, LayoutMode) override; + private: virtual bool is_block() const override { return true; } NonnullRefPtr<StyleProperties> style_for_anonymous_block() const; - void layout_inline_children(); - void layout_block_children(); + void layout_children(LayoutMode); + void layout_inline_children(LayoutMode); + void layout_block_children(LayoutMode); void compute_width(); void compute_position(); diff --git a/Libraries/LibWeb/Layout/LayoutBreak.cpp b/Libraries/LibWeb/Layout/LayoutBreak.cpp index 9d0d2b768e..b4bcfec26d 100644 --- a/Libraries/LibWeb/Layout/LayoutBreak.cpp +++ b/Libraries/LibWeb/Layout/LayoutBreak.cpp @@ -39,7 +39,7 @@ LayoutBreak::~LayoutBreak() { } -void LayoutBreak::split_into_lines(LayoutBlock& block) +void LayoutBreak::split_into_lines(LayoutBlock& block, LayoutMode) { block.add_line_box(); } diff --git a/Libraries/LibWeb/Layout/LayoutBreak.h b/Libraries/LibWeb/Layout/LayoutBreak.h index 1fb28540d1..5c3dfb0986 100644 --- a/Libraries/LibWeb/Layout/LayoutBreak.h +++ b/Libraries/LibWeb/Layout/LayoutBreak.h @@ -40,7 +40,7 @@ public: private: virtual const char* class_name() const override { return "LayoutBreak"; } - virtual void split_into_lines(LayoutBlock&) override; + virtual void split_into_lines(LayoutBlock&, LayoutMode) override; }; } diff --git a/Libraries/LibWeb/Layout/LayoutCanvas.cpp b/Libraries/LibWeb/Layout/LayoutCanvas.cpp index deb316ea49..820ca07dfe 100644 --- a/Libraries/LibWeb/Layout/LayoutCanvas.cpp +++ b/Libraries/LibWeb/Layout/LayoutCanvas.cpp @@ -40,11 +40,11 @@ LayoutCanvas::~LayoutCanvas() { } -void LayoutCanvas::layout() +void LayoutCanvas::layout(LayoutMode line_break_policy) { rect().set_width(node().requested_width()); rect().set_height(node().requested_height()); - LayoutReplaced::layout(); + LayoutReplaced::layout(line_break_policy); } void LayoutCanvas::render(RenderingContext& context) diff --git a/Libraries/LibWeb/Layout/LayoutCanvas.h b/Libraries/LibWeb/Layout/LayoutCanvas.h index e2613fc780..931d36aa89 100644 --- a/Libraries/LibWeb/Layout/LayoutCanvas.h +++ b/Libraries/LibWeb/Layout/LayoutCanvas.h @@ -38,7 +38,7 @@ public: LayoutCanvas(const HTMLCanvasElement&, NonnullRefPtr<StyleProperties>); virtual ~LayoutCanvas() override; - virtual void layout() override; + virtual void layout(LayoutMode = LayoutMode::Default) override; virtual void render(RenderingContext&) override; const HTMLCanvasElement& node() const { return static_cast<const HTMLCanvasElement&>(LayoutReplaced::node()); } diff --git a/Libraries/LibWeb/Layout/LayoutDocument.cpp b/Libraries/LibWeb/Layout/LayoutDocument.cpp index d01a9787dd..7e6b77fe09 100644 --- a/Libraries/LibWeb/Layout/LayoutDocument.cpp +++ b/Libraries/LibWeb/Layout/LayoutDocument.cpp @@ -40,12 +40,12 @@ LayoutDocument::~LayoutDocument() { } -void LayoutDocument::layout() +void LayoutDocument::layout(LayoutMode line_break_policy) { ASSERT(document().frame()); rect().set_width(document().frame()->size().width()); - LayoutNode::layout(); + LayoutNode::layout(line_break_policy); ASSERT(!children_are_inline()); diff --git a/Libraries/LibWeb/Layout/LayoutDocument.h b/Libraries/LibWeb/Layout/LayoutDocument.h index 89dd0f3726..c89353b8ca 100644 --- a/Libraries/LibWeb/Layout/LayoutDocument.h +++ b/Libraries/LibWeb/Layout/LayoutDocument.h @@ -38,7 +38,7 @@ public: const Document& node() const { return static_cast<const Document&>(*LayoutNode::node()); } virtual const char* class_name() const override { return "LayoutDocument"; } - virtual void layout() override; + virtual void layout(LayoutMode = LayoutMode::Default) override; const LayoutRange& selection() const { return m_selection; } LayoutRange& selection() { return m_selection; } diff --git a/Libraries/LibWeb/Layout/LayoutImage.cpp b/Libraries/LibWeb/Layout/LayoutImage.cpp index 20a9538eff..d12246e4c9 100644 --- a/Libraries/LibWeb/Layout/LayoutImage.cpp +++ b/Libraries/LibWeb/Layout/LayoutImage.cpp @@ -40,7 +40,7 @@ LayoutImage::~LayoutImage() { } -void LayoutImage::layout() +void LayoutImage::layout(LayoutMode line_break_policy) { if (node().preferred_width() && node().preferred_height()) { rect().set_width(node().preferred_width()); @@ -57,7 +57,7 @@ void LayoutImage::layout() rect().set_height(16); } - LayoutReplaced::layout(); + LayoutReplaced::layout(line_break_policy); } void LayoutImage::render(RenderingContext& context) diff --git a/Libraries/LibWeb/Layout/LayoutImage.h b/Libraries/LibWeb/Layout/LayoutImage.h index 526d4832fc..2112bab079 100644 --- a/Libraries/LibWeb/Layout/LayoutImage.h +++ b/Libraries/LibWeb/Layout/LayoutImage.h @@ -38,7 +38,7 @@ public: LayoutImage(const HTMLImageElement&, NonnullRefPtr<StyleProperties>); virtual ~LayoutImage() override; - virtual void layout() override; + virtual void layout(LayoutMode = LayoutMode::Default) override; virtual void render(RenderingContext&) override; const HTMLImageElement& node() const { return static_cast<const HTMLImageElement&>(LayoutReplaced::node()); } diff --git a/Libraries/LibWeb/Layout/LayoutListItem.cpp b/Libraries/LibWeb/Layout/LayoutListItem.cpp index 2d14fb0ce6..c82c2cea08 100644 --- a/Libraries/LibWeb/Layout/LayoutListItem.cpp +++ b/Libraries/LibWeb/Layout/LayoutListItem.cpp @@ -38,14 +38,14 @@ LayoutListItem::~LayoutListItem() { } -void LayoutListItem::layout() +void LayoutListItem::layout(LayoutMode line_break_policy) { if (m_marker) { remove_child(*m_marker); m_marker = nullptr; } - LayoutBlock::layout(); + LayoutBlock::layout(line_break_policy); if (!m_marker) { m_marker = adopt(*new LayoutListItemMarker); diff --git a/Libraries/LibWeb/Layout/LayoutListItem.h b/Libraries/LibWeb/Layout/LayoutListItem.h index 7c3987570c..b5d4b03a24 100644 --- a/Libraries/LibWeb/Layout/LayoutListItem.h +++ b/Libraries/LibWeb/Layout/LayoutListItem.h @@ -38,7 +38,7 @@ public: LayoutListItem(const Element&, NonnullRefPtr<StyleProperties>); virtual ~LayoutListItem() override; - virtual void layout() override; + virtual void layout(LayoutMode = LayoutMode::Default) override; private: virtual const char* class_name() const override { return "LayoutListItem"; } diff --git a/Libraries/LibWeb/Layout/LayoutNode.cpp b/Libraries/LibWeb/Layout/LayoutNode.cpp index 5fd339c291..c784ac302c 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.cpp +++ b/Libraries/LibWeb/Layout/LayoutNode.cpp @@ -46,10 +46,10 @@ LayoutNode::~LayoutNode() m_node->set_layout_node({}, nullptr); } -void LayoutNode::layout() +void LayoutNode::layout(LayoutMode line_break_policy) { - for_each_child([](auto& child) { - child.layout(); + for_each_child([&](auto& child) { + child.layout(line_break_policy); }); } @@ -111,11 +111,11 @@ LayoutDocument& LayoutNode::root() return *document().layout_node(); } -void LayoutNode::split_into_lines(LayoutBlock& container) +void LayoutNode::split_into_lines(LayoutBlock& container, LayoutMode line_break_policy) { for_each_child([&](auto& child) { if (child.is_inline()) { - child.split_into_lines(container); + child.split_into_lines(container, line_break_policy); } else { // FIXME: Support block children of inlines. } diff --git a/Libraries/LibWeb/Layout/LayoutNode.h b/Libraries/LibWeb/Layout/LayoutNode.h index a9d64d61f5..b9a5adbb13 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.h +++ b/Libraries/LibWeb/Layout/LayoutNode.h @@ -99,7 +99,13 @@ public: bool is_inline_block() const { return is_inline() && is_block(); } - virtual void layout(); + enum class LayoutMode { + Default, + AllPossibleLineBreaks, + OnlyRequiredLineBreaks, + }; + + virtual void layout(LayoutMode); virtual void render(RenderingContext&); const LayoutBlock* containing_block() const; @@ -111,11 +117,11 @@ public: LayoutNodeWithStyle* parent(); const LayoutNodeWithStyle* parent() const; - void inserted_into(LayoutNode&) {} - void removed_from(LayoutNode&) {} - void children_changed() {} + void inserted_into(LayoutNode&) { } + void removed_from(LayoutNode&) { } + void children_changed() { } - virtual void split_into_lines(LayoutBlock& container); + virtual void split_into_lines(LayoutBlock& container, LayoutMode); bool is_visible() const { return m_visible; } void set_visible(bool visible) { m_visible = visible; } @@ -161,7 +167,7 @@ private: class LayoutNodeWithStyle : public LayoutNode { public: - virtual ~LayoutNodeWithStyle() override {} + virtual ~LayoutNodeWithStyle() override { } const StyleProperties& style() const { return m_style; } void set_style(const StyleProperties& style) { m_style = style; } diff --git a/Libraries/LibWeb/Layout/LayoutReplaced.cpp b/Libraries/LibWeb/Layout/LayoutReplaced.cpp index e98316ea73..904cf9769a 100644 --- a/Libraries/LibWeb/Layout/LayoutReplaced.cpp +++ b/Libraries/LibWeb/Layout/LayoutReplaced.cpp @@ -41,9 +41,9 @@ LayoutReplaced::~LayoutReplaced() { } -void LayoutReplaced::split_into_lines(LayoutBlock& container) +void LayoutReplaced::split_into_lines(LayoutBlock& container, LayoutMode line_break_policy) { - layout(); + layout(line_break_policy); auto* line_box = &container.ensure_last_line_box(); if (line_box->width() > 0 && line_box->width() + width() > container.width()) diff --git a/Libraries/LibWeb/Layout/LayoutReplaced.h b/Libraries/LibWeb/Layout/LayoutReplaced.h index d19c4e891a..f0446b116c 100644 --- a/Libraries/LibWeb/Layout/LayoutReplaced.h +++ b/Libraries/LibWeb/Layout/LayoutReplaced.h @@ -41,7 +41,7 @@ public: private: virtual const char* class_name() const override { return "LayoutReplaced"; } - virtual void split_into_lines(LayoutBlock& container) override; + virtual void split_into_lines(LayoutBlock& container, LayoutMode) override; }; template<> diff --git a/Libraries/LibWeb/Layout/LayoutTable.cpp b/Libraries/LibWeb/Layout/LayoutTable.cpp index 782e27e76d..8ad59649c0 100644 --- a/Libraries/LibWeb/Layout/LayoutTable.cpp +++ b/Libraries/LibWeb/Layout/LayoutTable.cpp @@ -39,10 +39,9 @@ LayoutTable::~LayoutTable() { } -void LayoutTable::layout() +void LayoutTable::layout(LayoutMode line_break_policy) { - - LayoutBlock::layout(); + LayoutBlock::layout(line_break_policy); } LayoutTableRow* LayoutTable::first_row() diff --git a/Libraries/LibWeb/Layout/LayoutTable.h b/Libraries/LibWeb/Layout/LayoutTable.h index 5166fc2a94..70b6b940ac 100644 --- a/Libraries/LibWeb/Layout/LayoutTable.h +++ b/Libraries/LibWeb/Layout/LayoutTable.h @@ -37,7 +37,7 @@ public: LayoutTable(const Element&, NonnullRefPtr<StyleProperties>); virtual ~LayoutTable() override; - virtual void layout() override; + virtual void layout(LayoutMode = LayoutMode::Default) override; LayoutTableRow* first_row(); const LayoutTableRow* first_row() const; diff --git a/Libraries/LibWeb/Layout/LayoutTableRow.cpp b/Libraries/LibWeb/Layout/LayoutTableRow.cpp index d8dc1f441c..9d0920d754 100644 --- a/Libraries/LibWeb/Layout/LayoutTableRow.cpp +++ b/Libraries/LibWeb/Layout/LayoutTableRow.cpp @@ -39,9 +39,9 @@ LayoutTableRow::~LayoutTableRow() { } -void LayoutTableRow::layout() +void LayoutTableRow::layout(LayoutMode line_break_policy) { - LayoutBox::layout(); + LayoutBox::layout(line_break_policy); } LayoutTableCell* LayoutTableRow::first_cell() diff --git a/Libraries/LibWeb/Layout/LayoutTableRow.h b/Libraries/LibWeb/Layout/LayoutTableRow.h index c77265fce8..ded261d16f 100644 --- a/Libraries/LibWeb/Layout/LayoutTableRow.h +++ b/Libraries/LibWeb/Layout/LayoutTableRow.h @@ -37,7 +37,7 @@ public: LayoutTableRow(const Element&, NonnullRefPtr<StyleProperties>); virtual ~LayoutTableRow() override; - virtual void layout() override; + virtual void layout(LayoutMode = LayoutMode::Default) override; LayoutTableCell* first_cell(); const LayoutTableCell* first_cell() const; diff --git a/Libraries/LibWeb/Layout/LayoutText.cpp b/Libraries/LibWeb/Layout/LayoutText.cpp index 406340b6db..a1d70087d3 100644 --- a/Libraries/LibWeb/Layout/LayoutText.cpp +++ b/Libraries/LibWeb/Layout/LayoutText.cpp @@ -95,7 +95,7 @@ void LayoutText::render_fragment(RenderingContext& context, const LineBoxFragmen } template<typename Callback> -void LayoutText::for_each_chunk(Callback callback, bool do_wrap_lines, bool do_wrap_breaks) const +void LayoutText::for_each_chunk(Callback callback, LayoutMode line_break_policy, bool do_wrap_lines, bool do_wrap_breaks) const { Utf8View view(m_text_for_rendering); if (view.is_empty()) @@ -103,7 +103,10 @@ void LayoutText::for_each_chunk(Callback callback, bool do_wrap_lines, bool do_w auto start_of_chunk = view.begin(); - auto commit_chunk = [&](auto it, bool has_breaking_newline) { + auto commit_chunk = [&](auto it, bool has_breaking_newline, bool must_commit = false) { + if (line_break_policy == LayoutMode::OnlyRequiredLineBreaks && !must_commit) + return; + int start = view.byte_offset_of(start_of_chunk); int length = view.byte_offset_of(it) - view.byte_offset_of(start_of_chunk); @@ -117,6 +120,9 @@ void LayoutText::for_each_chunk(Callback callback, bool do_wrap_lines, bool do_w bool last_was_space = isspace(*view.begin()); bool last_was_newline = false; for (auto it = view.begin(); it != view.end();) { + if (line_break_policy == LayoutMode::AllPossibleLineBreaks) { + commit_chunk(it, false); + } if (last_was_newline) { last_was_newline = false; commit_chunk(it, true); @@ -137,10 +143,10 @@ void LayoutText::for_each_chunk(Callback callback, bool do_wrap_lines, bool do_w if (last_was_newline) commit_chunk(view.end(), true); if (start_of_chunk != view.end()) - commit_chunk(view.end(), false); + commit_chunk(view.end(), false, true); } -void LayoutText::split_into_lines_by_rules(LayoutBlock& container, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks) +void LayoutText::split_into_lines_by_rules(LayoutBlock& container, LayoutMode line_break_policy, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks) { auto& font = style().font(); float space_width = font.glyph_width(' ') + font.glyph_spacing(); @@ -182,10 +188,11 @@ void LayoutText::split_into_lines_by_rules(LayoutBlock& container, bool do_colla }; Vector<Chunk> chunks; - for_each_chunk([&](const Utf8View& view, int start, int length, bool is_break) { - chunks.append({ Utf8View(view), start, length, is_break }); - }, - do_wrap_lines, do_wrap_breaks); + for_each_chunk( + [&](const Utf8View& view, int start, int length, bool is_break) { + chunks.append({ Utf8View(view), start, length, is_break }); + }, + line_break_policy, do_wrap_lines, do_wrap_breaks); for (size_t i = 0; i < chunks.size(); ++i) { auto& chunk = chunks[i]; @@ -229,7 +236,7 @@ void LayoutText::split_into_lines_by_rules(LayoutBlock& container, bool do_colla } } -void LayoutText::split_into_lines(LayoutBlock& container) +void LayoutText::split_into_lines(LayoutBlock& container, LayoutMode line_break_policy) { bool do_collapse = true; bool do_wrap_lines = true; @@ -254,7 +261,7 @@ void LayoutText::split_into_lines(LayoutBlock& container) do_wrap_breaks = true; } - split_into_lines_by_rules(container, do_collapse, do_wrap_lines, do_wrap_breaks); + split_into_lines_by_rules(container, line_break_policy, do_collapse, do_wrap_lines, do_wrap_breaks); } } diff --git a/Libraries/LibWeb/Layout/LayoutText.h b/Libraries/LibWeb/Layout/LayoutText.h index 0ab6373e44..bc8aac3a3e 100644 --- a/Libraries/LibWeb/Layout/LayoutText.h +++ b/Libraries/LibWeb/Layout/LayoutText.h @@ -48,15 +48,15 @@ public: void render_fragment(RenderingContext&, const LineBoxFragment&) const; - virtual void split_into_lines(LayoutBlock& container) override; + virtual void split_into_lines(LayoutBlock& container, LayoutMode) override; const StyleProperties& style() const { return parent()->style(); } private: - void split_into_lines_by_rules(LayoutBlock& container, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks); + void split_into_lines_by_rules(LayoutBlock& container, LayoutMode, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks); template<typename Callback> - void for_each_chunk(Callback, bool do_wrap_lines, bool do_wrap_breaks) const; + void for_each_chunk(Callback, LayoutMode, bool do_wrap_lines, bool do_wrap_breaks) const; String m_text_for_rendering; }; diff --git a/Libraries/LibWeb/Layout/LayoutWidget.cpp b/Libraries/LibWeb/Layout/LayoutWidget.cpp index b4f80290ea..acc02befcc 100644 --- a/Libraries/LibWeb/Layout/LayoutWidget.cpp +++ b/Libraries/LibWeb/Layout/LayoutWidget.cpp @@ -43,10 +43,10 @@ LayoutWidget::~LayoutWidget() widget().remove_from_parent(); } -void LayoutWidget::layout() +void LayoutWidget::layout(LayoutMode line_break_policy) { rect().set_size(widget().width(), widget().height()); - LayoutReplaced::layout(); + LayoutReplaced::layout(line_break_policy); widget().move_to(rect().x(), rect().y()); } diff --git a/Libraries/LibWeb/Layout/LayoutWidget.h b/Libraries/LibWeb/Layout/LayoutWidget.h index ab24c8dafc..e11c31f5cd 100644 --- a/Libraries/LibWeb/Layout/LayoutWidget.h +++ b/Libraries/LibWeb/Layout/LayoutWidget.h @@ -35,7 +35,7 @@ public: LayoutWidget(const Element&, GUI::Widget&); virtual ~LayoutWidget() override; - virtual void layout() override; + virtual void layout(LayoutMode = LayoutMode::Default) override; virtual void render(RenderingContext&) override; GUI::Widget& widget() { return m_widget; } |