summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-08-28 13:42:07 +0200
committerAndreas Kling <kling@serenityos.org>2022-09-06 00:27:09 +0200
commit6f433c86564c24d47d520cb5bdcc2209d724ac96 (patch)
tree886a2f727782e466e99c61c628637872c1b7403f /Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
parentbb547ce1c4251e3689287eac845593398a379ca5 (diff)
downloadserenity-6f433c86564c24d47d520cb5bdcc2209d724ac96.zip
LibWeb+LibJS: Make the EventTarget hierarchy (incl. DOM) GC-allocated
This is a monster patch that turns all EventTargets into GC-allocated PlatformObjects. Their C++ wrapper classes are removed, and the LibJS garbage collector is now responsible for their lifetimes. There's a fair amount of hacks and band-aids in this patch, and we'll have a lot of cleanup to do after this.
Diffstat (limited to 'Userland/Libraries/LibWeb/HTML/HTMLElement.cpp')
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLElement.cpp66
1 files changed, 37 insertions, 29 deletions
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
index 592f354d46..05350872c7 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
@@ -7,6 +7,7 @@
#include <AK/StringBuilder.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Parser.h>
+#include <LibWeb/Bindings/HTMLElementPrototype.h>
#include <LibWeb/DOM/DOMException.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/ExceptionOr.h>
@@ -30,12 +31,19 @@ namespace Web::HTML {
HTMLElement::HTMLElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: Element(document, move(qualified_name))
- , m_dataset(JS::make_handle(DOMStringMap::create(*this)))
+ , m_dataset(DOMStringMap::create(*this))
{
+ set_prototype(&window().ensure_web_prototype<Bindings::HTMLElementPrototype>("HTMLElement"));
}
HTMLElement::~HTMLElement() = default;
+void HTMLElement::visit_edges(Cell::Visitor& visitor)
+{
+ Base::visit_edges(visitor);
+ visitor.visit(m_dataset.ptr());
+}
+
HTMLElement::ContentEditableState HTMLElement::content_editable_state() const
{
auto contenteditable = attribute(HTML::AttributeNames::contenteditable);
@@ -200,7 +208,7 @@ void HTMLElement::parse_attribute(FlyString const& name, String const& value)
}
// https://html.spec.whatwg.org/multipage/interaction.html#focus-update-steps
-static void run_focus_update_steps(NonnullRefPtrVector<DOM::Node> old_chain, NonnullRefPtrVector<DOM::Node> new_chain, DOM::Node& new_focus_target)
+static void run_focus_update_steps(Vector<JS::Handle<DOM::Node>> old_chain, Vector<JS::Handle<DOM::Node>> new_chain, DOM::Node& new_focus_target)
{
// 1. If the last entry in old chain and the last entry in new chain are the same,
// pop the last entry from old chain and the last entry from new chain and redo this step.
@@ -221,33 +229,33 @@ static void run_focus_update_steps(NonnullRefPtrVector<DOM::Node> old_chain, Non
// then fire an event named change at the element,
// with the bubbles attribute initialized to true.
- RefPtr<DOM::EventTarget> blur_event_target;
- if (is<DOM::Element>(entry)) {
+ JS::GCPtr<DOM::EventTarget> blur_event_target;
+ if (is<DOM::Element>(*entry)) {
// 2. If entry is an element, let blur event target be entry.
- blur_event_target = entry;
- } else if (is<DOM::Document>(entry)) {
+ 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,
// and the last entry in new chain is also an Element,
// then let related blur target be the last entry in new chain.
// Otherwise, let related blur target be null.
- RefPtr<DOM::EventTarget> related_blur_target;
+ JS::GCPtr<DOM::EventTarget> related_blur_target;
if (!old_chain.is_empty()
&& &entry == &old_chain.last()
- && is<DOM::Element>(entry)
+ && is<DOM::Element>(*entry)
&& !new_chain.is_empty()
- && is<DOM::Element>(new_chain.last())) {
- related_blur_target = new_chain.last();
+ && is<DOM::Element>(*new_chain.last())) {
+ related_blur_target = new_chain.last().ptr();
}
// 4. If blur event target is not null, fire a focus event named blur at blur event target,
// with related blur target as the related target.
if (blur_event_target) {
// FIXME: Implement the "fire a focus event" spec operation.
- auto blur_event = UIEvents::FocusEvent::create(verify_cast<DOM::Node>(*blur_event_target).document().preferred_window_object(), HTML::EventNames::blur);
+ auto blur_event = UIEvents::FocusEvent::create(verify_cast<DOM::Node>(*blur_event_target).document().window(), HTML::EventNames::blur);
blur_event->set_related_target(related_blur_target);
blur_event_target->dispatch_event(*blur_event);
}
@@ -261,50 +269,50 @@ static void run_focus_update_steps(NonnullRefPtrVector<DOM::Node> old_chain, Non
for (auto& entry : new_chain.in_reverse()) {
// 1. If entry is a focusable area: designate entry as the focused area of the document.
// FIXME: This isn't entirely right.
- if (is<DOM::Element>(entry))
- entry.document().set_focused_element(&static_cast<DOM::Element&>(entry));
+ if (is<DOM::Element>(*entry))
+ entry->document().set_focused_element(&static_cast<DOM::Element&>(*entry));
- RefPtr<DOM::EventTarget> focus_event_target;
- if (is<DOM::Element>(entry)) {
+ JS::GCPtr<DOM::EventTarget> focus_event_target;
+ if (is<DOM::Element>(*entry)) {
// 2. If entry is an element, let focus event target be entry.
- focus_event_target = entry;
- } else if (is<DOM::Document>(entry)) {
+ 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,
// and the last entry in old chain is also an Element,
// then let related focus target be the last entry in old chain.
// Otherwise, let related focus target be null.
- RefPtr<DOM::EventTarget> related_focus_target;
+ JS::GCPtr<DOM::EventTarget> related_focus_target;
if (!new_chain.is_empty()
&& &entry == &new_chain.last()
- && is<DOM::Element>(entry)
+ && is<DOM::Element>(*entry)
&& !old_chain.is_empty()
- && is<DOM::Element>(old_chain.last())) {
- related_focus_target = old_chain.last();
+ && is<DOM::Element>(*old_chain.last())) {
+ related_focus_target = old_chain.last().ptr();
}
// 4. If focus event target is not null, fire a focus event named focus at focus event target,
// with related focus target as the related target.
if (focus_event_target) {
// FIXME: Implement the "fire a focus event" spec operation.
- auto focus_event = UIEvents::FocusEvent::create(verify_cast<DOM::Node>(*focus_event_target).document().preferred_window_object(), HTML::EventNames::focus);
+ auto focus_event = UIEvents::FocusEvent::create(verify_cast<DOM::Node>(*focus_event_target).document().window(), HTML::EventNames::focus);
focus_event->set_related_target(related_focus_target);
focus_event_target->dispatch_event(*focus_event);
}
}
}
// https://html.spec.whatwg.org/multipage/interaction.html#focus-chain
-static NonnullRefPtrVector<DOM::Node> focus_chain(DOM::Node* subject)
+static Vector<JS::Handle<DOM::Node>> focus_chain(DOM::Node* subject)
{
// FIXME: Move this somewhere more spec-friendly.
if (!subject)
return {};
// 1. Let output be an empty list.
- NonnullRefPtrVector<DOM::Node> output;
+ Vector<JS::Handle<DOM::Node>> output;
// 2. Let currentObject be subject.
auto* current_object = subject;
@@ -312,7 +320,7 @@ static NonnullRefPtrVector<DOM::Node> focus_chain(DOM::Node* subject)
// 3. While true:
while (true) {
// 1. Append currentObject to output.
- output.append(*current_object);
+ output.append(JS::make_handle(*current_object));
// FIXME: 2. If currentObject is an area element's shape, then append that area element to output.
@@ -369,7 +377,7 @@ static void run_focusing_steps(DOM::Node* new_focus_target, DOM::Node* fallback_
if (!new_focus_target->document().browsing_context())
return;
auto& top_level_browsing_context = new_focus_target->document().browsing_context()->top_level_browsing_context();
- if (new_focus_target == top_level_browsing_context.currently_focused_area())
+ if (new_focus_target == top_level_browsing_context.currently_focused_area().ptr())
return;
// 6. Let old chain be the current focus chain of the top-level browsing context in which
@@ -411,7 +419,7 @@ bool HTMLElement::fire_a_synthetic_pointer_event(FlyString const& type, DOM::Ele
// 1. Let event be the result of creating an event using PointerEvent.
// 2. Initialize event's type attribute to e.
// FIXME: Actually create a PointerEvent!
- auto event = UIEvents::MouseEvent::create(document().preferred_window_object(), type);
+ auto event = UIEvents::MouseEvent::create(document().window(), type);
// 3. Initialize event's bubbles and cancelable attributes to true.
event->set_bubbles(true);