1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 20:27:45 +00:00

LibWeb: Ignore window-forwarded document.body.onfoo in detached DOM

Normally, assigning to e.g document.body.onload will forward to
window.onload. However, in a detached DOM tree, there is no associated
window, so we have nowhere to forward to, making this a no-op.

The bulk of this change is making Document::window() return a nullable
pointer, as documents created by DOMParser or DOMImplementation do not
have an associated window object, and so must be able to return null
from here.
This commit is contained in:
Andreas Kling 2024-03-10 08:41:18 +01:00
parent 7139d5945f
commit b98a2be96b
28 changed files with 92 additions and 61 deletions

View file

@ -55,7 +55,7 @@ static void run_focus_update_steps(Vector<JS::Handle<DOM::Node>> old_chain, Vect
blur_event_target = entry.ptr();
} else if (is<DOM::Document>(*entry)) {
// If entry is a Document object, let blur event target be that Document object's relevant global object.
blur_event_target = &static_cast<DOM::Document&>(*entry).window();
blur_event_target = static_cast<DOM::Document&>(*entry).window();
}
// 3. If entry is the last entry in old chain, and entry is an Element,
@ -105,7 +105,7 @@ static void run_focus_update_steps(Vector<JS::Handle<DOM::Node>> old_chain, Vect
focus_event_target = entry.ptr();
} else if (is<DOM::Document>(*entry)) {
// If entry is a Document object, let focus event target be that Document object's relevant global object.
focus_event_target = &static_cast<DOM::Document&>(*entry).window();
focus_event_target = static_cast<DOM::Document&>(*entry).window();
}
// 3. If entry is the last entry in new chain, and entry is an Element,

View file

@ -12,14 +12,17 @@
namespace Web::HTML {
#undef __ENUMERATE
#define __ENUMERATE(attribute_name, event_name) \
void GlobalEventHandlers::set_##attribute_name(WebIDL::CallbackType* value) \
{ \
global_event_handlers_to_event_target(event_name).set_event_handler_attribute(event_name, value); \
} \
WebIDL::CallbackType* GlobalEventHandlers::attribute_name() \
{ \
return global_event_handlers_to_event_target(event_name).event_handler_attribute(event_name); \
#define __ENUMERATE(attribute_name, event_name) \
void GlobalEventHandlers::set_##attribute_name(WebIDL::CallbackType* value) \
{ \
if (auto event_target = global_event_handlers_to_event_target(event_name)) \
event_target->set_event_handler_attribute(event_name, value); \
} \
WebIDL::CallbackType* GlobalEventHandlers::attribute_name() \
{ \
if (auto event_target = global_event_handlers_to_event_target(event_name)) \
return event_target->event_handler_attribute(event_name); \
return nullptr; \
}
ENUMERATE_GLOBAL_EVENT_HANDLERS(__ENUMERATE)
#undef __ENUMERATE

View file

@ -94,7 +94,7 @@ public:
#undef __ENUMERATE
protected:
virtual DOM::EventTarget& global_event_handlers_to_event_target(FlyString const& event_name) = 0;
virtual JS::GCPtr<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const& event_name) = 0;
};
}

View file

@ -94,7 +94,7 @@ void HTMLBodyElement::attribute_changed(FlyString const& name, Optional<String>
#undef __ENUMERATE
}
DOM::EventTarget& HTMLBodyElement::global_event_handlers_to_event_target(FlyString const& event_name)
JS::GCPtr<DOM::EventTarget> HTMLBodyElement::global_event_handlers_to_event_target(FlyString const& event_name)
{
// NOTE: This is a little weird, but IIUC document.body.onload actually refers to window.onload
// NOTE: document.body can return either a HTMLBodyElement or HTMLFrameSetElement, so both these elements must support this mapping.
@ -104,7 +104,7 @@ DOM::EventTarget& HTMLBodyElement::global_event_handlers_to_event_target(FlyStri
return *this;
}
DOM::EventTarget& HTMLBodyElement::window_event_handlers_to_event_target()
JS::GCPtr<DOM::EventTarget> HTMLBodyElement::window_event_handlers_to_event_target()
{
// All WindowEventHandlers on HTMLFrameSetElement (e.g. document.body.onrejectionhandled) are mapped to window.on{event}.
// NOTE: document.body can return either a HTMLBodyElement or HTMLFrameSetElement, so both these elements must support this mapping.

View file

@ -38,10 +38,10 @@ private:
virtual void initialize(JS::Realm&) override;
// ^HTML::GlobalEventHandlers
virtual EventTarget& global_event_handlers_to_event_target(FlyString const& event_name) override;
virtual JS::GCPtr<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const& event_name) override;
// ^HTML::WindowEventHandlers
virtual EventTarget& window_event_handlers_to_event_target() override;
virtual JS::GCPtr<DOM::EventTarget> window_event_handlers_to_event_target() override;
RefPtr<CSS::ImageStyleValue> m_background_style_value;
};

