summaryrefslogtreecommitdiff
path: root/Libraries/LibWeb
diff options
context:
space:
mode:
Diffstat (limited to 'Libraries/LibWeb')
-rw-r--r--Libraries/LibWeb/Layout/LayoutBlock.cpp153
-rw-r--r--Libraries/LibWeb/Layout/LayoutBlock.h10
-rw-r--r--Libraries/LibWeb/Layout/LayoutBreak.cpp2
-rw-r--r--Libraries/LibWeb/Layout/LayoutBreak.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutCanvas.cpp4
-rw-r--r--Libraries/LibWeb/Layout/LayoutCanvas.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutDocument.cpp4
-rw-r--r--Libraries/LibWeb/Layout/LayoutDocument.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutImage.cpp4
-rw-r--r--Libraries/LibWeb/Layout/LayoutImage.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutListItem.cpp4
-rw-r--r--Libraries/LibWeb/Layout/LayoutListItem.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutNode.cpp10
-rw-r--r--Libraries/LibWeb/Layout/LayoutNode.h18
-rw-r--r--Libraries/LibWeb/Layout/LayoutReplaced.cpp4
-rw-r--r--Libraries/LibWeb/Layout/LayoutReplaced.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutTable.cpp5
-rw-r--r--Libraries/LibWeb/Layout/LayoutTable.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutTableRow.cpp4
-rw-r--r--Libraries/LibWeb/Layout/LayoutTableRow.h2
-rw-r--r--Libraries/LibWeb/Layout/LayoutText.cpp27
-rw-r--r--Libraries/LibWeb/Layout/LayoutText.h6
-rw-r--r--Libraries/LibWeb/Layout/LayoutWidget.cpp4
-rw-r--r--Libraries/LibWeb/Layout/LayoutWidget.h2
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; }