Skip to content

Commit 5c9554c

Browse files
committed
feat: add property event listener for window and body element.
1 parent afd2644 commit 5c9554c

23 files changed

+159
-41
lines changed

bridge/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ if ($ENV{WEBF_JS_ENGINE} MATCHES "quickjs")
277277
core/frame/legacy/location.cc
278278
core/frame/legacy/location.h
279279
core/frame/module_callback_coordinator.h
280+
core/frame/window_event_handlers.h
280281
core/css/legacy/css_style_declaration.cc
281282
core/css/legacy/css_style_declaration.h
282283
core/dom/frame_request_callback_collection.cc

bridge/core/dom/document.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
*/
55
#include "document.h"
66
#include "bindings/qjs/exception_message.h"
7+
#include "core/frame/window.h"
78
#include "core/dom/element.h"
9+
#include "core/dom/comment.h"
10+
#include "core/dom/document_fragment.h"
11+
#include "core/dom/text.h"
812
#include "core/html/html_body_element.h"
913
#include "core/html/html_element.h"
1014
#include "core/html/html_head_element.h"
@@ -130,6 +134,10 @@ Node* Document::Clone(Document&, CloneChildrenFlag) const {
130134
return nullptr;
131135
}
132136

137+
HTMLHtmlElement* Document::documentElement() const {
138+
return DynamicTo<HTMLHtmlElement>(document_element_.Get());
139+
}
140+
133141
void Document::InitDocumentElement() {
134142
ExceptionState exception_state;
135143
AppendChild(document_element_, exception_state);
@@ -202,6 +210,18 @@ void Document::CancelAnimationFrame(uint32_t request_id, ExceptionState& excepti
202210
script_animation_controller_.CancelFrameCallback(GetExecutingContext(), request_id, exception_state);
203211
}
204212

213+
void Document::SetWindowAttributeEventListener(const AtomicString& event_type, const std::shared_ptr<EventListener>& listener, ExceptionState& exception_state) {
214+
Window* window = GetExecutingContext()->window();
215+
if (!window) return;
216+
window->SetAttributeEventListener(event_type, listener, exception_state);
217+
}
218+
219+
std::shared_ptr<EventListener> Document::GetWindowAttributeEventListener(const AtomicString& event_type) {
220+
Window* window = GetExecutingContext()->window();
221+
if (!window) return nullptr;
222+
return window->GetAttributeEventListener(event_type);
223+
}
224+
205225
void Document::Trace(GCVisitor* visitor) const {
206226
visitor->Trace(document_element_);
207227
script_animation_controller_.Trace(visitor);

bridge/core/dom/document.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77

88
#include "bindings/qjs/cppgc/local_handle.h"
99
#include "container_node.h"
10-
#include "core/dom/comment.h"
11-
#include "core/dom/document_fragment.h"
12-
#include "core/dom/text.h"
13-
#include "html_element_type_helper.h"
1410
#include "scripted_animation_controller.h"
1511
#include "tree_scope.h"
1612

@@ -19,6 +15,8 @@ namespace webf {
1915
class HTMLBodyElement;
2016
class HTMLHeadElement;
2117
class HTMLHtmlElement;
18+
class Text;
19+
class Comment;
2220

2321
// A document (https://dom.spec.whatwg.org/#concept-document) is the root node
2422
// of a tree of DOM nodes, generally resulting from the parsing of a markup
@@ -48,7 +46,7 @@ class Document : public ContainerNode, public TreeScope {
4846

4947
Node* Clone(Document&, CloneChildrenFlag) const override;
5048

51-
[[nodiscard]] HTMLHtmlElement* documentElement() const { return DynamicTo<HTMLHtmlElement>(document_element_.Get()); }
49+
[[nodiscard]] HTMLHtmlElement* documentElement() const;
5250
void InitDocumentElement();
5351

5452
// "body element" as defined by HTML5
@@ -71,6 +69,11 @@ class Document : public ContainerNode, public TreeScope {
7169
uint32_t RequestAnimationFrame(const std::shared_ptr<FrameCallback>& callback, ExceptionState& exception_state);
7270
void CancelAnimationFrame(uint32_t request_id, ExceptionState& exception_state);
7371

72+
// Helper functions for forwarding LocalDOMWindow event related tasks to the
73+
// LocalDOMWindow if it exists.
74+
void SetWindowAttributeEventListener(const AtomicString& event_type, const std::shared_ptr<EventListener>& listener, ExceptionState& exception_state);
75+
std::shared_ptr<EventListener> GetWindowAttributeEventListener(const AtomicString& event_type);
76+
7477
void Trace(GCVisitor* visitor) const override;
7578

7679
private:

bridge/core/dom/element.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
* Copyright (C) 2022-present The WebF authors. All rights reserved.
44
*/
55
#include "element.h"
6+
#include "text.h"
67

78
#include <utility>
89
#include "binding_call_methods.h"
910
#include "bindings/qjs/exception_state.h"
1011
#include "bindings/qjs/script_promise.h"
1112
#include "bindings/qjs/script_promise_resolver.h"
13+
#include "html_element_type_helper.h"
1214
#include "core/dom/document_fragment.h"
1315
#include "core/fileapi/blob.h"
1416
#include "core/html/html_template_element.h"

bridge/core/dom/events/event_target.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ EventTarget::~EventTarget() {
4545
EventTarget::EventTarget(ExecutingContext* context)
4646
: BindingObject(context), ScriptWrappable(context->ctx()), event_target_id_(global_event_target_id++) {}
4747

48+
Node* EventTarget::ToNode() {
49+
return nullptr;
50+
}
51+
4852
bool EventTarget::addEventListener(const AtomicString& event_type,
4953
const std::shared_ptr<EventListener>& event_listener,
5054
const std::shared_ptr<AddEventListenerOptions>& options,

bridge/core/dom/events/event_target.h

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ class EventTargetData final {
7272
std::unique_ptr<FiringEventIteratorVector> firing_event_iterators;
7373
};
7474

75+
class Node;
76+
7577
// All DOM event targets extend EventTarget. The spec is defined here:
7678
// https://dom.spec.whatwg.org/#interface-eventtarget
7779
// EventTarget objects allow us to add and remove an event
@@ -89,6 +91,8 @@ class EventTarget : public ScriptWrappable, public BindingObject {
8991
~EventTarget();
9092
explicit EventTarget(ExecutingContext* context);
9193

94+
virtual Node* ToNode();
95+
9296
bool addEventListener(const AtomicString& event_type,
9397
const std::shared_ptr<EventListener>& event_listener,
9498
const std::shared_ptr<AddEventListenerOptions>& options,
@@ -183,29 +187,28 @@ class EventTargetWithInlineData : public EventTarget {
183187
eventTarget.SetAttributeEventListener(event_type_names::symbol_name, listener, exception_state); \
184188
}
185189

186-
#define DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(lower_name, symbol_name) \
187-
EventListener* on##lower_name() { \
188-
return GetDocument().GetWindowAttributeEventListener(event_type_names::symbol_name); \
189-
} \
190-
void setOn##lower_name(EventListener* listener) { \
191-
GetDocument().SetWindowAttributeEventListener(event_type_names::symbol_name, listener); \
190+
#define DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(lower_name, symbol_name) \
191+
std::shared_ptr<EventListener> on##lower_name() { \
192+
return GetDocument().GetWindowAttributeEventListener(event_type_names::symbol_name); \
193+
} \
194+
void setOn##lower_name(const std::shared_ptr<EventListener>& listener, ExceptionState& exception_state) { \
195+
GetDocument().SetWindowAttributeEventListener(event_type_names::symbol_name, listener, exception_state); \
192196
}
193197

194-
#define DEFINE_STATIC_WINDOW_ATTRIBUTE_EVENT_LISTENER(lower_name, symbol_name) \
195-
static EventListener* on##lower_name(EventTarget& eventTarget) { \
196-
if (Node* node = eventTarget.ToNode()) { \
197-
return node->GetDocument().GetWindowAttributeEventListener(event_type_names::symbol_name); \
198-
} \
199-
DCHECK(eventTarget.ToLocalDOMWindow()); \
200-
return eventTarget.GetAttributeEventListener(event_type_names::symbol_name); \
201-
} \
202-
static void setOn##lower_name(EventTarget& eventTarget, EventListener* listener) { \
203-
if (Node* node = eventTarget.ToNode()) { \
204-
node->GetDocument().SetWindowAttributeEventListener(event_type_names::symbol_name, listener); \
205-
} else { \
206-
DCHECK(eventTarget.ToLocalDOMWindow()); \
207-
eventTarget.SetAttributeEventListener(event_type_names::symbol_name, listener); \
208-
} \
198+
#define DEFINE_STATIC_WINDOW_ATTRIBUTE_EVENT_LISTENER(lower_name, symbol_name) \
199+
static std::shared_ptr<EventListener> on##lower_name(EventTarget& eventTarget) { \
200+
if (Node* node = eventTarget.ToNode()) { \
201+
return node->GetDocument().GetWindowAttributeEventListener(event_type_names::symbol_name); \
202+
} \
203+
return eventTarget.GetAttributeEventListener(event_type_names::symbol_name); \
204+
} \
205+
static void setOn##lower_name(EventTarget& eventTarget, const std::shared_ptr<EventListener>& listener, \
206+
ExceptionState& exception_state) { \
207+
if (Node* node = eventTarget.ToNode()) { \
208+
node->GetDocument().SetWindowAttributeEventListener(event_type_names::symbol_name, listener, exception_state); \
209+
} else { \
210+
eventTarget.SetAttributeEventListener(event_type_names::symbol_name, listener, exception_state); \
211+
} \
209212
}
210213

211214
//

bridge/core/dom/global_event_handlers.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
type IDLEventHandler = Function;
22

3+
// @ts-ignore
4+
@Mixin()
35
export interface GlobalEventHandlers {
46
/**
57
* Fires when the user aborts the download.

bridge/core/dom/node.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <unordered_map>
88
#include "character_data.h"
99
#include "child_node_list.h"
10+
#include "element.h"
1011
#include "document.h"
1112
#include "document_fragment.h"
1213
#include "empty_node_list.h"
@@ -21,6 +22,10 @@ Node* Node::Create(ExecutingContext* context, ExceptionState& exception_state) {
2122
return nullptr;
2223
}
2324

25+
Node* Node::ToNode() {
26+
return this;
27+
}
28+
2429
void Node::setNodeValue(const AtomicString& value, ExceptionState& exception_state) {
2530
// By default, setting nodeValue has no effect.
2631
}

bridge/core/dom/node.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class Node : public EventTarget {
6060
using ImplType = Node*;
6161
static Node* Create(ExecutingContext* context, ExceptionState& exception_state);
6262

63+
Node* ToNode() override;
64+
6365
// DOM methods & attributes for Node
6466
virtual std::string nodeName() const = 0;
6567
virtual std::string nodeValue() const = 0;

bridge/core/executing_context.cc

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,7 @@ static void DispatchPromiseRejectionEvent(const AtomicString& event_type,
266266
event_init->setReason(Converter<IDLAny>::FromValue(context->ctx(), error, exception_state));
267267
auto event = PromiseRejectionEvent::Create(context, event_type, event_init, exception_state);
268268

269-
auto* window = toScriptWrappable<Window>(context->Global());
270-
window->dispatchEvent(event, exception_state);
269+
context->window()->dispatchEvent(event, exception_state);
271270
if (exception_state.HasException()) {
272271
context->ReportError(error);
273272
}
@@ -289,9 +288,8 @@ void ExecutingContext::DispatchErrorEvent(ErrorEvent* error_event) {
289288
void ExecutingContext::DispatchErrorEventInterval(ErrorEvent* error_event) {
290289
assert(!in_dispatch_error_event_);
291290
in_dispatch_error_event_ = true;
292-
auto* window = toScriptWrappable<Window>(Global());
293291
ExceptionState exception_state;
294-
window->dispatchEvent(error_event, exception_state);
292+
window_->dispatchEvent(error_event, exception_state);
295293
in_dispatch_error_event_ = false;
296294

297295
if (exception_state.HasException()) {
@@ -373,9 +371,9 @@ void ExecutingContext::InstallDocument() {
373371

374372
void ExecutingContext::InstallGlobal() {
375373
MemberMutationScope mutation_scope{this};
376-
auto* window = MakeGarbageCollected<Window>(this);
377-
JS_SetPrototype(ctx(), Global(), window->ToQuickJSUnsafe());
378-
JS_SetOpaque(Global(), window);
374+
window_ = MakeGarbageCollected<Window>(this);
375+
JS_SetPrototype(ctx(), Global(), window_->ToQuickJSUnsafe());
376+
JS_SetOpaque(Global(), window_);
379377
}
380378

381379
// An lock free context validator.

0 commit comments

Comments
 (0)