Coverage Report

Created: 2025-12-18 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibWeb/Layout/Viewport.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibWeb/DOM/Range.h>
8
#include <LibWeb/Dump.h>
9
#include <LibWeb/Layout/Viewport.h>
10
#include <LibWeb/Painting/PaintableBox.h>
11
#include <LibWeb/Painting/StackingContext.h>
12
#include <LibWeb/Painting/ViewportPaintable.h>
13
14
namespace Web::Layout {
15
16
JS_DEFINE_ALLOCATOR(Viewport);
17
18
Viewport::Viewport(DOM::Document& document, NonnullRefPtr<CSS::StyleProperties> style)
19
0
    : BlockContainer(document, &document, move(style))
20
0
{
21
0
}
22
23
0
Viewport::~Viewport() = default;
24
25
JS::GCPtr<Painting::Paintable> Viewport::create_paintable() const
26
0
{
27
0
    return Painting::ViewportPaintable::create(*this);
28
0
}
29
30
void Viewport::visit_edges(Visitor& visitor)
31
0
{
32
0
    Base::visit_edges(visitor);
33
0
    if (!m_text_blocks.has_value())
34
0
        return;
35
36
0
    for (auto& text_block : *m_text_blocks) {
37
0
        for (auto& text_position : text_block.positions)
38
0
            visitor.visit(text_position.dom_node);
39
0
    }
40
0
}
41
42
Vector<Viewport::TextBlock> const& Viewport::text_blocks()
43
0
{
44
0
    if (!m_text_blocks.has_value())
45
0
        update_text_blocks();
46
47
0
    return *m_text_blocks;
48
0
}
49
50
void Viewport::update_text_blocks()
51
0
{
52
0
    StringBuilder builder;
53
0
    size_t current_start_position = 0;
54
0
    Vector<TextPosition> text_positions;
55
0
    Vector<TextBlock> text_blocks;
56
0
    for_each_in_inclusive_subtree([&](auto const& layout_node) {
57
0
        if (layout_node.display().is_none() || !layout_node.paintable() || !layout_node.paintable()->is_visible())
58
0
            return TraversalDecision::Continue;
59
60
0
        if (layout_node.is_box() || layout_node.is_generated()) {
61
0
            if (!builder.is_empty()) {
62
0
                text_blocks.append({ builder.to_string_without_validation(), text_positions });
63
0
                current_start_position = 0;
64
0
                text_positions.clear_with_capacity();
65
0
                builder.clear();
66
0
            }
67
0
            return TraversalDecision::Continue;
68
0
        }
69
70
0
        if (layout_node.is_text_node()) {
71
0
            auto const& text_node = verify_cast<Layout::TextNode>(layout_node);
72
0
            auto& dom_node = const_cast<DOM::Text&>(text_node.dom_node());
73
0
            if (text_positions.is_empty()) {
74
0
                text_positions.empend(dom_node);
75
0
            } else {
76
0
                text_positions.empend(dom_node, current_start_position);
77
0
            }
78
79
0
            auto const& current_node_text = text_node.text_for_rendering();
80
0
            current_start_position += current_node_text.bytes_as_string_view().length();
81
0
            builder.append(move(current_node_text));
82
0
        }
83
84
0
        return TraversalDecision::Continue;
85
0
    });
86
87
0
    if (!builder.is_empty())
88
0
        text_blocks.append({ builder.to_string_without_validation(), text_positions });
89
90
0
    m_text_blocks = move(text_blocks);
91
0
}
92
93
}