diff --git a/Userland/Libraries/LibWeb/Layout/BreakNode.h b/Userland/Libraries/LibWeb/Layout/BreakNode.h index 80ec3ed773..4276b4eaee 100644 --- a/Userland/Libraries/LibWeb/Layout/BreakNode.h +++ b/Userland/Libraries/LibWeb/Layout/BreakNode.h @@ -19,9 +19,13 @@ public: const HTML::HTMLBRElement& dom_node() const { return verify_cast(*Node::dom_node()); } private: + virtual bool is_break_node() const final { return true; } virtual void paint(PaintContext&, PaintPhase) override; virtual void split_into_lines(InlineFormattingContext&, LayoutMode) override; }; +template<> +inline bool Node::fast_is() const { return is_break_node(); } + } diff --git a/Userland/Libraries/LibWeb/Layout/LineBox.cpp b/Userland/Libraries/LibWeb/Layout/LineBox.cpp index de4d900ad4..50a65af787 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBox.cpp +++ b/Userland/Libraries/LibWeb/Layout/LineBox.cpp @@ -5,8 +5,10 @@ */ #include +#include #include #include +#include #include #include #include @@ -61,9 +63,13 @@ bool LineBox::is_empty_or_ends_in_whitespace() const { if (m_fragments.is_empty()) return true; - if (m_fragments.last().length() == 0) - return true; + return m_fragments.last().ends_in_whitespace(); } +bool LineBox::ends_with_forced_line_break() const +{ + return is(m_fragments.last().layout_node()); +} + } diff --git a/Userland/Libraries/LibWeb/Layout/LineBox.h b/Userland/Libraries/LibWeb/Layout/LineBox.h index 77fab5346c..6e6a3b3cd9 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBox.h +++ b/Userland/Libraries/LibWeb/Layout/LineBox.h @@ -26,6 +26,7 @@ public: void trim_trailing_whitespace(); bool is_empty_or_ends_in_whitespace() const; + bool ends_with_forced_line_break() const; private: friend class BlockContainer; diff --git a/Userland/Libraries/LibWeb/Layout/Node.h b/Userland/Libraries/LibWeb/Layout/Node.h index f9d384f190..f466652439 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.h +++ b/Userland/Libraries/LibWeb/Layout/Node.h @@ -99,6 +99,7 @@ public: // These are used to optimize hot is variants for some classes where dynamic_cast is too slow. virtual bool is_box() const { return false; } virtual bool is_block_container() const { return false; } + virtual bool is_break_node() const { return false; } virtual bool is_text_node() const { return false; } virtual bool is_initial_containing_block_box() const { return false; } virtual bool is_svg_box() const { return false; } diff --git a/Userland/Libraries/LibWeb/Layout/TextNode.cpp b/Userland/Libraries/LibWeb/Layout/TextNode.cpp index 76dc291508..e2aec8e005 100644 --- a/Userland/Libraries/LibWeb/Layout/TextNode.cpp +++ b/Userland/Libraries/LibWeb/Layout/TextNode.cpp @@ -217,7 +217,7 @@ void TextNode::split_into_lines_by_rules(InlineFormattingContext& context, Layou float chunk_width; if (do_wrap_lines) { - if (do_collapse && is_ascii_space(*chunk.view.begin()) && line_boxes.last().is_empty_or_ends_in_whitespace()) { + if (do_collapse && is_ascii_space(*chunk.view.begin()) && (line_boxes.last().is_empty_or_ends_in_whitespace() || line_boxes.last().ends_with_forced_line_break())) { // This is a non-empty chunk that starts with collapsible whitespace. // We are at either at the start of a new line, or after something that ended in whitespace, // so we don't need to contribute our own whitespace to the line. Skip over it instead!