View file

@ -82,7 +82,7 @@ private:
virtual bool is_html_element() const final { return true; }
// ^HTML::GlobalEventHandlers
virtual DOM::EventTarget& global_event_handlers_to_event_target(FlyString const&) override { return *this; }
virtual JS::GCPtr<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const&) override { return *this; }
virtual void did_receive_focus() override;
JS::GCPtr<DOMStringMap> m_dataset;

View file

@ -38,7 +38,7 @@ void HTMLFrameSetElement::attribute_changed(FlyString const& name, Optional<Stri
#undef __ENUMERATE
}
DOM::EventTarget& HTMLFrameSetElement::global_event_handlers_to_event_target(FlyString const& event_name)
JS::GCPtr<DOM::EventTarget> HTMLFrameSetElement::global_event_handlers_to_event_target(FlyString const& event_name)
{
// NOTE: This is a little weird, but IIUC document.body.onload actually refers to window.onload
// NOTE: document.body can return either a HTMLBodyElement or HTMLFrameSetElement, so both these elements must support this mapping.
@ -48,7 +48,7 @@ DOM::EventTarget& HTMLFrameSetElement::global_event_handlers_to_event_target(Fly
return *this;
}
DOM::EventTarget& HTMLFrameSetElement::window_event_handlers_to_event_target()
JS::GCPtr<DOM::EventTarget> HTMLFrameSetElement::window_event_handlers_to_event_target()
{
// All WindowEventHandlers on HTMLFrameSetElement (e.g. document.body.onrejectionhandled) are mapped to window.on{event}.
// NOTE: document.body can return either a HTMLBodyElement or HTMLFrameSetElement, so both these elements must support this mapping.

View file

@ -28,10 +28,10 @@ private:
virtual void attribute_changed(FlyString const&, Optional<String> const&) override;
// ^HTML::GlobalEventHandlers
virtual EventTarget& global_event_handlers_to_event_target(FlyString const& event_name) override;
virtual JS::GCPtr<EventTarget> global_event_handlers_to_event_target(FlyString const& event_name) override;
// ^HTML::WindowEventHandlers
virtual EventTarget& window_event_handlers_to_event_target() override;
virtual JS::GCPtr<EventTarget> window_event_handlers_to_event_target() override;
};
}

View file

@ -941,7 +941,7 @@ static void update_the_source_set(DOM::Element& element)
if (child->has_attribute(HTML::AttributeNames::media)) {
auto media_query = parse_media_query(CSS::Parser::ParsingContext { element.document() },
child->get_attribute_value(HTML::AttributeNames::media));
if (!media_query || !media_query->evaluate(element.document().window())) {
if (!media_query || !element.document().window() || !media_query->evaluate(*element.document().window())) {
continue;
}
}

View file

@ -64,7 +64,7 @@ void HTMLMetaElement::inserted()
auto media = attribute(AttributeNames::media);
if (media.has_value()) {
auto query = parse_media_query(context, media.value());
if (!query->evaluate(document().window()))
if (document().window() && !query->evaluate(*document().window()))
return;
}

View file

@ -328,7 +328,7 @@ void HTMLParser::the_end(JS::NonnullGCPtr<DOM::Document> document, JS::GCPtr<HTM
return;
// 3. Let window be the Document's relevant global object.
JS::NonnullGCPtr<Window> window = document->window();
auto& window = verify_cast<Window>(relevant_global_object(*document));
// 4. Set the Document's load timing info's load event start time to the current high resolution time given window.
document->load_timing_info().load_event_start_time = HighResolutionTime::unsafe_shared_current_time();
@ -336,7 +336,7 @@ void HTMLParser::the_end(JS::NonnullGCPtr<DOM::Document> document, JS::GCPtr<HTM
// 5. Fire an event named load at window, with legacy target override flag set.
// FIXME: The legacy target override flag is currently set by a virtual override of dispatch_event()
// We should reorganize this so that the flag appears explicitly here instead.
window->dispatch_event(DOM::Event::create(document->realm(), HTML::EventNames::load));
window.dispatch_event(DOM::Event::create(document->realm(), HTML::EventNames::load));
// FIXME: 6. Invoke WebDriver BiDi load complete with the Document's browsing context, and a new WebDriver BiDi navigation status whose id is the Document object's navigation id, status is "complete", and url is the Document object's URL.
@ -352,7 +352,7 @@ void HTMLParser::the_end(JS::NonnullGCPtr<DOM::Document> document, JS::GCPtr<HTM
document->set_page_showing(true);
// 11. Fire a page transition event named pageshow at window with false.
window->fire_a_page_transition_event(HTML::EventNames::pageshow, false);
window.fire_a_page_transition_event(HTML::EventNames::pageshow, false);
// 12. Completely finish loading the Document.
document->completely_finish_loading();

View file

@ -79,7 +79,7 @@ JS_DEFINE_ALLOCATOR(Window);
void run_animation_frame_callbacks(DOM::Document& document, double now)
{
// FIXME: Bring this closer to the spec.
document.window().animation_frame_callback_driver().run(now);
document.window()->animation_frame_callback_driver().run(now);
}
class IdleCallback : public RefCounted<IdleCallback> {

View file

@ -218,10 +218,10 @@ private:
virtual void finalize() override;
// ^HTML::GlobalEventHandlers
virtual DOM::EventTarget& global_event_handlers_to_event_target(FlyString const&) override { return *this; }
virtual JS::GCPtr<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const&) override { return *this; }
// ^HTML::WindowEventHandlers
virtual DOM::EventTarget& window_event_handlers_to_event_target() override { return *this; }
virtual JS::GCPtr<DOM::EventTarget> window_event_handlers_to_event_target() override { return *this; }
void invoke_idle_callbacks();

View file

@ -11,14 +11,17 @@
namespace Web::HTML {
#undef __ENUMERATE
#define __ENUMERATE(attribute_name, event_name) \
void WindowEventHandlers::set_##attribute_name(WebIDL::CallbackType* value) \
{ \
window_event_handlers_to_event_target().set_event_handler_attribute(event_name, value); \
} \
WebIDL::CallbackType* WindowEventHandlers::attribute_name() \
{ \
return window_event_handlers_to_event_target().event_handler_attribute(event_name); \
#define __ENUMERATE(attribute_name, event_name) \
void WindowEventHandlers::set_##attribute_name(WebIDL::CallbackType* value) \
{ \
if (auto event_target = window_event_handlers_to_event_target()) \
event_target->set_event_handler_attribute(event_name, value); \
} \
WebIDL::CallbackType* WindowEventHandlers::attribute_name() \
{ \
if (auto event_target = window_event_handlers_to_event_target()) \
return event_target->event_handler_attribute(event_name); \
return nullptr; \
}
ENUMERATE_WINDOW_EVENT_HANDLERS(__ENUMERATE)
#undef __ENUMERATE

View file

@ -41,7 +41,7 @@ public:
#undef __ENUMERATE
protected:
virtual DOM::EventTarget& window_event_handlers_to_event_target() = 0;
virtual JS::GCPtr<DOM::EventTarget> window_event_handlers_to_event_target() = 0;
};
}