mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:37:43 +00:00
LibWeb: Only allocate DOM::Node registered observer list on demand
Most DOM nodes don't have registered mutation observers, so let's put the metadata about them behind an OwnPtr to save space in the common case. Saves 16 bytes per DOM node that doesn't have registered observers.
This commit is contained in:
parent
c1fd55ce94
commit
9edfd5e360
4 changed files with 53 additions and 32 deletions
|
@ -608,10 +608,12 @@ void queue_mutation_observer_microtask(DOM::Document const& document)
|
|||
if (node.is_null())
|
||||
continue;
|
||||
|
||||
node->registered_observers_list().remove_all_matching([&mutation_observer](DOM::RegisteredObserver& registered_observer) {
|
||||
if (node->registered_observer_list()) {
|
||||
node->registered_observer_list()->remove_all_matching([&mutation_observer](DOM::RegisteredObserver& registered_observer) {
|
||||
return is<DOM::TransientRegisteredObserver>(registered_observer) && static_cast<DOM::TransientRegisteredObserver&>(registered_observer).observer().ptr() == mutation_observer.ptr();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 4. If records is not empty, then invoke mo’s callback with « records, mo », and mo. If this throws an exception, catch it, and report the exception.
|
||||
if (!records.is_empty()) {
|
||||
|
|
|
@ -85,7 +85,8 @@ WebIDL::ExceptionOr<void> MutationObserver::observe(Node& target, MutationObserv
|
|||
|
||||
// 7. For each registered of target’s registered observer list, if registered’s observer is this:
|
||||
bool updated_existing_observer = false;
|
||||
for (auto& registered_observer : target.registered_observers_list()) {
|
||||
if (target.registered_observer_list()) {
|
||||
for (auto& registered_observer : *target.registered_observer_list()) {
|
||||
if (registered_observer->observer().ptr() != this)
|
||||
continue;
|
||||
|
||||
|
@ -97,15 +98,18 @@ WebIDL::ExceptionOr<void> MutationObserver::observe(Node& target, MutationObserv
|
|||
if (node.is_null())
|
||||
continue;
|
||||
|
||||
node->registered_observers_list().remove_all_matching([®istered_observer](RegisteredObserver& observer) {
|
||||
if (node->registered_observer_list()) {
|
||||
node->registered_observer_list()->remove_all_matching([®istered_observer](RegisteredObserver& observer) {
|
||||
return is<TransientRegisteredObserver>(observer) && verify_cast<TransientRegisteredObserver>(observer).source().ptr() == registered_observer;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Set registered’s options to options.
|
||||
registered_observer->set_options(options);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 8. Otherwise:
|
||||
if (!updated_existing_observer) {
|
||||
|
@ -129,10 +133,12 @@ void MutationObserver::disconnect()
|
|||
if (node.is_null())
|
||||
continue;
|
||||
|
||||
node->registered_observers_list().remove_all_matching([this](RegisteredObserver& registered_observer) {
|
||||
if (node->registered_observer_list()) {
|
||||
node->registered_observer_list()->remove_all_matching([this](RegisteredObserver& registered_observer) {
|
||||
return registered_observer.observer().ptr() == this;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Empty this’s record queue.
|
||||
m_record_queue.clear();
|
||||
|
|
|
@ -103,8 +103,10 @@ void Node::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(m_layout_node);
|
||||
visitor.visit(m_paintable);
|
||||
|
||||
for (auto& registered_observer : m_registered_observer_list)
|
||||
if (m_registered_observer_list) {
|
||||
for (auto& registered_observer : *m_registered_observer_list)
|
||||
visitor.visit(registered_observer);
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-node-baseuri
|
||||
|
@ -686,10 +688,12 @@ void Node::remove(bool suppress_observers)
|
|||
// if registered’s options["subtree"] is true, then append a new transient registered observer
|
||||
// whose observer is registered’s observer, options is registered’s options, and source is registered to node’s registered observer list.
|
||||
for (auto* inclusive_ancestor = parent; inclusive_ancestor; inclusive_ancestor = inclusive_ancestor->parent()) {
|
||||
for (auto& registered : inclusive_ancestor->m_registered_observer_list) {
|
||||
if (!inclusive_ancestor->m_registered_observer_list)
|
||||
continue;
|
||||
for (auto& registered : *inclusive_ancestor->m_registered_observer_list) {
|
||||
if (registered->options().subtree) {
|
||||
auto transient_observer = TransientRegisteredObserver::create(registered->observer(), registered->options(), registered);
|
||||
m_registered_observer_list.append(move(transient_observer));
|
||||
m_registered_observer_list->append(move(transient_observer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1546,7 +1550,9 @@ void Node::queue_mutation_record(FlyString const& type, Optional<FlyString> cons
|
|||
// 2. Let nodes be the inclusive ancestors of target.
|
||||
// 3. For each node in nodes, and then for each registered of node’s registered observer list:
|
||||
for (auto* node = this; node; node = node->parent()) {
|
||||
for (auto& registered_observer : node->m_registered_observer_list) {
|
||||
if (!node->m_registered_observer_list)
|
||||
continue;
|
||||
for (auto& registered_observer : *node->m_registered_observer_list) {
|
||||
// 1. Let options be registered’s options.
|
||||
auto& options = registered_observer->options();
|
||||
|
||||
|
@ -1995,4 +2001,11 @@ ErrorOr<void> Node::prepend_with_space(StringBuilder x, StringView const& result
|
|||
return {};
|
||||
}
|
||||
|
||||
void Node::add_registered_observer(RegisteredObserver& registered_observer)
|
||||
{
|
||||
if (!m_registered_observer_list)
|
||||
m_registered_observer_list = make<Vector<JS::NonnullGCPtr<RegisteredObserver>>>();
|
||||
m_registered_observer_list->append(registered_observer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -254,10 +254,10 @@ public:
|
|||
|
||||
size_t length() const;
|
||||
|
||||
auto& registered_observers_list() { return m_registered_observer_list; }
|
||||
auto const& registered_observers_list() const { return m_registered_observer_list; }
|
||||
auto& registered_observer_list() { return m_registered_observer_list; }
|
||||
auto const& registered_observer_list() const { return m_registered_observer_list; }
|
||||
|
||||
void add_registered_observer(RegisteredObserver& registered_observer) { m_registered_observer_list.append(registered_observer); }
|
||||
void add_registered_observer(RegisteredObserver&);
|
||||
|
||||
void queue_mutation_record(FlyString const& type, Optional<FlyString> const& attribute_name, Optional<FlyString> const& attribute_namespace, Optional<String> const& old_value, Vector<JS::Handle<Node>> added_nodes, Vector<JS::Handle<Node>> removed_nodes, Node* previous_sibling, Node* next_sibling) const;
|
||||
|
||||
|
@ -693,7 +693,7 @@ protected:
|
|||
|
||||
// https://dom.spec.whatwg.org/#registered-observer-list
|
||||
// "Nodes have a strong reference to registered observers in their registered observer list." https://dom.spec.whatwg.org/#garbage-collection
|
||||
Vector<JS::NonnullGCPtr<RegisteredObserver>> m_registered_observer_list;
|
||||
OwnPtr<Vector<JS::NonnullGCPtr<RegisteredObserver>>> m_registered_observer_list;
|
||||
|
||||
void build_accessibility_tree(AccessibilityTreeNode& parent);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue