Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef mozilla_dom_StructuredCloneHolder_h
7 : #define mozilla_dom_StructuredCloneHolder_h
8 :
9 : #include "jsapi.h"
10 : #include "js/StructuredClone.h"
11 : #include "mozilla/Move.h"
12 : #include "mozilla/UniquePtr.h"
13 : #include "mozilla/dom/BindingDeclarations.h"
14 : #include "nsISupports.h"
15 : #include "nsTArray.h"
16 :
17 : #ifdef DEBUG
18 : #include "nsIThread.h"
19 : #endif
20 :
21 : class nsIInputStream;
22 :
23 : namespace mozilla {
24 : class ErrorResult;
25 : namespace layers {
26 : class Image;
27 : }
28 :
29 : namespace gfx {
30 : class DataSourceSurface;
31 : }
32 :
33 : namespace dom {
34 :
35 : class StructuredCloneHolderBase
36 : {
37 : public:
38 : typedef JS::StructuredCloneScope StructuredCloneScope;
39 :
40 : StructuredCloneHolderBase(StructuredCloneScope aScope = StructuredCloneScope::SameProcessSameThread);
41 : virtual ~StructuredCloneHolderBase();
42 :
43 : StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = default;
44 :
45 : // These methods should be implemented in order to clone data.
46 : // Read more documentation in js/public/StructuredClone.h.
47 :
48 : virtual JSObject* CustomReadHandler(JSContext* aCx,
49 : JSStructuredCloneReader* aReader,
50 : uint32_t aTag,
51 : uint32_t aIndex) = 0;
52 :
53 : virtual bool CustomWriteHandler(JSContext* aCx,
54 : JSStructuredCloneWriter* aWriter,
55 : JS::Handle<JSObject*> aObj) = 0;
56 :
57 : // This method has to be called when this object is not needed anymore.
58 : // It will free memory and the buffer. This has to be called because
59 : // otherwise the buffer will be freed in the DTOR of this class and at that
60 : // point we cannot use the overridden methods.
61 : void Clear();
62 :
63 : // If these 3 methods are not implement, transfering objects will not be
64 : // allowed. Otherwise only arrayBuffers will be transferred.
65 :
66 : virtual bool
67 : CustomReadTransferHandler(JSContext* aCx,
68 : JSStructuredCloneReader* aReader,
69 : uint32_t aTag,
70 : void* aContent,
71 : uint64_t aExtraData,
72 : JS::MutableHandleObject aReturnObject);
73 :
74 : virtual bool
75 : CustomWriteTransferHandler(JSContext* aCx,
76 : JS::Handle<JSObject*> aObj,
77 : // Output:
78 : uint32_t* aTag,
79 : JS::TransferableOwnership* aOwnership,
80 : void** aContent,
81 : uint64_t* aExtraData);
82 :
83 : virtual void
84 : CustomFreeTransferHandler(uint32_t aTag,
85 : JS::TransferableOwnership aOwnership,
86 : void* aContent,
87 : uint64_t aExtraData);
88 :
89 : // These methods are what you should use to read/write data.
90 :
91 : // Execute the serialization of aValue using the Structured Clone Algorithm.
92 : // The data can read back using Read().
93 : bool Write(JSContext* aCx,
94 : JS::Handle<JS::Value> aValue);
95 :
96 : // Like Write() but it supports the transferring of objects and handling
97 : // of cloning policy.
98 : bool Write(JSContext* aCx,
99 : JS::Handle<JS::Value> aValue,
100 : JS::Handle<JS::Value> aTransfer,
101 : JS::CloneDataPolicy cloneDataPolicy);
102 :
103 : // If Write() has been called, this method retrieves data and stores it into
104 : // aValue.
105 : bool Read(JSContext* aCx,
106 : JS::MutableHandle<JS::Value> aValue);
107 :
108 2 : bool HasData() const
109 : {
110 2 : return !!mBuffer;
111 : }
112 :
113 : JSStructuredCloneData& BufferData() const
114 : {
115 : MOZ_ASSERT(mBuffer, "Write() has never been called.");
116 : return mBuffer->data();
117 : }
118 :
119 : protected:
120 : UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
121 :
122 : StructuredCloneScope mStructuredCloneScope;
123 :
124 : #ifdef DEBUG
125 : bool mClearCalled;
126 : #endif
127 : };
128 :
129 : class BlobImpl;
130 : class MessagePort;
131 : class MessagePortIdentifier;
132 :
133 : class StructuredCloneHolder : public StructuredCloneHolderBase
134 : {
135 : public:
136 : enum CloningSupport
137 : {
138 : CloningSupported,
139 : CloningNotSupported
140 : };
141 :
142 : enum TransferringSupport
143 : {
144 : TransferringSupported,
145 : TransferringNotSupported
146 : };
147 :
148 : // If cloning is supported, this object will clone objects such as Blobs,
149 : // FileList, ImageData, etc.
150 : // If transferring is supported, we will transfer MessagePorts and in the
151 : // future other transferrable objects.
152 : // The StructuredCloneScope is useful to know where the cloned/transferred
153 : // data can be read and written. Additional checks about the nature of the
154 : // objects will be done based on this scope value because not all the
155 : // objects can be sent between threads or processes.
156 : explicit StructuredCloneHolder(CloningSupport aSupportsCloning,
157 : TransferringSupport aSupportsTransferring,
158 : StructuredCloneScope aStructuredCloneScope);
159 : virtual ~StructuredCloneHolder();
160 :
161 : StructuredCloneHolder(StructuredCloneHolder&& aOther) = default;
162 :
163 : // Normally you should just use Write() and Read().
164 :
165 : void Write(JSContext* aCx,
166 : JS::Handle<JS::Value> aValue,
167 : ErrorResult &aRv);
168 :
169 : void Write(JSContext* aCx,
170 : JS::Handle<JS::Value> aValue,
171 : JS::Handle<JS::Value> aTransfer,
172 : JS::CloneDataPolicy cloneDataPolicy,
173 : ErrorResult &aRv);
174 :
175 : void Read(nsISupports* aParent,
176 : JSContext* aCx,
177 : JS::MutableHandle<JS::Value> aValue,
178 : ErrorResult &aRv);
179 :
180 : // Call this method to know if this object is keeping some DOM object alive.
181 0 : bool HasClonedDOMObjects() const
182 : {
183 0 : return !mBlobImplArray.IsEmpty() ||
184 0 : !mWasmModuleArray.IsEmpty() ||
185 0 : !mClonedSurfaces.IsEmpty() ||
186 0 : !mInputStreamArray.IsEmpty();
187 : }
188 :
189 0 : nsTArray<RefPtr<BlobImpl>>& BlobImpls()
190 : {
191 0 : MOZ_ASSERT(mSupportsCloning, "Blobs cannot be taken/set if cloning is not supported.");
192 0 : return mBlobImplArray;
193 : }
194 :
195 6 : nsTArray<RefPtr<JS::WasmModule>>& WasmModules()
196 : {
197 6 : MOZ_ASSERT(mSupportsCloning, "WasmModules cannot be taken/set if cloning is not supported.");
198 6 : return mWasmModuleArray;
199 : }
200 :
201 0 : nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams()
202 : {
203 0 : MOZ_ASSERT(mSupportsCloning, "InputStreams cannot be taken/set if cloning is not supported.");
204 0 : return mInputStreamArray;
205 : }
206 :
207 0 : StructuredCloneScope CloneScope() const
208 : {
209 0 : return mStructuredCloneScope;
210 : }
211 :
212 : // The parent object is set internally just during the Read(). This method
213 : // can be used by read functions to retrieve it.
214 0 : nsISupports* ParentDuringRead() const
215 : {
216 0 : return mParent;
217 : }
218 :
219 : // This must be called if the transferring has ports generated by Read().
220 : // MessagePorts are not thread-safe and they must be retrieved in the thread
221 : // where they are created.
222 46 : nsTArray<RefPtr<MessagePort>>&& TakeTransferredPorts()
223 : {
224 46 : MOZ_ASSERT(mSupportsTransferring);
225 46 : return Move(mTransferredPorts);
226 : }
227 :
228 : // This method uses TakeTransferredPorts() to populate a sequence of
229 : // MessagePorts for WebIDL binding classes.
230 : bool
231 : TakeTransferredPortsAsSequence(Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts);
232 :
233 98 : nsTArray<MessagePortIdentifier>& PortIdentifiers() const
234 : {
235 98 : MOZ_ASSERT(mSupportsTransferring);
236 98 : return mPortIdentifiers;
237 : }
238 :
239 6 : nsTArray<RefPtr<gfx::DataSourceSurface>>& GetSurfaces()
240 : {
241 6 : return mClonedSurfaces;
242 : }
243 :
244 : // Implementations of the virtual methods to allow cloning of objects which
245 : // JS engine itself doesn't clone.
246 :
247 : virtual JSObject* CustomReadHandler(JSContext* aCx,
248 : JSStructuredCloneReader* aReader,
249 : uint32_t aTag,
250 : uint32_t aIndex) override;
251 :
252 : virtual bool CustomWriteHandler(JSContext* aCx,
253 : JSStructuredCloneWriter* aWriter,
254 : JS::Handle<JSObject*> aObj) override;
255 :
256 : virtual bool CustomReadTransferHandler(JSContext* aCx,
257 : JSStructuredCloneReader* aReader,
258 : uint32_t aTag,
259 : void* aContent,
260 : uint64_t aExtraData,
261 : JS::MutableHandleObject aReturnObject) override;
262 :
263 : virtual bool CustomWriteTransferHandler(JSContext* aCx,
264 : JS::Handle<JSObject*> aObj,
265 : uint32_t* aTag,
266 : JS::TransferableOwnership* aOwnership,
267 : void** aContent,
268 : uint64_t* aExtraData) override;
269 :
270 : virtual void CustomFreeTransferHandler(uint32_t aTag,
271 : JS::TransferableOwnership aOwnership,
272 : void* aContent,
273 : uint64_t aExtraData) override;
274 :
275 : // These 2 static methods are useful to read/write fully serializable objects.
276 : // They can be used by custom StructuredCloneHolderBase classes to
277 : // serialize objects such as ImageData, CryptoKey, RTCCertificate, etc.
278 :
279 : static JSObject* ReadFullySerializableObjects(JSContext* aCx,
280 : JSStructuredCloneReader* aReader,
281 : uint32_t aTag);
282 :
283 : static bool WriteFullySerializableObjects(JSContext* aCx,
284 : JSStructuredCloneWriter* aWriter,
285 : JS::Handle<JSObject*> aObj);
286 :
287 : static const JSStructuredCloneCallbacks sCallbacks;
288 :
289 : protected:
290 : // If you receive a buffer from IPC, you can use this method to retrieve a
291 : // JS::Value. It can happen that you want to pre-populate the array of Blobs
292 : // and/or the PortIdentifiers.
293 : void ReadFromBuffer(nsISupports* aParent,
294 : JSContext* aCx,
295 : JSStructuredCloneData& aBuffer,
296 : JS::MutableHandle<JS::Value> aValue,
297 : ErrorResult &aRv);
298 :
299 : void ReadFromBuffer(nsISupports* aParent,
300 : JSContext* aCx,
301 : JSStructuredCloneData& aBuffer,
302 : uint32_t aAlgorithmVersion,
303 : JS::MutableHandle<JS::Value> aValue,
304 : ErrorResult &aRv);
305 :
306 : bool mSupportsCloning;
307 : bool mSupportsTransferring;
308 :
309 : // Used for cloning blobs in the structured cloning algorithm.
310 : nsTArray<RefPtr<BlobImpl>> mBlobImplArray;
311 :
312 : // Used for cloning JS::WasmModules in the structured cloning algorithm.
313 : nsTArray<RefPtr<JS::WasmModule>> mWasmModuleArray;
314 :
315 : // Used for cloning InputStream in the structured cloning algorithm.
316 : nsTArray<nsCOMPtr<nsIInputStream>> mInputStreamArray;
317 :
318 : // This is used for sharing the backend of ImageBitmaps.
319 : // The DataSourceSurface object must be thread-safely reference-counted.
320 : // The DataSourceSurface object will not be written ever via any ImageBitmap
321 : // instance, so no race condition will occur.
322 : nsTArray<RefPtr<gfx::DataSourceSurface>> mClonedSurfaces;
323 :
324 : // This raw pointer is only set within ::Read() and is unset by the end.
325 : nsISupports* MOZ_NON_OWNING_REF mParent;
326 :
327 : // This array contains the ports once we've finished the reading. It's
328 : // generated from the mPortIdentifiers array.
329 : nsTArray<RefPtr<MessagePort>> mTransferredPorts;
330 :
331 : // This array contains the identifiers of the MessagePorts. Based on these we
332 : // are able to reconnect the new transferred ports with the other
333 : // MessageChannel ports.
334 : mutable nsTArray<MessagePortIdentifier> mPortIdentifiers;
335 :
336 : #ifdef DEBUG
337 : nsCOMPtr<nsIEventTarget> mCreationEventTarget;
338 : #endif
339 : };
340 :
341 : } // dom namespace
342 : } // mozilla namespace
343 :
344 : #endif // mozilla_dom_StructuredCloneHolder_h
|