diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 25b8e7ac22..2320a1ef2b 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -5111,65 +5111,13 @@ void Document::set_needs_to_refresh_scroll_state(bool b) Vector> Document::find_matching_text(String const& query, CaseSensitivity case_sensitivity) { - if (!document_element() || !document_element()->layout_node()) + if (!layout_node()) return {}; - struct TextPosition { - DOM::Text& dom_node; - size_t start_offset { 0 }; - }; - - struct TextBlock { - String text; - Vector positions; - }; - - auto gather_text_blocks = [&]() -> Vector { - StringBuilder builder; - size_t current_start_position = 0; - Vector text_positions; - Vector text_blocks; - document_element()->layout_node()->for_each_in_inclusive_subtree([&](auto const& layout_node) { - if (layout_node.display().is_none() || !layout_node.paintable() || !layout_node.paintable()->is_visible()) - return TraversalDecision::Continue; - - if (layout_node.is_block_container()) { - if (!builder.is_empty()) { - text_blocks.append({ builder.to_string_without_validation(), text_positions }); - current_start_position = 0; - text_positions.clear_with_capacity(); - builder.clear(); - } - return TraversalDecision::Continue; - } - - if (layout_node.is_text_node()) { - auto const& text_node = verify_cast(layout_node); - auto& dom_node = const_cast(text_node.dom_node()); - if (text_positions.is_empty()) { - text_positions.empend(dom_node); - } else { - text_positions.empend(dom_node, current_start_position); - } - - auto const& current_node_text = text_node.text_for_rendering(); - current_start_position += current_node_text.bytes_as_string_view().length(); - builder.append(move(current_node_text)); - } - - return TraversalDecision::Continue; - }); - - if (!builder.is_empty()) - text_blocks.append({ builder.to_string_without_validation(), text_positions }); - - return text_blocks; - }; - // Ensure the layout tree exists before searching for text matches. update_layout(); - auto text_blocks = gather_text_blocks(); + auto const& text_blocks = layout_node()->text_blocks(); if (text_blocks.is_empty()) return {}; diff --git a/Userland/Libraries/LibWeb/Layout/Viewport.cpp b/Userland/Libraries/LibWeb/Layout/Viewport.cpp index 81d97906c2..a5e77542ce 100644 --- a/Userland/Libraries/LibWeb/Layout/Viewport.cpp +++ b/Userland/Libraries/LibWeb/Layout/Viewport.cpp @@ -27,4 +27,67 @@ JS::GCPtr Viewport::create_paintable() const return Painting::ViewportPaintable::create(*this); } +void Viewport::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + if (!m_text_blocks.has_value()) + return; + + for (auto& text_block : *m_text_blocks) { + for (auto& text_position : text_block.positions) + visitor.visit(text_position.dom_node); + } +} + +Vector const& Viewport::text_blocks() +{ + if (!m_text_blocks.has_value()) + update_text_blocks(); + + return *m_text_blocks; +} + +void Viewport::update_text_blocks() +{ + StringBuilder builder; + size_t current_start_position = 0; + Vector text_positions; + Vector text_blocks; + for_each_in_inclusive_subtree([&](auto const& layout_node) { + if (layout_node.display().is_none() || !layout_node.paintable() || !layout_node.paintable()->is_visible()) + return TraversalDecision::Continue; + + if (layout_node.is_box()) { + if (!builder.is_empty()) { + text_blocks.append({ builder.to_string_without_validation(), text_positions }); + current_start_position = 0; + text_positions.clear_with_capacity(); + builder.clear(); + } + return TraversalDecision::Continue; + } + + if (layout_node.is_text_node()) { + auto const& text_node = verify_cast(layout_node); + auto& dom_node = const_cast(text_node.dom_node()); + if (text_positions.is_empty()) { + text_positions.empend(dom_node); + } else { + text_positions.empend(dom_node, current_start_position); + } + + auto const& current_node_text = text_node.text_for_rendering(); + current_start_position += current_node_text.bytes_as_string_view().length(); + builder.append(move(current_node_text)); + } + + return TraversalDecision::Continue; + }); + + if (!builder.is_empty()) + text_blocks.append({ builder.to_string_without_validation(), text_positions }); + + m_text_blocks = move(text_blocks); +} + } diff --git a/Userland/Libraries/LibWeb/Layout/Viewport.h b/Userland/Libraries/LibWeb/Layout/Viewport.h index 0280ba1a4d..2f44684548 100644 --- a/Userland/Libraries/LibWeb/Layout/Viewport.h +++ b/Userland/Libraries/LibWeb/Layout/Viewport.h @@ -19,12 +19,28 @@ public: explicit Viewport(DOM::Document&, NonnullRefPtr); virtual ~Viewport() override; + struct TextPosition { + JS::NonnullGCPtr dom_node; + size_t start_offset { 0 }; + }; + struct TextBlock { + String text; + Vector positions; + }; + Vector const& text_blocks(); + const DOM::Document& dom_node() const { return static_cast(*Node::dom_node()); } + virtual void visit_edges(Visitor&) override; + private: virtual JS::GCPtr create_paintable() const override; + void update_text_blocks(); + virtual bool is_viewport() const override { return true; } + + Optional> m_text_blocks; }; template<>