/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_JSActor_h #define mozilla_dom_JSActor_h #include "js/TypeDecls.h" #include "ipc/EnumSerializer.h" #include "mozilla/Attributes.h" #include "mozilla/dom/PromiseNativeHandler.h" #include "nsCycleCollectionParticipant.h" #include "nsTHashMap.h" #include "nsWrapperCache.h" class nsIGlobalObject; class nsQueryJSActor; namespace mozilla { class ErrorResult; namespace dom { namespace ipc { class StructuredCloneData; } class JSActorManager; class JSActorMessageMeta; class QueryPromiseHandler; enum class JSActorMessageKind { Message, Query, QueryResolve, QueryReject, EndGuard_, }; // Common base class for JSWindowActor{Parent,Child}. class JSActor : public nsISupports, public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(JSActor) explicit JSActor(nsISupports* aGlobal = nullptr); const nsCString& Name() const { return mName; } void GetName(nsCString& aName) { aName = Name(); } void SendAsyncMessage(JSContext* aCx, const nsAString& aMessageName, JS::Handle aObj, ErrorResult& aRv); already_AddRefed SendQuery(JSContext* aCx, const nsAString& aMessageName, JS::Handle aObj, ErrorResult& aRv); nsIGlobalObject* GetParentObject() const { return mGlobal; }; protected: // Send the message described by the structured clone data |aData|, and the // message metadata |aMetadata|. The underlying transport should call the // |ReceiveMessage| method on the other side asynchronously. virtual void SendRawMessage(const JSActorMessageMeta& aMetadata, Maybe&& aData, Maybe&& aStack, ErrorResult& aRv) = 0; // Helper method to send an in-process raw message. using OtherSideCallback = std::function()>; static void SendRawMessageInProcess(const JSActorMessageMeta& aMeta, Maybe&& aData, Maybe&& aStack, OtherSideCallback&& aGetOtherSide); virtual ~JSActor() = default; void SetName(const nsACString& aName); bool CanSend() const { return mCanSend; } void ThrowStateErrorForGetter(const char* aName, ErrorResult& aRv) const; void StartDestroy(); void AfterDestroy(); enum class CallbackFunction { DidDestroy, ActorCreated }; void InvokeCallback(CallbackFunction callback); virtual void ClearManager() = 0; private: friend class JSActorManager; friend class ::nsQueryJSActor; // for QueryInterfaceActor nsresult QueryInterfaceActor(const nsIID& aIID, void** aPtr); // Called by JSActorManager when they receive raw message data destined for // this actor. void ReceiveMessage(JSContext* aCx, const JSActorMessageMeta& aMetadata, JS::Handle aData, ErrorResult& aRv); void ReceiveQuery(JSContext* aCx, const JSActorMessageMeta& aMetadata, JS::Handle aData, ErrorResult& aRv); void ReceiveQueryReply(JSContext* aCx, const JSActorMessageMeta& aMetadata, JS::Handle aData, ErrorResult& aRv); // Call the actual `ReceiveMessage` method, and get the return value. void CallReceiveMessage(JSContext* aCx, const JSActorMessageMeta& aMetadata, JS::Handle aData, JS::MutableHandle aRetVal, ErrorResult& aRv); // Helper object used while processing query messages to send the final reply // message. class QueryHandler final : public PromiseNativeHandler { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(QueryHandler) QueryHandler(JSActor* aActor, const JSActorMessageMeta& aMetadata, Promise* aPromise); void RejectedCallback(JSContext* aCx, JS::Handle aValue, ErrorResult& aRv) override; void ResolvedCallback(JSContext* aCx, JS::Handle aValue, ErrorResult& aRv) override; private: ~QueryHandler() = default; void SendReply(JSContext* aCx, JSActorMessageKind aKind, Maybe&& aData); RefPtr mActor; RefPtr mPromise; nsString mMessageName; uint64_t mQueryId; }; // A query which hasn't been resolved yet, along with metadata about what // query the promise is for. struct PendingQuery { RefPtr mPromise; nsString mMessageName; }; nsCOMPtr mGlobal; nsCOMPtr mWrappedJS; nsCString mName; nsTHashMap mPendingQueries; uint64_t mNextQueryId = 0; bool mCanSend = true; }; } // namespace dom } // namespace mozilla namespace IPC { template <> struct ParamTraits : public ContiguousEnumSerializer< mozilla::dom::JSActorMessageKind, mozilla::dom::JSActorMessageKind::Message, mozilla::dom::JSActorMessageKind::EndGuard_> {}; } // namespace IPC #endif // !defined(mozilla_dom_JSActor_h)