mirror of
https://github.com/SerenityOS/serenity
synced 2026-05-10 00:52:28 +02:00
The first step of the find in page algorithm is to walk the layout tree of each document on the page and construct a list of strings against which to search for matches. Previously, this was being done for each new query, even when the page content hadn't been updated. The output of this process is now cached in the viewport node of the associated document. This ensures that this process is no longer repeated unnceessarily. (cherry picked from commit 156c1083e9de23a93075ec9e3c55cd5f93c48896)
94 lines
2.7 KiB
C++
94 lines
2.7 KiB
C++
/*
|
|
* Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibWeb/DOM/Range.h>
|
|
#include <LibWeb/Dump.h>
|
|
#include <LibWeb/Layout/Viewport.h>
|
|
#include <LibWeb/Painting/PaintableBox.h>
|
|
#include <LibWeb/Painting/StackingContext.h>
|
|
#include <LibWeb/Painting/ViewportPaintable.h>
|
|
|
|
namespace Web::Layout {
|
|
|
|
JS_DEFINE_ALLOCATOR(Viewport);
|
|
|
|
Viewport::Viewport(DOM::Document& document, NonnullRefPtr<CSS::StyleProperties> style)
|
|
: BlockContainer(document, &document, move(style))
|
|
{
|
|
}
|
|
|
|
Viewport::~Viewport() = default;
|
|
|
|
JS::GCPtr<Painting::Paintable> 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<Viewport::TextBlock> 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<TextPosition> text_positions;
|
|
Vector<TextBlock> 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::TextNode>(layout_node);
|
|
auto& dom_node = const_cast<DOM::Text&>(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);
|
|
}
|
|
|
|
}
|