summaryrefslogtreecommitdiffstats
path: root/dom/base/StructuredCloneHolder.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/StructuredCloneHolder.h')
-rw-r--r--dom/base/StructuredCloneHolder.h332
1 files changed, 332 insertions, 0 deletions
diff --git a/dom/base/StructuredCloneHolder.h b/dom/base/StructuredCloneHolder.h
new file mode 100644
index 000000000..e6953d0f3
--- /dev/null
+++ b/dom/base/StructuredCloneHolder.h
@@ -0,0 +1,332 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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_StructuredCloneHolder_h
+#define mozilla_dom_StructuredCloneHolder_h
+
+#include "jsapi.h"
+#include "js/StructuredClone.h"
+#include "mozilla/Move.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "nsISupports.h"
+#include "nsTArray.h"
+
+#ifdef DEBUG
+#include "nsIThread.h"
+#endif
+
+namespace mozilla {
+class ErrorResult;
+namespace layers {
+class Image;
+}
+
+namespace gfx {
+class DataSourceSurface;
+}
+
+namespace dom {
+
+class StructuredCloneHolderBase
+{
+public:
+ typedef JS::StructuredCloneScope StructuredCloneScope;
+
+ StructuredCloneHolderBase(StructuredCloneScope aScope = StructuredCloneScope::SameProcessSameThread);
+ virtual ~StructuredCloneHolderBase();
+
+ StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = default;
+
+ // These methods should be implemented in order to clone data.
+ // Read more documentation in js/public/StructuredClone.h.
+
+ virtual JSObject* CustomReadHandler(JSContext* aCx,
+ JSStructuredCloneReader* aReader,
+ uint32_t aTag,
+ uint32_t aIndex) = 0;
+
+ virtual bool CustomWriteHandler(JSContext* aCx,
+ JSStructuredCloneWriter* aWriter,
+ JS::Handle<JSObject*> aObj) = 0;
+
+ // This method has to be called when this object is not needed anymore.
+ // It will free memory and the buffer. This has to be called because
+ // otherwise the buffer will be freed in the DTOR of this class and at that
+ // point we cannot use the overridden methods.
+ void Clear();
+
+ // If these 3 methods are not implement, transfering objects will not be
+ // allowed. Otherwise only arrayBuffers will be transferred.
+
+ virtual bool
+ CustomReadTransferHandler(JSContext* aCx,
+ JSStructuredCloneReader* aReader,
+ uint32_t aTag,
+ void* aContent,
+ uint64_t aExtraData,
+ JS::MutableHandleObject aReturnObject);
+
+ virtual bool
+ CustomWriteTransferHandler(JSContext* aCx,
+ JS::Handle<JSObject*> aObj,
+ // Output:
+ uint32_t* aTag,
+ JS::TransferableOwnership* aOwnership,
+ void** aContent,
+ uint64_t* aExtraData);
+
+ virtual void
+ CustomFreeTransferHandler(uint32_t aTag,
+ JS::TransferableOwnership aOwnership,
+ void* aContent,
+ uint64_t aExtraData);
+
+ // These methods are what you should use to read/write data.
+
+ // Execute the serialization of aValue using the Structured Clone Algorithm.
+ // The data can read back using Read().
+ bool Write(JSContext* aCx,
+ JS::Handle<JS::Value> aValue);
+
+ // Like Write() but it supports the transferring of objects and handling
+ // of cloning policy.
+ bool Write(JSContext* aCx,
+ JS::Handle<JS::Value> aValue,
+ JS::Handle<JS::Value> aTransfer,
+ JS::CloneDataPolicy cloneDataPolicy);
+
+ // If Write() has been called, this method retrieves data and stores it into
+ // aValue.
+ bool Read(JSContext* aCx,
+ JS::MutableHandle<JS::Value> aValue);
+
+ bool HasData() const
+ {
+ return !!mBuffer;
+ }
+
+ JSStructuredCloneData& BufferData() const
+ {
+ MOZ_ASSERT(mBuffer, "Write() has never been called.");
+ return mBuffer->data();
+ }
+
+protected:
+ UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
+
+ StructuredCloneScope mStructuredCloneScope;
+
+#ifdef DEBUG
+ bool mClearCalled;
+#endif
+};
+
+class BlobImpl;
+class MessagePort;
+class MessagePortIdentifier;
+
+class StructuredCloneHolder : public StructuredCloneHolderBase
+{
+public:
+ enum CloningSupport
+ {
+ CloningSupported,
+ CloningNotSupported
+ };
+
+ enum TransferringSupport
+ {
+ TransferringSupported,
+ TransferringNotSupported
+ };
+
+ // If cloning is supported, this object will clone objects such as Blobs,
+ // FileList, ImageData, etc.
+ // If transferring is supported, we will transfer MessagePorts and in the
+ // future other transferrable objects.
+ // The StructuredCloneScope is useful to know where the cloned/transferred
+ // data can be read and written. Additional checks about the nature of the
+ // objects will be done based on this scope value because not all the
+ // objects can be sent between threads or processes.
+ explicit StructuredCloneHolder(CloningSupport aSupportsCloning,
+ TransferringSupport aSupportsTransferring,
+ StructuredCloneScope aStructuredCloneScope);
+ virtual ~StructuredCloneHolder();
+
+ StructuredCloneHolder(StructuredCloneHolder&& aOther) = default;
+
+ // Normally you should just use Write() and Read().
+
+ void Write(JSContext* aCx,
+ JS::Handle<JS::Value> aValue,
+ ErrorResult &aRv);
+
+ void Write(JSContext* aCx,
+ JS::Handle<JS::Value> aValue,
+ JS::Handle<JS::Value> aTransfer,
+ JS::CloneDataPolicy cloneDataPolicy,
+ ErrorResult &aRv);
+
+ void Read(nsISupports* aParent,
+ JSContext* aCx,
+ JS::MutableHandle<JS::Value> aValue,
+ ErrorResult &aRv);
+
+ // Call this method to know if this object is keeping some DOM object alive.
+ bool HasClonedDOMObjects() const
+ {
+ return !mBlobImplArray.IsEmpty() ||
+ !mWasmModuleArray.IsEmpty() ||
+ !mClonedSurfaces.IsEmpty();
+ }
+
+ nsTArray<RefPtr<BlobImpl>>& BlobImpls()
+ {
+ MOZ_ASSERT(mSupportsCloning, "Blobs cannot be taken/set if cloning is not supported.");
+ return mBlobImplArray;
+ }
+
+ nsTArray<RefPtr<JS::WasmModule>>& WasmModules()
+ {
+ MOZ_ASSERT(mSupportsCloning, "WasmModules cannot be taken/set if cloning is not supported.");
+ return mWasmModuleArray;
+ }
+
+ StructuredCloneScope CloneScope() const
+ {
+ return mStructuredCloneScope;
+ }
+
+ // The parent object is set internally just during the Read(). This method
+ // can be used by read functions to retrieve it.
+ nsISupports* ParentDuringRead() const
+ {
+ return mParent;
+ }
+
+ // This must be called if the transferring has ports generated by Read().
+ // MessagePorts are not thread-safe and they must be retrieved in the thread
+ // where they are created.
+ nsTArray<RefPtr<MessagePort>>&& TakeTransferredPorts()
+ {
+ MOZ_ASSERT(mSupportsTransferring);
+ return Move(mTransferredPorts);
+ }
+
+ // This method uses TakeTransferredPorts() to populate a sequence of
+ // MessagePorts for WebIDL binding classes.
+ bool
+ TakeTransferredPortsAsSequence(Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts);
+
+ nsTArray<MessagePortIdentifier>& PortIdentifiers() const
+ {
+ MOZ_ASSERT(mSupportsTransferring);
+ return mPortIdentifiers;
+ }
+
+ nsTArray<RefPtr<gfx::DataSourceSurface>>& GetSurfaces()
+ {
+ return mClonedSurfaces;
+ }
+
+ // Implementations of the virtual methods to allow cloning of objects which
+ // JS engine itself doesn't clone.
+
+ virtual JSObject* CustomReadHandler(JSContext* aCx,
+ JSStructuredCloneReader* aReader,
+ uint32_t aTag,
+ uint32_t aIndex) override;
+
+ virtual bool CustomWriteHandler(JSContext* aCx,
+ JSStructuredCloneWriter* aWriter,
+ JS::Handle<JSObject*> aObj) override;
+
+ virtual bool CustomReadTransferHandler(JSContext* aCx,
+ JSStructuredCloneReader* aReader,
+ uint32_t aTag,
+ void* aContent,
+ uint64_t aExtraData,
+ JS::MutableHandleObject aReturnObject) override;
+
+ virtual bool CustomWriteTransferHandler(JSContext* aCx,
+ JS::Handle<JSObject*> aObj,
+ uint32_t* aTag,
+ JS::TransferableOwnership* aOwnership,
+ void** aContent,
+ uint64_t* aExtraData) override;
+
+ virtual void CustomFreeTransferHandler(uint32_t aTag,
+ JS::TransferableOwnership aOwnership,
+ void* aContent,
+ uint64_t aExtraData) override;
+
+ // These 2 static methods are useful to read/write fully serializable objects.
+ // They can be used by custom StructuredCloneHolderBase classes to
+ // serialize objects such as ImageData, CryptoKey, RTCCertificate, etc.
+
+ static JSObject* ReadFullySerializableObjects(JSContext* aCx,
+ JSStructuredCloneReader* aReader,
+ uint32_t aTag);
+
+ static bool WriteFullySerializableObjects(JSContext* aCx,
+ JSStructuredCloneWriter* aWriter,
+ JS::Handle<JSObject*> aObj);
+
+ static const JSStructuredCloneCallbacks sCallbacks;
+
+protected:
+ // If you receive a buffer from IPC, you can use this method to retrieve a
+ // JS::Value. It can happen that you want to pre-populate the array of Blobs
+ // and/or the PortIdentifiers.
+ void ReadFromBuffer(nsISupports* aParent,
+ JSContext* aCx,
+ JSStructuredCloneData& aBuffer,
+ JS::MutableHandle<JS::Value> aValue,
+ ErrorResult &aRv);
+
+ void ReadFromBuffer(nsISupports* aParent,
+ JSContext* aCx,
+ JSStructuredCloneData& aBuffer,
+ uint32_t aAlgorithmVersion,
+ JS::MutableHandle<JS::Value> aValue,
+ ErrorResult &aRv);
+
+ bool mSupportsCloning;
+ bool mSupportsTransferring;
+
+ // Used for cloning blobs in the structured cloning algorithm.
+ nsTArray<RefPtr<BlobImpl>> mBlobImplArray;
+
+ // Used for cloning JS::WasmModules in the structured cloning algorithm.
+ nsTArray<RefPtr<JS::WasmModule>> mWasmModuleArray;
+
+ // This is used for sharing the backend of ImageBitmaps.
+ // The DataSourceSurface object must be thread-safely reference-counted.
+ // The DataSourceSurface object will not be written ever via any ImageBitmap
+ // instance, so no race condition will occur.
+ nsTArray<RefPtr<gfx::DataSourceSurface>> mClonedSurfaces;
+
+ // This raw pointer is only set within ::Read() and is unset by the end.
+ nsISupports* MOZ_NON_OWNING_REF mParent;
+
+ // This array contains the ports once we've finished the reading. It's
+ // generated from the mPortIdentifiers array.
+ nsTArray<RefPtr<MessagePort>> mTransferredPorts;
+
+ // This array contains the identifiers of the MessagePorts. Based on these we
+ // are able to reconnect the new transferred ports with the other
+ // MessageChannel ports.
+ mutable nsTArray<MessagePortIdentifier> mPortIdentifiers;
+
+#ifdef DEBUG
+ nsCOMPtr<nsIThread> mCreationThread;
+#endif
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_StructuredCloneHolder_h