// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_CALLBACK_INTERFACE_BASE_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_CALLBACK_INTERFACE_BASE_H_ #include "third_party/blink/renderer/platform/bindings/name_client.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h" #include "third_party/blink/renderer/platform/heap/handle.h" namespace blink { class V8PersistentCallbackInterfaceBase; // CallbackInterfaceBase is the common base class of all the callback interface // classes. Most importantly this class provides a way of type dispatching (e.g. // overload resolutions, SFINAE technique, etc.) so that it's possible to // distinguish callback interfaces from anything else. Also it provides a common // implementation of callback interfaces. // // As the signatures of callback interface's operations vary, this class does // not implement any operation. Subclasses will implement it. class PLATFORM_EXPORT CallbackInterfaceBase : public GarbageCollectedFinalized, public NameClient { public: // Whether the callback interface is a "single operation callback interface" // or not. // https://heycam.github.io/webidl/#dfn-single-operation-callback-interface enum SingleOperationOrNot { kNotSingleOperation, kSingleOperation, }; virtual ~CallbackInterfaceBase() = default; virtual void Trace(blink::Visitor*); // Check the identity of |callback_object_|. There can be multiple // CallbackInterfaceBase objects that have the same |callback_object_| but // have different |incumbent_script_state_|s. bool HasTheSameCallbackObject(const CallbackInterfaceBase& other) const { return callback_object_ == other.callback_object_; } v8::Local CallbackObject() { return callback_object_.NewLocal(GetIsolate()); } v8::Isolate* GetIsolate() { return incumbent_script_state_->GetIsolate(); } // Returns the ScriptState of the relevant realm of the callback object. // // NOTE: This function must be used only when it's pretty sure that the // callcack object is the same origin-domain. Otherwise, // |CallbackRelevantScriptStateOrReportError| or // |CallbackRelevantScriptStateOrThrowException| must be used instead. ScriptState* CallbackRelevantScriptState() { DCHECK(callback_relevant_script_state_); return callback_relevant_script_state_; } // Returns the ScriptState of the relevant realm of the callback object iff // the callback is the same origin-domain. Otherwise, reports an error and // returns nullptr. ScriptState* CallbackRelevantScriptStateOrReportError(const char* interface, const char* operation); // Returns the ScriptState of the relevant realm of the callback object iff // the callback is the same origin-domain. Otherwise, throws an exception and // returns nullptr. ScriptState* CallbackRelevantScriptStateOrThrowException( const char* interface, const char* operation); DOMWrapperWorld& GetWorld() const { return incumbent_script_state_->World(); } // NodeIteratorBase counts the invocation of those which are callable and // those which are not. bool IsCallbackObjectCallableForNodeIteratorBase() const { return IsCallbackObjectCallable(); } protected: explicit CallbackInterfaceBase(v8::Local callback_object, SingleOperationOrNot); // Returns true iff the callback interface is a single operation callback // interface and the callback interface type value is callable. bool IsCallbackObjectCallable() const { return is_callback_object_callable_; } ScriptState* IncumbentScriptState() { return incumbent_script_state_; } private: // The "callback interface type" value. TraceWrapperV8Reference callback_object_; bool is_callback_object_callable_ = false; // The associated Realm of the callback interface type value. Note that the // callback interface type value can be different from the function object // to be invoked. Member callback_relevant_script_state_; // The callback context, i.e. the incumbent Realm when an ECMAScript value is // converted to an IDL value. // https://heycam.github.io/webidl/#dfn-callback-context Member incumbent_script_state_; friend class V8PersistentCallbackInterfaceBase; }; // V8PersistentCallbackInterfaceBase retains the underlying v8::Object of a // CallbackInterfaceBase without wrapper-tracing. This class is necessary and // useful where wrapper-tracing is not suitable. Remember that, as a nature of // v8::Persistent, abuse of V8PersistentCallbackInterfaceBase would result in // memory leak, so the use of V8PersistentCallbackInterfaceBase should be // limited to those which are guaranteed to release the persistents in a finite // time period. class PLATFORM_EXPORT V8PersistentCallbackInterfaceBase : public GarbageCollectedFinalized { public: virtual ~V8PersistentCallbackInterfaceBase() { v8_object_.Reset(); } virtual void Trace(blink::Visitor*); v8::Isolate* GetIsolate() { return callback_interface_->GetIsolate(); } protected: explicit V8PersistentCallbackInterfaceBase(CallbackInterfaceBase*); template V8CallbackInterface* As() { static_assert( std::is_base_of::value, "V8CallbackInterface must be a subclass of CallbackInterfaceBase."); return static_cast(callback_interface_.Get()); } private: Member callback_interface_; v8::Persistent v8_object_; }; // V8PersistentCallbackInterface is a counter-part of // V8CallbackInterface. While V8CallbackInterface uses wrapper-tracing, // V8PersistentCallbackInterface uses v8::Persistent to // make the underlying v8::Object alive. // // Since the signatures of the operations vary depending on the IDL definition, // the class definition is specialized and generated by the bindings code // generator. template class V8PersistentCallbackInterface; // Converts the wrapper-tracing version of a callback interface to the // v8::Persistent version of it. template inline V8PersistentCallbackInterface* ToV8PersistentCallbackInterface(V8CallbackInterface* callback_interface) { static_assert( std::is_base_of::value, "V8CallbackInterface must be a subclass of CallbackInterfaceBase."); return callback_interface ? MakeGarbageCollected< V8PersistentCallbackInterface>( callback_interface) : nullptr; } // CallbackInterfaceBase is designed to be used with wrapper-tracing. As // blink::Persistent does not perform wrapper-tracing, use of |WrapPersistent| // for callback interfaces is likely (if not always) misuse. Thus, this code // prohibits such a use case. The call sites should explicitly use // WrapPersistent(V8PersistentCallbackInterface*). Persistent WrapPersistent(CallbackInterfaceBase*) = delete; } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_CALLBACK_INTERFACE_BASE_H_