2020-01-18 09:38:21 +01:00
|
|
|
/*
|
2024-10-04 13:19:50 +02:00
|
|
|
* Copyright (c) 2018-2023, Andreas Kling <andreas@ladybird.org>
|
2020-01-18 09:38:21 +01:00
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 09:38:21 +01:00
|
|
|
*/
|
|
|
|
|
2023-01-11 19:48:53 +01:00
|
|
|
#include <LibWeb/DOM/Range.h>
|
2020-03-07 10:32:51 +01:00
|
|
|
#include <LibWeb/Dump.h>
|
2024-10-14 16:07:56 +02:00
|
|
|
#include <LibWeb/Layout/TextNode.h>
|
2023-02-25 11:04:29 +01:00
|
|
|
#include <LibWeb/Layout/Viewport.h>
|
2022-03-10 23:13:37 +01:00
|
|
|
#include <LibWeb/Painting/PaintableBox.h>
|
2020-06-18 21:39:27 +02:00
|
|
|
#include <LibWeb/Painting/StackingContext.h>
|
2023-08-18 15:52:40 +02:00
|
|
|
#include <LibWeb/Painting/ViewportPaintable.h>
|
2019-06-15 22:49:44 +02:00
|
|
|
|
2020-11-22 15:53:01 +01:00
|
|
|
namespace Web::Layout {
|
2020-03-07 10:27:02 +01:00
|
|
|
|
2024-11-15 04:01:23 +13:00
|
|
|
GC_DEFINE_ALLOCATOR(Viewport);
|
2024-04-06 10:16:04 -07:00
|
|
|
|
2024-12-20 16:35:12 +01:00
|
|
|
Viewport::Viewport(DOM::Document& document, GC::Ref<CSS::ComputedProperties> style)
|
2021-10-06 20:02:41 +02:00
|
|
|
: BlockContainer(document, &document, move(style))
|
2019-06-15 22:49:44 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-02-25 11:04:29 +01:00
|
|
|
Viewport::~Viewport() = default;
|
2019-06-16 21:35:03 +02:00
|
|
|
|
2024-11-15 04:01:23 +13:00
|
|
|
GC::Ptr<Painting::Paintable> Viewport::create_paintable() const
|
2023-08-18 15:52:40 +02:00
|
|
|
{
|
|
|
|
return Painting::ViewportPaintable::create(*this);
|
|
|
|
}
|
|
|
|
|
2024-06-28 11:07:58 +01:00
|
|
|
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()
|
|
|
|
{
|
2025-07-09 14:13:38 -04:00
|
|
|
StringBuilder builder(StringBuilder::Mode::UTF16);
|
2024-06-28 11:07:58 +01:00
|
|
|
size_t current_start_position = 0;
|
|
|
|
Vector<TextPosition> text_positions;
|
|
|
|
Vector<TextBlock> text_blocks;
|
2025-07-09 14:13:38 -04:00
|
|
|
|
2024-06-28 11:07:58 +01:00
|
|
|
for_each_in_inclusive_subtree([&](auto const& layout_node) {
|
2024-10-16 15:19:32 +02:00
|
|
|
if (layout_node.display().is_none() || !layout_node.first_paintable() || !layout_node.first_paintable()->is_visible())
|
2024-06-28 11:07:58 +01:00
|
|
|
return TraversalDecision::Continue;
|
|
|
|
|
2025-07-26 12:40:34 +10:00
|
|
|
if (layout_node.is_box() || layout_node.is_generated_for_pseudo_element()) {
|
2024-06-28 11:07:58 +01:00
|
|
|
if (!builder.is_empty()) {
|
2025-07-09 14:13:38 -04:00
|
|
|
text_blocks.append({ builder.to_utf16_string(), text_positions });
|
2024-06-28 11:07:58 +01:00
|
|
|
current_start_position = 0;
|
|
|
|
text_positions.clear_with_capacity();
|
|
|
|
builder.clear();
|
|
|
|
}
|
|
|
|
return TraversalDecision::Continue;
|
|
|
|
}
|
|
|
|
|
2025-02-05 23:57:14 +00:00
|
|
|
if (auto* text_node = as_if<Layout::TextNode>(layout_node)) {
|
|
|
|
// https://html.spec.whatwg.org/multipage/interaction.html#inert-subtrees
|
|
|
|
// When a node is inert:
|
|
|
|
// - The user agent should ignore the node for the purposes of find-in-page.
|
|
|
|
if (auto& dom_node = const_cast<DOM::Text&>(text_node->dom_node()); !dom_node.is_inert()) {
|
|
|
|
if (text_positions.is_empty()) {
|
|
|
|
text_positions.empend(dom_node);
|
|
|
|
} else {
|
|
|
|
text_positions.empend(dom_node, current_start_position);
|
|
|
|
}
|
|
|
|
|
2025-07-25 09:34:41 -04:00
|
|
|
auto const& current_node_text = text_node->text_for_rendering();
|
2025-07-09 14:13:38 -04:00
|
|
|
current_start_position += current_node_text.length_in_code_units();
|
|
|
|
builder.append(current_node_text);
|
2024-06-28 11:07:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TraversalDecision::Continue;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!builder.is_empty())
|
2025-07-09 14:13:38 -04:00
|
|
|
text_blocks.append({ builder.to_utf16_string(), text_positions });
|
2024-06-28 11:07:58 +01:00
|
|
|
|
|
|
|
m_text_blocks = move(text_blocks);
|
|
|
|
}
|
|
|
|
|
2020-03-07 10:27:02 +01:00
|
|
|
}
|