Commit e4d81dae authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

v8binding: Refactors MutationObserver and MutationCallback.

Major changes in this CL are:
- Drops [CustomConstructor] from MutationObserver.idl.
- Replaces hand-written V8MutationCallback with code-generated
  MutationCallback. Note that the new (code-generated)
  MutationCallback is different from the old (hand-written)
  MutationCallback.
- Rewrote the old (hand-written) MutationCallback as
  MutationObserver::Delegate.  Note that the name
  "MutationCallback" is taken by the new (code-generated)
  MutationCallback.

This CL mostly follows the same way as https://crrev.com/c/581128 .

Bug: 
Change-Id: I3f8b36044499c50baade331e2bfafbbed4271e0d
Reviewed-on: https://chromium-review.googlesource.com/590832Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarKenichi Ishibashi <bashi@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491297}
parent 379dacd4
...@@ -8,10 +8,10 @@ PASS typeof WebKitMutationObserver.prototype.observe is "function" ...@@ -8,10 +8,10 @@ PASS typeof WebKitMutationObserver.prototype.observe is "function"
PASS typeof WebKitMutationObserver.prototype.disconnect is "function" PASS typeof WebKitMutationObserver.prototype.disconnect is "function"
PASS typeof observer.observe is "function" PASS typeof observer.observe is "function"
PASS typeof observer.disconnect is "function" PASS typeof observer.disconnect is "function"
PASS new MutationObserver({ handleEvent: function() {} }) threw exception TypeError: Failed to construct 'MutationObserver': Callback argument must be a function. PASS new MutationObserver({ handleEvent: function() {} }) threw exception TypeError: Failed to construct 'MutationObserver': The callback provided as parameter 1 is not a function..
PASS new MutationObserver({}) threw exception TypeError: Failed to construct 'MutationObserver': Callback argument must be a function. PASS new MutationObserver({}) threw exception TypeError: Failed to construct 'MutationObserver': The callback provided as parameter 1 is not a function..
PASS new MutationObserver(42) threw exception TypeError: Failed to construct 'MutationObserver': Callback argument must be a function. PASS new MutationObserver(42) threw exception TypeError: Failed to construct 'MutationObserver': The callback provided as parameter 1 is not a function..
PASS new MutationObserver("foo") threw exception TypeError: Failed to construct 'MutationObserver': Callback argument must be a function. PASS new MutationObserver("foo") threw exception TypeError: Failed to construct 'MutationObserver': The callback provided as parameter 1 is not a function..
PASS successfullyParsed is true PASS successfullyParsed is true
TEST COMPLETE TEST COMPLETE
......
...@@ -21,7 +21,6 @@ bindings_core_v8_files = ...@@ -21,7 +21,6 @@ bindings_core_v8_files =
"core/v8/custom/V8MediaQueryListCustom.cpp", "core/v8/custom/V8MediaQueryListCustom.cpp",
"core/v8/custom/V8MessageChannelCustom.cpp", "core/v8/custom/V8MessageChannelCustom.cpp",
"core/v8/custom/V8MessageEventCustom.cpp", "core/v8/custom/V8MessageEventCustom.cpp",
"core/v8/custom/V8MutationObserverCustom.cpp",
"core/v8/custom/V8PopStateEventCustom.cpp", "core/v8/custom/V8PopStateEventCustom.cpp",
"core/v8/custom/V8PromiseRejectionEventCustom.cpp", "core/v8/custom/V8PromiseRejectionEventCustom.cpp",
"core/v8/custom/V8WindowCustom.cpp", "core/v8/custom/V8WindowCustom.cpp",
...@@ -137,8 +136,6 @@ bindings_core_v8_files = ...@@ -137,8 +136,6 @@ bindings_core_v8_files =
"core/v8/V8IteratorResultValue.h", "core/v8/V8IteratorResultValue.h",
"core/v8/V8LazyEventListener.cpp", "core/v8/V8LazyEventListener.cpp",
"core/v8/V8LazyEventListener.h", "core/v8/V8LazyEventListener.h",
"core/v8/V8MutationCallback.cpp",
"core/v8/V8MutationCallback.h",
"core/v8/V8NodeFilterCondition.cpp", "core/v8/V8NodeFilterCondition.cpp",
"core/v8/V8NodeFilterCondition.h", "core/v8/V8NodeFilterCondition.h",
"core/v8/V8ObjectBuilder.cpp", "core/v8/V8ObjectBuilder.cpp",
......
...@@ -109,6 +109,8 @@ generated_core_callback_function_files = [ ...@@ -109,6 +109,8 @@ generated_core_callback_function_files = [
"$bindings_core_v8_output_dir/IntersectionObserverCallback.h", "$bindings_core_v8_output_dir/IntersectionObserverCallback.h",
"$bindings_core_v8_output_dir/MojoWatchCallback.cpp", "$bindings_core_v8_output_dir/MojoWatchCallback.cpp",
"$bindings_core_v8_output_dir/MojoWatchCallback.h", "$bindings_core_v8_output_dir/MojoWatchCallback.h",
"$bindings_core_v8_output_dir/MutationCallback.cpp",
"$bindings_core_v8_output_dir/MutationCallback.h",
"$bindings_core_v8_output_dir/PerformanceObserverCallback.cpp", "$bindings_core_v8_output_dir/PerformanceObserverCallback.cpp",
"$bindings_core_v8_output_dir/PerformanceObserverCallback.h", "$bindings_core_v8_output_dir/PerformanceObserverCallback.h",
"$bindings_core_v8_output_dir/ReportingObserverCallback.cpp", "$bindings_core_v8_output_dir/ReportingObserverCallback.cpp",
......
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "bindings/core/v8/V8MutationCallback.h"
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "bindings/core/v8/V8MutationObserver.h"
#include "bindings/core/v8/V8MutationRecord.h"
#include "core/dom/ExecutionContext.h"
#include "platform/bindings/ScriptState.h"
#include "platform/bindings/V8PrivateProperty.h"
#include "platform/wtf/Assertions.h"
namespace blink {
V8MutationCallback::V8MutationCallback(v8::Local<v8::Function> callback,
v8::Local<v8::Object> owner,
ScriptState* script_state)
: callback_(script_state->GetIsolate(), this, callback),
script_state_(script_state) {
V8PrivateProperty::GetMutationObserverCallback(script_state->GetIsolate())
.Set(owner, callback);
}
V8MutationCallback::~V8MutationCallback() {}
void V8MutationCallback::Call(
const HeapVector<Member<MutationRecord>>& mutations,
MutationObserver* observer) {
if (callback_.IsEmpty())
return;
if (!script_state_->ContextIsValid())
return;
v8::Isolate* isolate = script_state_->GetIsolate();
ExecutionContext* execution_context =
ExecutionContext::From(script_state_.Get());
if (!execution_context || execution_context->IsContextSuspended() ||
execution_context->IsContextDestroyed())
return;
ScriptState::Scope scope(script_state_.Get());
v8::Local<v8::Value> observer_handle =
ToV8(observer, script_state_->GetContext()->Global(), isolate);
if (!observer_handle->IsObject())
return;
v8::Local<v8::Object> this_object =
v8::Local<v8::Object>::Cast(observer_handle);
v8::Local<v8::Value> v8_mutations =
ToV8(mutations, script_state_->GetContext()->Global(), isolate);
if (v8_mutations.IsEmpty())
return;
v8::Local<v8::Value> argv[] = {v8_mutations, observer_handle};
v8::TryCatch exception_catcher(isolate);
exception_catcher.SetVerbose(true);
V8ScriptRunner::CallFunction(callback_.NewLocal(isolate),
GetExecutionContext(), this_object,
WTF_ARRAY_LENGTH(argv), argv, isolate);
}
DEFINE_TRACE(V8MutationCallback) {
MutationCallback::Trace(visitor);
}
DEFINE_TRACE_WRAPPERS(V8MutationCallback) {
visitor->TraceWrappers(callback_.Cast<v8::Value>());
MutationCallback::TraceWrappers(visitor);
}
} // namespace blink
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef V8MutationCallback_h
#define V8MutationCallback_h
#include "core/dom/ExecutionContext.h"
#include "core/dom/MutationCallback.h"
#include "platform/bindings/ScopedPersistent.h"
#include "platform/bindings/ScriptState.h"
#include "platform/bindings/TraceWrapperV8Reference.h"
#include "platform/wtf/RefPtr.h"
#include "v8/include/v8.h"
namespace blink {
class ExecutionContext;
class V8MutationCallback final : public MutationCallback {
public:
static V8MutationCallback* Create(v8::Local<v8::Function> callback,
v8::Local<v8::Object> owner,
ScriptState* script_state) {
return new V8MutationCallback(callback, owner, script_state);
}
~V8MutationCallback() override;
void Call(const HeapVector<Member<MutationRecord>>&,
MutationObserver*) override;
ExecutionContext* GetExecutionContext() const override {
// The context might have navigated away or closed because this is an async
// call. Check if the context is still alive.
// TODO(yukishiino): Make (V8?)MutationCallback inherit from ContextClient.
v8::HandleScope scope(script_state_->GetIsolate());
if (script_state_->GetContext().IsEmpty())
return nullptr;
return ExecutionContext::From(script_state_.Get());
}
DECLARE_VIRTUAL_TRACE();
DECLARE_VIRTUAL_TRACE_WRAPPERS();
private:
V8MutationCallback(v8::Local<v8::Function>,
v8::Local<v8::Object>,
ScriptState*);
TraceWrapperV8Reference<v8::Function> callback_;
RefPtr<ScriptState> script_state_;
};
} // namespace blink
#endif // V8MutationCallback_h
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "bindings/core/v8/V8MutationObserver.h"
#include "bindings/core/v8/ExceptionMessages.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "bindings/core/v8/V8GCController.h"
#include "bindings/core/v8/V8MutationCallback.h"
#include "core/dom/MutationObserver.h"
#include "core/dom/Node.h"
#include "platform/bindings/V8DOMWrapper.h"
namespace blink {
void V8MutationObserver::constructorCustom(
const v8::FunctionCallbackInfo<v8::Value>& info) {
ExceptionState exception_state(info.GetIsolate(),
ExceptionState::kConstructionContext,
"MutationObserver");
if (info.Length() < 1) {
exception_state.ThrowTypeError(
ExceptionMessages::NotEnoughArguments(1, info.Length()));
return;
}
v8::Local<v8::Value> arg = info[0];
if (!arg->IsFunction()) {
exception_state.ThrowTypeError("Callback argument must be a function");
return;
}
v8::Local<v8::Object> wrapper = info.Holder();
MutationCallback* callback =
V8MutationCallback::Create(v8::Local<v8::Function>::Cast(arg), wrapper,
ScriptState::Current(info.GetIsolate()));
MutationObserver* observer = MutationObserver::Create(callback);
V8SetReturnValue(info,
V8DOMWrapper::AssociateObjectWithWrapper(
info.GetIsolate(), observer, &wrapperTypeInfo, wrapper));
}
} // namespace blink
...@@ -172,7 +172,6 @@ blink_core_sources("dom") { ...@@ -172,7 +172,6 @@ blink_core_sources("dom") {
"ModulePendingScript.h", "ModulePendingScript.h",
"ModuleScript.cpp", "ModuleScript.cpp",
"ModuleScript.h", "ModuleScript.h",
"MutationCallback.h",
"MutationObserver.cpp", "MutationObserver.cpp",
"MutationObserver.h", "MutationObserver.h",
"MutationObserverInterestGroup.cpp", "MutationObserverInterestGroup.cpp",
......
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MutationCallback_h
#define MutationCallback_h
#include "platform/bindings/ScriptWrappable.h"
#include "platform/heap/Handle.h"
#include "platform/wtf/Vector.h"
namespace blink {
class ExecutionContext;
class MutationRecord;
class MutationObserver;
class MutationCallback : public GarbageCollectedFinalized<MutationCallback>,
public TraceWrapperBase {
public:
virtual ~MutationCallback() {}
virtual void Call(const HeapVector<Member<MutationRecord>>&,
MutationObserver*) = 0;
virtual ExecutionContext* GetExecutionContext() const = 0;
DEFINE_INLINE_VIRTUAL_TRACE() {}
};
} // namespace blink
#endif // MutationCallback_h
...@@ -31,8 +31,11 @@ ...@@ -31,8 +31,11 @@
#include "core/dom/MutationObserver.h" #include "core/dom/MutationObserver.h"
#include <algorithm> #include <algorithm>
#include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/ExceptionState.h"
#include "core/dom/MutationCallback.h" #include "bindings/core/v8/MutationCallback.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "core/dom/ExecutionContext.h"
#include "core/dom/MutationObserverInit.h" #include "core/dom/MutationObserverInit.h"
#include "core/dom/MutationObserverRegistration.h" #include "core/dom/MutationObserverRegistration.h"
#include "core/dom/MutationRecord.h" #include "core/dom/MutationRecord.h"
...@@ -43,6 +46,47 @@ ...@@ -43,6 +46,47 @@
namespace blink { namespace blink {
class MutationObserver::V8DelegateImpl final
: public MutationObserver::Delegate,
public ContextClient {
USING_GARBAGE_COLLECTED_MIXIN(V8DelegateImpl);
public:
static V8DelegateImpl* Create(v8::Isolate* isolate,
MutationCallback* callback) {
ExecutionContext* execution_context =
ToExecutionContext(callback->v8Value(isolate)->CreationContext());
return new V8DelegateImpl(callback, execution_context);
}
ExecutionContext* GetExecutionContext() const override {
return ContextClient::GetExecutionContext();
}
void Deliver(const MutationRecordVector& records,
MutationObserver& observer) override {
// https://dom.spec.whatwg.org/#notify-mutation-observers
// step 5-4. specifies that the callback this value is a MutationObserver.
callback_->call(&observer, records, &observer);
}
DEFINE_INLINE_VIRTUAL_TRACE() {
visitor->Trace(callback_);
MutationObserver::Delegate::Trace(visitor);
ContextClient::Trace(visitor);
}
DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() { visitor->TraceWrappers(callback_); }
private:
V8DelegateImpl(MutationCallback* callback,
ExecutionContext* execution_context)
: ContextClient(execution_context), callback_(this, callback) {}
TraceWrapperMember<MutationCallback> callback_;
};
static unsigned g_observer_priority = 0; static unsigned g_observer_priority = 0;
struct MutationObserver::ObserverLessThan { struct MutationObserver::ObserverLessThan {
...@@ -52,13 +96,24 @@ struct MutationObserver::ObserverLessThan { ...@@ -52,13 +96,24 @@ struct MutationObserver::ObserverLessThan {
} }
}; };
MutationObserver* MutationObserver::Create(MutationCallback* callback) { MutationObserver* MutationObserver::Create(Delegate* delegate) {
DCHECK(IsMainThread()); DCHECK(IsMainThread());
return new MutationObserver(callback); return new MutationObserver(delegate->GetExecutionContext(), delegate);
} }
MutationObserver::MutationObserver(MutationCallback* callback) MutationObserver* MutationObserver::Create(ScriptState* script_state,
: callback_(this, callback), priority_(g_observer_priority++) {} MutationCallback* callback) {
DCHECK(IsMainThread());
return new MutationObserver(
ExecutionContext::From(script_state),
V8DelegateImpl::Create(script_state->GetIsolate(), callback));
}
MutationObserver::MutationObserver(ExecutionContext* execution_context,
Delegate* delegate)
: ContextClient(execution_context),
delegate_(this, delegate),
priority_(g_observer_priority++) {}
MutationObserver::~MutationObserver() { MutationObserver::~MutationObserver() {
CancelInspectorAsyncTasks(); CancelInspectorAsyncTasks();
...@@ -218,7 +273,7 @@ void MutationObserver::EnqueueMutationRecord(MutationRecord* mutation) { ...@@ -218,7 +273,7 @@ void MutationObserver::EnqueueMutationRecord(MutationRecord* mutation) {
DCHECK(IsMainThread()); DCHECK(IsMainThread());
records_.push_back(TraceWrapperMember<MutationRecord>(this, mutation)); records_.push_back(TraceWrapperMember<MutationRecord>(this, mutation));
ActivateObserver(this); ActivateObserver(this);
probe::AsyncTaskScheduled(callback_->GetExecutionContext(), mutation->type(), probe::AsyncTaskScheduled(delegate_->GetExecutionContext(), mutation->type(),
mutation); mutation);
} }
...@@ -235,13 +290,13 @@ HeapHashSet<Member<Node>> MutationObserver::GetObservedNodes() const { ...@@ -235,13 +290,13 @@ HeapHashSet<Member<Node>> MutationObserver::GetObservedNodes() const {
} }
bool MutationObserver::ShouldBeSuspended() const { bool MutationObserver::ShouldBeSuspended() const {
return callback_->GetExecutionContext() && const ExecutionContext* execution_context = delegate_->GetExecutionContext();
callback_->GetExecutionContext()->IsContextSuspended(); return execution_context && execution_context->IsContextSuspended();
} }
void MutationObserver::CancelInspectorAsyncTasks() { void MutationObserver::CancelInspectorAsyncTasks() {
for (auto& record : records_) for (auto& record : records_)
probe::AsyncTaskCanceled(callback_->GetExecutionContext(), record); probe::AsyncTaskCanceled(delegate_->GetExecutionContext(), record);
} }
void MutationObserver::Deliver() { void MutationObserver::Deliver() {
...@@ -265,9 +320,9 @@ void MutationObserver::Deliver() { ...@@ -265,9 +320,9 @@ void MutationObserver::Deliver() {
swap(records_, records, this); swap(records_, records, this);
// Report the first (earliest) stack as the async cause. // Report the first (earliest) stack as the async cause.
probe::AsyncTask async_task(callback_->GetExecutionContext(), probe::AsyncTask async_task(delegate_->GetExecutionContext(),
records.front()); records.front());
callback_->Call(records, this); delegate_->Deliver(records, *this);
} }
void MutationObserver::ResumeSuspendedObservers() { void MutationObserver::ResumeSuspendedObservers() {
...@@ -310,19 +365,15 @@ void MutationObserver::DeliverMutations() { ...@@ -310,19 +365,15 @@ void MutationObserver::DeliverMutations() {
slot->DispatchSlotChangeEvent(); slot->DispatchSlotChangeEvent();
} }
ExecutionContext* MutationObserver::GetExecutionContext() const {
return callback_->GetExecutionContext();
}
DEFINE_TRACE(MutationObserver) { DEFINE_TRACE(MutationObserver) {
visitor->Trace(callback_); visitor->Trace(delegate_);
visitor->Trace(records_); visitor->Trace(records_);
visitor->Trace(registrations_); visitor->Trace(registrations_);
visitor->Trace(callback_); ContextClient::Trace(visitor);
} }
DEFINE_TRACE_WRAPPERS(MutationObserver) { DEFINE_TRACE_WRAPPERS(MutationObserver) {
visitor->TraceWrappers(callback_); visitor->TraceWrappers(delegate_);
for (auto record : records_) for (auto record : records_)
visitor->TraceWrappers(record); visitor->TraceWrappers(record);
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "core/CoreExport.h" #include "core/CoreExport.h"
#include "core/dom/ContextLifecycleObserver.h"
#include "core/dom/ExecutionContext.h" #include "core/dom/ExecutionContext.h"
#include "platform/bindings/ScriptWrappable.h" #include "platform/bindings/ScriptWrappable.h"
#include "platform/bindings/TraceWrapperMember.h" #include "platform/bindings/TraceWrapperMember.h"
...@@ -51,6 +52,7 @@ class MutationObserverInit; ...@@ -51,6 +52,7 @@ class MutationObserverInit;
class MutationObserverRegistration; class MutationObserverRegistration;
class MutationRecord; class MutationRecord;
class Node; class Node;
class ScriptState;
typedef unsigned char MutationObserverOptions; typedef unsigned char MutationObserverOptions;
typedef unsigned char MutationRecordDeliveryOptions; typedef unsigned char MutationRecordDeliveryOptions;
...@@ -64,7 +66,8 @@ using MutationRecordVector = HeapVector<Member<MutationRecord>>; ...@@ -64,7 +66,8 @@ using MutationRecordVector = HeapVector<Member<MutationRecord>>;
class CORE_EXPORT MutationObserver final class CORE_EXPORT MutationObserver final
: public GarbageCollectedFinalized<MutationObserver>, : public GarbageCollectedFinalized<MutationObserver>,
public ActiveScriptWrappable<MutationObserver>, public ActiveScriptWrappable<MutationObserver>,
public ScriptWrappable { public ScriptWrappable,
public ContextClient {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(MutationObserver); USING_GARBAGE_COLLECTED_MIXIN(MutationObserver);
...@@ -84,7 +87,21 @@ class CORE_EXPORT MutationObserver final ...@@ -84,7 +87,21 @@ class CORE_EXPORT MutationObserver final
kCharacterDataOldValue = 1 << 6, kCharacterDataOldValue = 1 << 6,
}; };
static MutationObserver* Create(MutationCallback*); class CORE_EXPORT Delegate : public GarbageCollectedFinalized<Delegate>,
public TraceWrapperBase {
public:
virtual ~Delegate() = default;
virtual ExecutionContext* GetExecutionContext() const = 0;
virtual void Deliver(const MutationRecordVector& records,
MutationObserver&) = 0;
DEFINE_INLINE_VIRTUAL_TRACE() {}
DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() {}
};
class CORE_EXPORT V8DelegateImpl;
static MutationObserver* Create(Delegate*);
static MutationObserver* Create(ScriptState*, MutationCallback*);
static void ResumeSuspendedObservers(); static void ResumeSuspendedObservers();
static void DeliverMutations(); static void DeliverMutations();
static void EnqueueSlotChange(HTMLSlotElement&); static void EnqueueSlotChange(HTMLSlotElement&);
...@@ -103,7 +120,6 @@ class CORE_EXPORT MutationObserver final ...@@ -103,7 +120,6 @@ class CORE_EXPORT MutationObserver final
HeapHashSet<Member<Node>> GetObservedNodes() const; HeapHashSet<Member<Node>> GetObservedNodes() const;
bool HasPendingActivity() const override { return !records_.IsEmpty(); } bool HasPendingActivity() const override { return !records_.IsEmpty(); }
ExecutionContext* GetExecutionContext() const;
// Eagerly finalized as destructor accesses heap object members. // Eagerly finalized as destructor accesses heap object members.
EAGERLY_FINALIZE(); EAGERLY_FINALIZE();
...@@ -114,12 +130,12 @@ class CORE_EXPORT MutationObserver final ...@@ -114,12 +130,12 @@ class CORE_EXPORT MutationObserver final
private: private:
struct ObserverLessThan; struct ObserverLessThan;
explicit MutationObserver(MutationCallback*); MutationObserver(ExecutionContext*, Delegate*);
void Deliver(); void Deliver();
bool ShouldBeSuspended() const; bool ShouldBeSuspended() const;
void CancelInspectorAsyncTasks(); void CancelInspectorAsyncTasks();
TraceWrapperMember<MutationCallback> callback_; TraceWrapperMember<Delegate> delegate_;
HeapVector<TraceWrapperMember<MutationRecord>> records_; HeapVector<TraceWrapperMember<MutationRecord>> records_;
MutationObserverRegistrationSet registrations_; MutationObserverRegistrationSet registrations_;
unsigned priority_; unsigned priority_;
......
...@@ -30,8 +30,12 @@ ...@@ -30,8 +30,12 @@
// https://dom.spec.whatwg.org/#interface-mutationobserver // https://dom.spec.whatwg.org/#interface-mutationobserver
callback MutationCallback = void (sequence<MutationRecord> mutations,
MutationObserver observer);
[ [
CustomConstructor(MutationCallback callback), ConstructorCallWith=ScriptState,
Constructor(MutationCallback callback),
ActiveScriptWrappable, ActiveScriptWrappable,
DependentLifetime DependentLifetime
] interface MutationObserver { ] interface MutationObserver {
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include "core/dom/MutationObserver.h" #include "core/dom/MutationObserver.h"
#include "core/dom/MutationCallback.h"
#include "core/dom/MutationObserverInit.h" #include "core/dom/MutationObserverInit.h"
#include "core/dom/MutationObserverRegistration.h" #include "core/dom/MutationObserverRegistration.h"
#include "core/html/HTMLDocument.h" #include "core/html/HTMLDocument.h"
...@@ -15,22 +14,24 @@ namespace blink { ...@@ -15,22 +14,24 @@ namespace blink {
namespace { namespace {
class EmptyMutationCallback : public MutationCallback { class EmptyMutationCallback : public MutationObserver::Delegate {
public: public:
explicit EmptyMutationCallback(Document& document) : document_(document) {} explicit EmptyMutationCallback(Document& document) : document_(document) {}
ExecutionContext* GetExecutionContext() const override { return document_; }
void Deliver(const MutationRecordVector&, MutationObserver&) override {}
DEFINE_INLINE_VIRTUAL_TRACE() { DEFINE_INLINE_VIRTUAL_TRACE() {
visitor->Trace(document_); visitor->Trace(document_);
MutationCallback::Trace(visitor); MutationObserver::Delegate::Trace(visitor);
} }
private: private:
void Call(const HeapVector<Member<MutationRecord>>&,
MutationObserver*) override {}
ExecutionContext* GetExecutionContext() const override { return document_; }
Member<Document> document_; Member<Document> document_;
}; };
}
} // namespace
TEST(MutationObserverTest, DisconnectCrash) { TEST(MutationObserverTest, DisconnectCrash) {
Persistent<Document> document = HTMLDocument::CreateForTest(); Persistent<Document> document = HTMLDocument::CreateForTest();
......
...@@ -49,22 +49,22 @@ class Document; ...@@ -49,22 +49,22 @@ class Document;
class Element; class Element;
class ElementShadow; class ElementShadow;
class Event; class Event;
class EventDispatchHandlingState;
class ExceptionState; class ExceptionState;
class GetRootNodeOptions; class GetRootNodeOptions;
class HTMLQualifiedName; class HTMLQualifiedName;
class HTMLSlotElement; class HTMLSlotElement;
class IntRect; class IntRect;
class EventDispatchHandlingState; class KURL;
class LayoutBox;
class LayoutBoxModelObject;
class LayoutObject;
class NodeList; class NodeList;
class NodeListsNodeData; class NodeListsNodeData;
class NodeOrString; class NodeOrString;
class NodeRareData; class NodeRareData;
class QualifiedName; class QualifiedName;
class RegisteredEventListener; class RegisteredEventListener;
class LayoutBox;
class LayoutBoxModelObject;
class LayoutObject;
class ComputedStyle;
class SVGQualifiedName; class SVGQualifiedName;
class ShadowRoot; class ShadowRoot;
template <typename NodeType> template <typename NodeType>
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include "core/exported/WebFormElementObserverImpl.h" #include "core/exported/WebFormElementObserverImpl.h"
#include "core/css/CSSComputedStyleDeclaration.h" #include "core/css/CSSComputedStyleDeclaration.h"
#include "core/dom/MutationCallback.h"
#include "core/dom/MutationObserver.h" #include "core/dom/MutationObserver.h"
#include "core/dom/MutationObserverInit.h" #include "core/dom/MutationObserverInit.h"
#include "core/dom/MutationRecord.h" #include "core/dom/MutationRecord.h"
...@@ -19,20 +18,21 @@ ...@@ -19,20 +18,21 @@
namespace blink { namespace blink {
class WebFormElementObserverImpl::ObserverCallback : public MutationCallback { class WebFormElementObserverImpl::ObserverCallback
: public MutationObserver::Delegate {
public: public:
ObserverCallback(HTMLElement&, ObserverCallback(HTMLElement&,
std::unique_ptr<WebFormElementObserverCallback>); std::unique_ptr<WebFormElementObserverCallback>);
DECLARE_VIRTUAL_TRACE();
ExecutionContext* GetExecutionContext() const override; ExecutionContext* GetExecutionContext() const override;
void Deliver(const MutationRecordVector& records, MutationObserver&) override;
void Disconnect(); void Disconnect();
private: DECLARE_VIRTUAL_TRACE();
void Call(const HeapVector<Member<MutationRecord>>& records,
MutationObserver*) override;
private:
Member<HTMLElement> element_; Member<HTMLElement> element_;
Member<MutationObserver> mutation_observer_; Member<MutationObserver> mutation_observer_;
std::unique_ptr<WebFormElementObserverCallback> callback_; std::unique_ptr<WebFormElementObserverCallback> callback_;
...@@ -41,19 +41,13 @@ class WebFormElementObserverImpl::ObserverCallback : public MutationCallback { ...@@ -41,19 +41,13 @@ class WebFormElementObserverImpl::ObserverCallback : public MutationCallback {
WebFormElementObserverImpl::ObserverCallback::ObserverCallback( WebFormElementObserverImpl::ObserverCallback::ObserverCallback(
HTMLElement& element, HTMLElement& element,
std::unique_ptr<WebFormElementObserverCallback> callback) std::unique_ptr<WebFormElementObserverCallback> callback)
: element_(&element), callback_(std::move(callback)) { : element_(element),
DCHECK(element.ownerDocument()); mutation_observer_(MutationObserver::Create(this)),
mutation_observer_ = MutationObserver::Create(this); callback_(std::move(callback)) {
{ {
Vector<String> filter;
filter.ReserveCapacity(3);
filter.push_back(String("action"));
filter.push_back(String("class"));
filter.push_back(String("style"));
MutationObserverInit init; MutationObserverInit init;
init.setAttributes(true); init.setAttributes(true);
init.setAttributeFilter(filter); init.setAttributeFilter({"action", "class", "style"});
mutation_observer_->observe(element_, init, ASSERT_NO_EXCEPTION); mutation_observer_->observe(element_, init, ASSERT_NO_EXCEPTION);
} }
if (element_->parentElement()) { if (element_->parentElement()) {
...@@ -66,17 +60,12 @@ WebFormElementObserverImpl::ObserverCallback::ObserverCallback( ...@@ -66,17 +60,12 @@ WebFormElementObserverImpl::ObserverCallback::ObserverCallback(
ExecutionContext* ExecutionContext*
WebFormElementObserverImpl::ObserverCallback::GetExecutionContext() const { WebFormElementObserverImpl::ObserverCallback::GetExecutionContext() const {
return element_->ownerDocument(); return &element_->GetDocument();
}
void WebFormElementObserverImpl::ObserverCallback::Disconnect() {
mutation_observer_->disconnect();
callback_.reset();
} }
void WebFormElementObserverImpl::ObserverCallback::Call( void WebFormElementObserverImpl::ObserverCallback::Deliver(
const HeapVector<Member<MutationRecord>>& records, const MutationRecordVector& records,
MutationObserver*) { MutationObserver&) {
for (const auto& record : records) { for (const auto& record : records) {
if (record->type() == "childList") { if (record->type() == "childList") {
for (unsigned i = 0; i < record->removedNodes()->length(); ++i) { for (unsigned i = 0; i < record->removedNodes()->length(); ++i) {
...@@ -108,10 +97,15 @@ void WebFormElementObserverImpl::ObserverCallback::Call( ...@@ -108,10 +97,15 @@ void WebFormElementObserverImpl::ObserverCallback::Call(
} }
} }
void WebFormElementObserverImpl::ObserverCallback::Disconnect() {
mutation_observer_->disconnect();
callback_.reset();
}
DEFINE_TRACE(WebFormElementObserverImpl::ObserverCallback) { DEFINE_TRACE(WebFormElementObserverImpl::ObserverCallback) {
visitor->Trace(element_); visitor->Trace(element_);
visitor->Trace(mutation_observer_); visitor->Trace(mutation_observer_);
MutationCallback::Trace(visitor); MutationObserver::Delegate::Trace(visitor);
} }
WebFormElementObserver* WebFormElementObserver::Create( WebFormElementObserver* WebFormElementObserver::Create(
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "core/geometry/DOMMatrix.h" #include "core/geometry/DOMMatrix.h"
#include "core/dom/ExecutionContext.h"
namespace blink { namespace blink {
DOMMatrix* DOMMatrix::Create() { DOMMatrix* DOMMatrix::Create() {
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include "core/dom/AXObjectCache.h" #include "core/dom/AXObjectCache.h"
#include "core/dom/Attribute.h" #include "core/dom/Attribute.h"
#include "core/dom/ElementTraversal.h" #include "core/dom/ElementTraversal.h"
#include "core/dom/MutationCallback.h"
#include "core/dom/MutationObserver.h" #include "core/dom/MutationObserver.h"
#include "core/dom/MutationObserverInit.h" #include "core/dom/MutationObserverInit.h"
#include "core/dom/MutationRecord.h" #include "core/dom/MutationRecord.h"
...@@ -2003,17 +2002,29 @@ void HTMLSelectElement::ResetTypeAheadSessionForTesting() { ...@@ -2003,17 +2002,29 @@ void HTMLSelectElement::ResetTypeAheadSessionForTesting() {
// PopupUpdater notifies updates of the specified SELECT element subtree to // PopupUpdater notifies updates of the specified SELECT element subtree to
// a PopupMenu object. // a PopupMenu object.
class HTMLSelectElement::PopupUpdater : public MutationCallback { class HTMLSelectElement::PopupUpdater : public MutationObserver::Delegate {
public: public:
explicit PopupUpdater(HTMLSelectElement&); explicit PopupUpdater(HTMLSelectElement& select)
DECLARE_VIRTUAL_TRACE(); : select_(select), observer_(MutationObserver::Create(this)) {
MutationObserverInit init;
init.setAttributeOldValue(true);
init.setAttributes(true);
// Observe only attributes which affect popup content.
init.setAttributeFilter({"disabled", "label", "selected", "value"});
init.setCharacterData(true);
init.setCharacterDataOldValue(true);
init.setChildList(true);
init.setSubtree(true);
observer_->observe(select_, init, ASSERT_NO_EXCEPTION);
}
void Dispose() { observer_->disconnect(); } ExecutionContext* GetExecutionContext() const override {
return &select_->GetDocument();
}
private: void Deliver(const MutationRecordVector& records,
void Call(const HeapVector<Member<MutationRecord>>& records, MutationObserver&) override {
MutationObserver*) override { // We disconnect the MutationObserver when a popup is closed. However
// We disconnect the MutationObserver when a popuup is closed. However
// MutationObserver can call back after disconnection. // MutationObserver can call back after disconnection.
if (!select_->PopupIsVisible()) if (!select_->PopupIsVisible())
return; return;
...@@ -2031,41 +2042,19 @@ class HTMLSelectElement::PopupUpdater : public MutationCallback { ...@@ -2031,41 +2042,19 @@ class HTMLSelectElement::PopupUpdater : public MutationCallback {
} }
} }
ExecutionContext* GetExecutionContext() const override { void Dispose() { observer_->disconnect(); }
return &select_->GetDocument();
DEFINE_INLINE_VIRTUAL_TRACE() {
visitor->Trace(select_);
visitor->Trace(observer_);
MutationObserver::Delegate::Trace(visitor);
} }
private:
Member<HTMLSelectElement> select_; Member<HTMLSelectElement> select_;
Member<MutationObserver> observer_; Member<MutationObserver> observer_;
}; };
HTMLSelectElement::PopupUpdater::PopupUpdater(HTMLSelectElement& select)
: select_(select) {
observer_ = MutationObserver::Create(this);
Vector<String> filter;
filter.ReserveCapacity(4);
// Observe only attributes which affect popup content.
filter.push_back(String("disabled"));
filter.push_back(String("label"));
filter.push_back(String("selected"));
filter.push_back(String("value"));
MutationObserverInit init;
init.setAttributeOldValue(true);
init.setAttributes(true);
init.setAttributeFilter(filter);
init.setCharacterData(true);
init.setCharacterDataOldValue(true);
init.setChildList(true);
init.setSubtree(true);
observer_->observe(&select, init, ASSERT_NO_EXCEPTION);
}
DEFINE_TRACE(HTMLSelectElement::PopupUpdater) {
visitor->Trace(select_);
visitor->Trace(observer_);
MutationCallback::Trace(visitor);
}
void HTMLSelectElement::ObserveTreeMutation() { void HTMLSelectElement::ObserveTreeMutation() {
DCHECK(!popup_updater_); DCHECK(!popup_updater_);
popup_updater_ = new PopupUpdater(*this); popup_updater_ = new PopupUpdater(*this);
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "modules/media_controls/MediaControlsImpl.h" #include "modules/media_controls/MediaControlsImpl.h"
#include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/ExceptionState.h"
#include "core/dom/MutationCallback.h"
#include "core/dom/MutationObserver.h" #include "core/dom/MutationObserver.h"
#include "core/dom/MutationObserverInit.h" #include "core/dom/MutationObserverInit.h"
#include "core/dom/MutationRecord.h" #include "core/dom/MutationRecord.h"
...@@ -152,7 +151,7 @@ bool PreferHiddenVolumeControls(const Document& document) { ...@@ -152,7 +151,7 @@ bool PreferHiddenVolumeControls(const Document& document) {
document.GetSettings()->GetPreferHiddenVolumeControls(); document.GetSettings()->GetPreferHiddenVolumeControls();
} }
} // anonymous namespace } // namespace
class MediaControlsImpl::BatchedControlUpdate { class MediaControlsImpl::BatchedControlUpdate {
WTF_MAKE_NONCOPYABLE(BatchedControlUpdate); WTF_MAKE_NONCOPYABLE(BatchedControlUpdate);
...@@ -208,31 +207,23 @@ class MediaControlsImpl::MediaControlsResizeObserverDelegate final ...@@ -208,31 +207,23 @@ class MediaControlsImpl::MediaControlsResizeObserverDelegate final
// Observes changes to the HTMLMediaElement attributes that affect controls. // Observes changes to the HTMLMediaElement attributes that affect controls.
// Currently only observes the disableRemotePlayback attribute. // Currently only observes the disableRemotePlayback attribute.
class MediaControlsImpl::MediaElementMutationCallback class MediaControlsImpl::MediaElementMutationCallback
: public MutationCallback { : public MutationObserver::Delegate {
public: public:
explicit MediaElementMutationCallback(MediaControlsImpl* controls) explicit MediaElementMutationCallback(MediaControlsImpl* controls)
: controls_(controls) { : controls_(controls), observer_(MutationObserver::Create(this)) {
observer_ = MutationObserver::Create(this);
Vector<String> filter;
filter.push_back(HTMLNames::disableremoteplaybackAttr.ToString());
MutationObserverInit init; MutationObserverInit init;
init.setAttributeOldValue(true); init.setAttributeOldValue(true);
init.setAttributes(true); init.setAttributes(true);
init.setAttributeFilter(filter); init.setAttributeFilter({HTMLNames::disableremoteplaybackAttr.ToString()});
observer_->observe(&controls_->MediaElement(), init, ASSERT_NO_EXCEPTION); observer_->observe(&controls_->MediaElement(), init, ASSERT_NO_EXCEPTION);
} }
DEFINE_INLINE_VIRTUAL_TRACE() { ExecutionContext* GetExecutionContext() const override {
visitor->Trace(controls_); return &controls_->GetDocument();
visitor->Trace(observer_);
MutationCallback::Trace(visitor);
} }
void Disconnect() { observer_->disconnect(); } void Deliver(const MutationRecordVector& records,
MutationObserver&) override {
private:
void Call(const HeapVector<Member<MutationRecord>>& records,
MutationObserver*) override {
for (const auto& record : records) { for (const auto& record : records) {
if (record->type() != "attributes") if (record->type() != "attributes")
continue; continue;
...@@ -248,10 +239,15 @@ class MediaControlsImpl::MediaElementMutationCallback ...@@ -248,10 +239,15 @@ class MediaControlsImpl::MediaElementMutationCallback
} }
} }
ExecutionContext* GetExecutionContext() const override { void Disconnect() { observer_->disconnect(); }
return &controls_->GetDocument();
DEFINE_INLINE_VIRTUAL_TRACE() {
visitor->Trace(controls_);
visitor->Trace(observer_);
MutationObserver::Delegate::Trace(visitor);
} }
private:
Member<MediaControlsImpl> controls_; Member<MediaControlsImpl> controls_;
Member<MutationObserver> observer_; Member<MutationObserver> observer_;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment