Coverage Report

Created: 2026-02-16 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibWeb/Internals/Internals.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibJS/Runtime/VM.h>
8
#include <LibWeb/Bindings/InternalsPrototype.h>
9
#include <LibWeb/Bindings/Intrinsics.h>
10
#include <LibWeb/DOM/Document.h>
11
#include <LibWeb/DOM/Event.h>
12
#include <LibWeb/DOM/EventTarget.h>
13
#include <LibWeb/DOMURL/DOMURL.h>
14
#include <LibWeb/HTML/BrowsingContext.h>
15
#include <LibWeb/HTML/HTMLElement.h>
16
#include <LibWeb/HTML/Window.h>
17
#include <LibWeb/Internals/Internals.h>
18
#include <LibWeb/Page/InputEvent.h>
19
#include <LibWeb/Page/Page.h>
20
#include <LibWeb/Painting/PaintableBox.h>
21
#include <LibWeb/Painting/ViewportPaintable.h>
22
23
namespace Web::Internals {
24
25
JS_DEFINE_ALLOCATOR(Internals);
26
27
Internals::Internals(JS::Realm& realm)
28
0
    : Bindings::PlatformObject(realm)
29
0
{
30
0
}
31
32
0
Internals::~Internals() = default;
33
34
void Internals::initialize(JS::Realm& realm)
35
0
{
36
0
    Base::initialize(realm);
37
0
    WEB_SET_PROTOTYPE_FOR_INTERFACE(Internals);
38
0
}
39
40
HTML::Window& Internals::internals_window() const
41
0
{
42
0
    return verify_cast<HTML::Window>(HTML::relevant_global_object(*this));
43
0
}
44
45
Page& Internals::internals_page() const
46
0
{
47
0
    return internals_window().page();
48
0
}
49
50
void Internals::signal_text_test_is_done(String const& text)
51
0
{
52
0
    internals_page().client().page_did_finish_text_test(text);
53
0
}
54
55
void Internals::gc()
56
0
{
57
0
    vm().heap().collect_garbage();
58
0
}
59
60
JS::Object* Internals::hit_test(double x, double y)
61
0
{
62
0
    auto& active_document = internals_window().associated_document();
63
    // NOTE: Force a layout update just before hit testing. This is because the current layout tree, which is required
64
    //       for stacking context traversal, might not exist if this call occurs between the tear_down_layout_tree()
65
    //       and update_layout() calls
66
0
    active_document.update_layout();
67
0
    auto result = active_document.paintable_box()->hit_test({ x, y }, Painting::HitTestType::Exact);
68
0
    if (result.has_value()) {
69
0
        auto hit_tеsting_result = JS::Object::create(realm(), nullptr);
70
0
        hit_tеsting_result->define_direct_property("node", result->dom_node(), JS::default_attributes);
71
0
        hit_tеsting_result->define_direct_property("indexInNode", JS::Value(result->index_in_node), JS::default_attributes);
72
0
        return hit_tеsting_result;
73
0
    }
74
0
    return nullptr;
75
0
}
76
77
void Internals::send_text(HTML::HTMLElement& target, String const& text, WebIDL::UnsignedShort modifiers)
78
0
{
79
0
    auto& page = internals_page();
80
0
    target.focus();
81
82
0
    for (auto code_point : text.code_points())
83
0
        page.handle_keydown(UIEvents::code_point_to_key_code(code_point), modifiers, code_point);
84
0
}
85
86
void Internals::send_key(HTML::HTMLElement& target, String const& key_name, WebIDL::UnsignedShort modifiers)
87
0
{
88
0
    auto key_code = UIEvents::key_code_from_string(key_name);
89
0
    target.focus();
90
91
0
    internals_page().handle_keydown(key_code, modifiers, 0);
92
0
}
93
94
void Internals::commit_text()
95
0
{
96
0
    internals_page().handle_keydown(UIEvents::Key_Return, 0, 0);
97
0
}
98
99
void Internals::click(double x, double y)
100
0
{
101
0
    click(x, y, UIEvents::MouseButton::Primary);
102
0
}
103
104
void Internals::middle_click(double x, double y)
105
0
{
106
0
    click(x, y, UIEvents::MouseButton::Middle);
107
0
}
108
109
void Internals::click(double x, double y, UIEvents::MouseButton button)
110
0
{
111
0
    auto& page = internals_page();
112
113
0
    auto position = page.css_to_device_point({ x, y });
114
0
    page.handle_mousedown(position, position, button, 0, 0);
115
0
    page.handle_mouseup(position, position, button, 0, 0);
116
0
}
117
118
void Internals::move_pointer_to(double x, double y)
119
0
{
120
0
    auto& page = internals_page();
121
122
0
    auto position = page.css_to_device_point({ x, y });
123
0
    page.handle_mousemove(position, position, 0, 0);
124
0
}
125
126
void Internals::wheel(double x, double y, double delta_x, double delta_y)
127
0
{
128
0
    auto& page = internals_page();
129
130
0
    auto position = page.css_to_device_point({ x, y });
131
0
    page.handle_mousewheel(position, position, 0, 0, 0, delta_x, delta_y);
132
0
}
133
134
WebIDL::ExceptionOr<bool> Internals::dispatch_user_activated_event(DOM::EventTarget& target, DOM::Event& event)
135
0
{
136
0
    event.set_is_trusted(true);
137
0
    return target.dispatch_event(event);
138
0
}
139
140
void Internals::spoof_current_url(String const& url_string)
141
0
{
142
0
    auto url = DOMURL::parse(url_string);
143
144
0
    VERIFY(url.is_valid());
145
146
0
    auto origin = url.origin();
147
148
0
    auto& window = internals_window();
149
0
    window.associated_document().set_url(url);
150
0
    window.associated_document().set_origin(origin);
151
0
    HTML::relevant_settings_object(window.associated_document()).creation_url = url;
152
0
}
153
154
JS::NonnullGCPtr<InternalAnimationTimeline> Internals::create_internal_animation_timeline()
155
0
{
156
0
    auto& realm = this->realm();
157
0
    return realm.heap().allocate<InternalAnimationTimeline>(realm, realm);
158
0
}
159
160
void Internals::simulate_drag_start(double x, double y, String const& name, String const& contents)
161
0
{
162
0
    Vector<HTML::SelectedFile> files;
163
0
    files.empend(name.to_byte_string(), MUST(ByteBuffer::copy(contents.bytes())));
164
165
0
    auto& page = internals_page();
166
167
0
    auto position = page.css_to_device_point({ x, y });
168
0
    page.handle_drag_and_drop_event(DragEvent::Type::DragStart, position, position, UIEvents::MouseButton::Primary, 0, 0, move(files));
169
0
}
170
171
void Internals::simulate_drag_move(double x, double y)
172
0
{
173
0
    auto& page = internals_page();
174
175
0
    auto position = page.css_to_device_point({ x, y });
176
0
    page.handle_drag_and_drop_event(DragEvent::Type::DragMove, position, position, UIEvents::MouseButton::Primary, 0, 0, {});
177
0
}
178
179
void Internals::simulate_drop(double x, double y)
180
0
{
181
0
    auto& page = internals_page();
182
183
0
    auto position = page.css_to_device_point({ x, y });
184
0
    page.handle_drag_and_drop_event(DragEvent::Type::Drop, position, position, UIEvents::MouseButton::Primary, 0, 0, {});
185
0
}
186
187
}