Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "StructuredCloneHolder.h"
8 :
9 : #include "ImageContainer.h"
10 : #include "mozilla/AutoRestore.h"
11 : #include "mozilla/dom/BlobBinding.h"
12 : #include "mozilla/dom/CryptoKey.h"
13 : #include "mozilla/dom/StructuredCloneBlob.h"
14 : #include "mozilla/dom/Directory.h"
15 : #include "mozilla/dom/DirectoryBinding.h"
16 : #include "mozilla/dom/File.h"
17 : #include "mozilla/dom/FileList.h"
18 : #include "mozilla/dom/FileListBinding.h"
19 : #include "mozilla/dom/FormData.h"
20 : #include "mozilla/dom/ImageBitmap.h"
21 : #include "mozilla/dom/ImageBitmapBinding.h"
22 : #include "mozilla/dom/ImageData.h"
23 : #include "mozilla/dom/ImageDataBinding.h"
24 : #include "mozilla/dom/StructuredClone.h"
25 : #include "mozilla/dom/MessagePort.h"
26 : #include "mozilla/dom/MessagePortBinding.h"
27 : #include "mozilla/dom/OffscreenCanvas.h"
28 : #include "mozilla/dom/OffscreenCanvasBinding.h"
29 : #include "mozilla/dom/PMessagePort.h"
30 : #include "mozilla/dom/StructuredCloneTags.h"
31 : #include "mozilla/dom/SubtleCryptoBinding.h"
32 : #include "mozilla/dom/ToJSValue.h"
33 : #include "mozilla/dom/URLSearchParams.h"
34 : #include "mozilla/dom/URLSearchParamsBinding.h"
35 : #include "mozilla/dom/WebCryptoCommon.h"
36 : #include "mozilla/gfx/2D.h"
37 : #include "mozilla/ipc/BackgroundChild.h"
38 : #include "mozilla/ipc/BackgroundUtils.h"
39 : #include "mozilla/ipc/PBackgroundSharedTypes.h"
40 : #include "MultipartBlobImpl.h"
41 : #include "nsQueryObject.h"
42 :
43 : #ifdef MOZ_WEBRTC
44 : #include "mozilla/dom/RTCCertificate.h"
45 : #include "mozilla/dom/RTCCertificateBinding.h"
46 : #endif
47 :
48 : using namespace mozilla::ipc;
49 :
50 : namespace mozilla {
51 : namespace dom {
52 :
53 : namespace {
54 :
55 : JSObject*
56 1 : StructuredCloneCallbacksRead(JSContext* aCx,
57 : JSStructuredCloneReader* aReader,
58 : uint32_t aTag, uint32_t aIndex,
59 : void* aClosure)
60 : {
61 : StructuredCloneHolderBase* holder =
62 1 : static_cast<StructuredCloneHolderBase*>(aClosure);
63 1 : MOZ_ASSERT(holder);
64 1 : return holder->CustomReadHandler(aCx, aReader, aTag, aIndex);
65 : }
66 :
67 : bool
68 1 : StructuredCloneCallbacksWrite(JSContext* aCx,
69 : JSStructuredCloneWriter* aWriter,
70 : JS::Handle<JSObject*> aObj,
71 : void* aClosure)
72 : {
73 : StructuredCloneHolderBase* holder =
74 1 : static_cast<StructuredCloneHolderBase*>(aClosure);
75 1 : MOZ_ASSERT(holder);
76 1 : return holder->CustomWriteHandler(aCx, aWriter, aObj);
77 : }
78 :
79 : bool
80 0 : StructuredCloneCallbacksReadTransfer(JSContext* aCx,
81 : JSStructuredCloneReader* aReader,
82 : uint32_t aTag,
83 : void* aContent,
84 : uint64_t aExtraData,
85 : void* aClosure,
86 : JS::MutableHandleObject aReturnObject)
87 : {
88 : StructuredCloneHolderBase* holder =
89 0 : static_cast<StructuredCloneHolderBase*>(aClosure);
90 0 : MOZ_ASSERT(holder);
91 : return holder->CustomReadTransferHandler(aCx, aReader, aTag, aContent,
92 0 : aExtraData, aReturnObject);
93 : }
94 :
95 : bool
96 0 : StructuredCloneCallbacksWriteTransfer(JSContext* aCx,
97 : JS::Handle<JSObject*> aObj,
98 : void* aClosure,
99 : // Output:
100 : uint32_t* aTag,
101 : JS::TransferableOwnership* aOwnership,
102 : void** aContent,
103 : uint64_t* aExtraData)
104 : {
105 : StructuredCloneHolderBase* holder =
106 0 : static_cast<StructuredCloneHolderBase*>(aClosure);
107 0 : MOZ_ASSERT(holder);
108 : return holder->CustomWriteTransferHandler(aCx, aObj, aTag, aOwnership,
109 0 : aContent, aExtraData);
110 : }
111 :
112 : void
113 0 : StructuredCloneCallbacksFreeTransfer(uint32_t aTag,
114 : JS::TransferableOwnership aOwnership,
115 : void* aContent,
116 : uint64_t aExtraData,
117 : void* aClosure)
118 : {
119 : StructuredCloneHolderBase* holder =
120 0 : static_cast<StructuredCloneHolderBase*>(aClosure);
121 0 : MOZ_ASSERT(holder);
122 : return holder->CustomFreeTransferHandler(aTag, aOwnership, aContent,
123 0 : aExtraData);
124 : }
125 :
126 : void
127 0 : StructuredCloneCallbacksError(JSContext* aCx,
128 : uint32_t aErrorId)
129 : {
130 0 : NS_WARNING("Failed to clone data.");
131 0 : }
132 :
133 : } // anonymous namespace
134 :
135 : const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
136 : StructuredCloneCallbacksRead,
137 : StructuredCloneCallbacksWrite,
138 : StructuredCloneCallbacksError,
139 : StructuredCloneCallbacksReadTransfer,
140 : StructuredCloneCallbacksWriteTransfer,
141 : StructuredCloneCallbacksFreeTransfer
142 : };
143 :
144 : // StructuredCloneHolderBase class
145 :
146 125 : StructuredCloneHolderBase::StructuredCloneHolderBase(StructuredCloneScope aScope)
147 : : mStructuredCloneScope(aScope)
148 : #ifdef DEBUG
149 125 : , mClearCalled(false)
150 : #endif
151 125 : {}
152 :
153 246 : StructuredCloneHolderBase::~StructuredCloneHolderBase()
154 : {
155 : #ifdef DEBUG
156 123 : MOZ_ASSERT(mClearCalled);
157 : #endif
158 123 : }
159 :
160 : void
161 123 : StructuredCloneHolderBase::Clear()
162 : {
163 : #ifdef DEBUG
164 123 : mClearCalled = true;
165 : #endif
166 :
167 123 : mBuffer = nullptr;
168 123 : }
169 :
170 : bool
171 4 : StructuredCloneHolderBase::Write(JSContext* aCx,
172 : JS::Handle<JS::Value> aValue)
173 : {
174 : return Write(aCx, aValue, JS::UndefinedHandleValue,
175 4 : JS::CloneDataPolicy().denySharedArrayBuffer());
176 : }
177 :
178 : bool
179 49 : StructuredCloneHolderBase::Write(JSContext* aCx,
180 : JS::Handle<JS::Value> aValue,
181 : JS::Handle<JS::Value> aTransfer,
182 : JS::CloneDataPolicy cloneDataPolicy)
183 : {
184 49 : MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
185 49 : MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");
186 :
187 49 : mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(mStructuredCloneScope, &StructuredCloneHolder::sCallbacks, this);
188 :
189 49 : if (!mBuffer->write(aCx, aValue, aTransfer, cloneDataPolicy,
190 : &StructuredCloneHolder::sCallbacks, this))
191 : {
192 0 : mBuffer = nullptr;
193 0 : return false;
194 : }
195 :
196 49 : return true;
197 : }
198 :
199 : bool
200 4 : StructuredCloneHolderBase::Read(JSContext* aCx,
201 : JS::MutableHandle<JS::Value> aValue)
202 : {
203 4 : MOZ_ASSERT(mBuffer, "Read() without Write() is not allowed.");
204 4 : MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");
205 :
206 4 : bool ok = mBuffer->read(aCx, aValue, &StructuredCloneHolder::sCallbacks, this);
207 4 : return ok;
208 : }
209 :
210 : bool
211 0 : StructuredCloneHolderBase::CustomReadTransferHandler(JSContext* aCx,
212 : JSStructuredCloneReader* aReader,
213 : uint32_t aTag,
214 : void* aContent,
215 : uint64_t aExtraData,
216 : JS::MutableHandleObject aReturnObject)
217 : {
218 0 : MOZ_CRASH("Nothing to read.");
219 : return false;
220 : }
221 :
222 : bool
223 0 : StructuredCloneHolderBase::CustomWriteTransferHandler(JSContext* aCx,
224 : JS::Handle<JSObject*> aObj,
225 : uint32_t* aTag,
226 : JS::TransferableOwnership* aOwnership,
227 : void** aContent,
228 : uint64_t* aExtraData)
229 : {
230 : // No transfers are supported by default.
231 0 : return false;
232 : }
233 :
234 : void
235 0 : StructuredCloneHolderBase::CustomFreeTransferHandler(uint32_t aTag,
236 : JS::TransferableOwnership aOwnership,
237 : void* aContent,
238 : uint64_t aExtraData)
239 : {
240 0 : MOZ_CRASH("Nothing to free.");
241 : }
242 :
243 : // StructuredCloneHolder class
244 :
245 121 : StructuredCloneHolder::StructuredCloneHolder(CloningSupport aSupportsCloning,
246 : TransferringSupport aSupportsTransferring,
247 121 : StructuredCloneScope aScope)
248 : : StructuredCloneHolderBase(aScope)
249 121 : , mSupportsCloning(aSupportsCloning == CloningSupported)
250 121 : , mSupportsTransferring(aSupportsTransferring == TransferringSupported)
251 : , mParent(nullptr)
252 : #ifdef DEBUG
253 363 : , mCreationEventTarget(GetCurrentThreadEventTarget())
254 : #endif
255 121 : {}
256 :
257 238 : StructuredCloneHolder::~StructuredCloneHolder()
258 : {
259 119 : Clear();
260 119 : MOZ_ASSERT(mTransferredPorts.IsEmpty());
261 119 : }
262 :
263 : void
264 0 : StructuredCloneHolder::Write(JSContext* aCx,
265 : JS::Handle<JS::Value> aValue,
266 : ErrorResult& aRv)
267 : {
268 : Write(aCx, aValue, JS::UndefinedHandleValue,
269 0 : JS::CloneDataPolicy().denySharedArrayBuffer(), aRv);
270 0 : }
271 :
272 : void
273 45 : StructuredCloneHolder::Write(JSContext* aCx,
274 : JS::Handle<JS::Value> aValue,
275 : JS::Handle<JS::Value> aTransfer,
276 : JS::CloneDataPolicy cloneDataPolicy,
277 : ErrorResult& aRv)
278 : {
279 45 : MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread,
280 : mCreationEventTarget->IsOnCurrentThread());
281 :
282 45 : if (!StructuredCloneHolderBase::Write(aCx, aValue, aTransfer, cloneDataPolicy)) {
283 0 : aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
284 0 : return;
285 : }
286 : }
287 :
288 : void
289 0 : StructuredCloneHolder::Read(nsISupports* aParent,
290 : JSContext* aCx,
291 : JS::MutableHandle<JS::Value> aValue,
292 : ErrorResult& aRv)
293 : {
294 0 : MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread,
295 : mCreationEventTarget->IsOnCurrentThread());
296 0 : MOZ_ASSERT(aParent);
297 :
298 0 : mozilla::AutoRestore<nsISupports*> guard(mParent);
299 0 : mParent = aParent;
300 :
301 0 : if (!StructuredCloneHolderBase::Read(aCx, aValue)) {
302 0 : JS_ClearPendingException(aCx);
303 0 : aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
304 0 : return;
305 : }
306 :
307 : // If we are tranferring something, we cannot call 'Read()' more than once.
308 0 : if (mSupportsTransferring) {
309 0 : mBlobImplArray.Clear();
310 0 : mWasmModuleArray.Clear();
311 0 : mClonedSurfaces.Clear();
312 0 : mInputStreamArray.Clear();
313 0 : Clear();
314 : }
315 : }
316 :
317 : void
318 43 : StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
319 : JSContext* aCx,
320 : JSStructuredCloneData& aBuffer,
321 : JS::MutableHandle<JS::Value> aValue,
322 : ErrorResult& aRv)
323 : {
324 : ReadFromBuffer(aParent, aCx, aBuffer,
325 43 : JS_STRUCTURED_CLONE_VERSION, aValue, aRv);
326 43 : }
327 :
328 : void
329 43 : StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
330 : JSContext* aCx,
331 : JSStructuredCloneData& aBuffer,
332 : uint32_t aAlgorithmVersion,
333 : JS::MutableHandle<JS::Value> aValue,
334 : ErrorResult& aRv)
335 : {
336 43 : MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread,
337 : mCreationEventTarget->IsOnCurrentThread());
338 :
339 43 : MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
340 :
341 86 : mozilla::AutoRestore<nsISupports*> guard(mParent);
342 43 : mParent = aParent;
343 :
344 43 : if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion,
345 : mStructuredCloneScope, aValue, &sCallbacks,
346 : this)) {
347 0 : JS_ClearPendingException(aCx);
348 0 : aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
349 : }
350 43 : }
351 :
352 : /* static */ JSObject*
353 1 : StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
354 : JSStructuredCloneReader* aReader,
355 : uint32_t aTag)
356 : {
357 1 : if (aTag == SCTAG_DOM_IMAGEDATA) {
358 0 : return ReadStructuredCloneImageData(aCx, aReader);
359 : }
360 :
361 1 : if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) {
362 0 : nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
363 0 : if (!global) {
364 0 : return nullptr;
365 : }
366 :
367 : // Prevent the return value from being trashed by a GC during ~nsRefPtr.
368 0 : JS::Rooted<JSObject*> result(aCx);
369 : {
370 0 : if (aTag == SCTAG_DOM_WEBCRYPTO_KEY) {
371 0 : RefPtr<CryptoKey> key = new CryptoKey(global);
372 0 : if (!key->ReadStructuredClone(aReader)) {
373 0 : result = nullptr;
374 : } else {
375 0 : result = key->WrapObject(aCx, nullptr);
376 : }
377 0 : } else if (aTag == SCTAG_DOM_URLSEARCHPARAMS) {
378 0 : RefPtr<URLSearchParams> usp = new URLSearchParams(global);
379 0 : if (!usp->ReadStructuredClone(aReader)) {
380 0 : result = nullptr;
381 : } else {
382 0 : result = usp->WrapObject(aCx, nullptr);
383 : }
384 : }
385 : }
386 0 : return result;
387 : }
388 :
389 1 : if (aTag == SCTAG_DOM_NULL_PRINCIPAL ||
390 1 : aTag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
391 0 : aTag == SCTAG_DOM_CONTENT_PRINCIPAL ||
392 : aTag == SCTAG_DOM_EXPANDED_PRINCIPAL) {
393 : JSPrincipals* prin;
394 1 : if (!nsJSPrincipals::ReadKnownPrincipalType(aCx, aReader, aTag, &prin)) {
395 0 : return nullptr;
396 : }
397 : // nsJSPrincipals::ReadKnownPrincipalType addrefs for us, but because of the
398 : // casting between JSPrincipals* and nsIPrincipal* we can't use
399 : // getter_AddRefs above and have to already_AddRefed here.
400 2 : nsCOMPtr<nsIPrincipal> principal = already_AddRefed<nsIPrincipal>(nsJSPrincipals::get(prin));
401 :
402 2 : JS::RootedValue result(aCx);
403 3 : nsresult rv = nsContentUtils::WrapNative(aCx, principal,
404 : &NS_GET_IID(nsIPrincipal),
405 2 : &result);
406 1 : if (NS_FAILED(rv)) {
407 0 : xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
408 0 : return nullptr;
409 : }
410 :
411 1 : return result.toObjectOrNull();
412 : }
413 :
414 : #ifdef MOZ_WEBRTC
415 0 : if (aTag == SCTAG_DOM_RTC_CERTIFICATE) {
416 0 : if (!NS_IsMainThread()) {
417 0 : return nullptr;
418 : }
419 :
420 0 : nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
421 0 : if (!global) {
422 0 : return nullptr;
423 : }
424 :
425 : // Prevent the return value from being trashed by a GC during ~nsRefPtr.
426 0 : JS::Rooted<JSObject*> result(aCx);
427 : {
428 0 : RefPtr<RTCCertificate> cert = new RTCCertificate(global);
429 0 : if (!cert->ReadStructuredClone(aReader)) {
430 0 : result = nullptr;
431 : } else {
432 0 : result = cert->WrapObject(aCx, nullptr);
433 : }
434 : }
435 0 : return result;
436 : }
437 : #endif
438 :
439 : // Don't know what this is. Bail.
440 0 : xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
441 0 : return nullptr;
442 : }
443 :
444 : /* static */ bool
445 1 : StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
446 : JSStructuredCloneWriter* aWriter,
447 : JS::Handle<JSObject*> aObj)
448 : {
449 2 : JS::Rooted<JSObject*> obj(aCx, aObj);
450 :
451 : // See if this is a ImageData object.
452 : {
453 1 : ImageData* imageData = nullptr;
454 1 : if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, &obj, imageData))) {
455 0 : return WriteStructuredCloneImageData(aCx, aWriter, imageData);
456 : }
457 : }
458 :
459 : // Handle URLSearchParams cloning
460 : {
461 1 : URLSearchParams* usp = nullptr;
462 1 : if (NS_SUCCEEDED(UNWRAP_OBJECT(URLSearchParams, &obj, usp))) {
463 0 : return JS_WriteUint32Pair(aWriter, SCTAG_DOM_URLSEARCHPARAMS, 0) &&
464 0 : usp->WriteStructuredClone(aWriter);
465 : }
466 : }
467 :
468 : // Handle Key cloning
469 : {
470 1 : CryptoKey* key = nullptr;
471 1 : if (NS_SUCCEEDED(UNWRAP_OBJECT(CryptoKey, &obj, key))) {
472 0 : return JS_WriteUint32Pair(aWriter, SCTAG_DOM_WEBCRYPTO_KEY, 0) &&
473 0 : key->WriteStructuredClone(aWriter);
474 : }
475 : }
476 :
477 : #ifdef MOZ_WEBRTC
478 : {
479 : // Handle WebRTC Certificate cloning
480 1 : RTCCertificate* cert = nullptr;
481 1 : if (NS_SUCCEEDED(UNWRAP_OBJECT(RTCCertificate, &obj, cert))) {
482 0 : MOZ_ASSERT(NS_IsMainThread());
483 0 : return JS_WriteUint32Pair(aWriter, SCTAG_DOM_RTC_CERTIFICATE, 0) &&
484 0 : cert->WriteStructuredClone(aWriter);
485 : }
486 : }
487 : #endif
488 :
489 1 : if (NS_IsMainThread() && xpc::IsReflector(obj)) {
490 1 : nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(obj);
491 1 : nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(base);
492 1 : if (principal) {
493 1 : auto nsjsprincipals = nsJSPrincipals::get(principal);
494 1 : return nsjsprincipals->write(aCx, aWriter);
495 : }
496 : }
497 :
498 : // Don't know what this is
499 0 : xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
500 0 : return false;
501 : }
502 :
503 : namespace {
504 :
505 : JSObject*
506 0 : ReadBlob(JSContext* aCx,
507 : uint32_t aIndex,
508 : StructuredCloneHolder* aHolder)
509 : {
510 0 : MOZ_ASSERT(aHolder);
511 0 : MOZ_ASSERT(aIndex < aHolder->BlobImpls().Length());
512 0 : RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[aIndex];
513 :
514 0 : MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
515 :
516 : // RefPtr<File> needs to go out of scope before toObject() is
517 : // called because the static analysis thinks dereferencing XPCOM objects
518 : // can GC (because in some cases it can!), and a return statement with a
519 : // JSObject* type means that JSObject* is on the stack as a raw pointer
520 : // while destructors are running.
521 0 : JS::Rooted<JS::Value> val(aCx);
522 : {
523 0 : RefPtr<Blob> blob = Blob::Create(aHolder->ParentDuringRead(), blobImpl);
524 0 : if (!ToJSValue(aCx, blob, &val)) {
525 0 : return nullptr;
526 : }
527 : }
528 :
529 0 : return &val.toObject();
530 : }
531 :
532 : bool
533 0 : WriteBlob(JSStructuredCloneWriter* aWriter,
534 : Blob* aBlob,
535 : StructuredCloneHolder* aHolder)
536 : {
537 0 : MOZ_ASSERT(aWriter);
538 0 : MOZ_ASSERT(aBlob);
539 0 : MOZ_ASSERT(aHolder);
540 :
541 0 : if (JS_GetStructuredCloneScope(aWriter) != JS::StructuredCloneScope::SameProcessSameThread &&
542 0 : !aBlob->Impl()->MayBeClonedToOtherThreads()) {
543 0 : return false;
544 : }
545 :
546 0 : RefPtr<BlobImpl> blobImpl = aBlob->Impl();
547 0 : MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
548 :
549 : // We store the position of the blobImpl in the array as index.
550 0 : if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
551 0 : aHolder->BlobImpls().Length())) {
552 0 : aHolder->BlobImpls().AppendElement(blobImpl);
553 0 : return true;
554 : }
555 :
556 0 : return false;
557 : }
558 :
559 : // A directory is serialized as:
560 : // - pair of ints: SCTAG_DOM_DIRECTORY, path length
561 : // - path as string
562 : bool
563 0 : WriteDirectory(JSStructuredCloneWriter* aWriter,
564 : Directory* aDirectory)
565 : {
566 0 : MOZ_ASSERT(aWriter);
567 0 : MOZ_ASSERT(aDirectory);
568 :
569 0 : nsAutoString path;
570 0 : aDirectory->GetFullRealPath(path);
571 :
572 0 : size_t charSize = sizeof(nsString::char_type);
573 0 : return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DIRECTORY, path.Length()) &&
574 0 : JS_WriteBytes(aWriter, path.get(), path.Length() * charSize);
575 : }
576 :
577 : already_AddRefed<Directory>
578 0 : ReadDirectoryInternal(JSStructuredCloneReader* aReader,
579 : uint32_t aPathLength,
580 : StructuredCloneHolder* aHolder)
581 : {
582 0 : MOZ_ASSERT(aReader);
583 0 : MOZ_ASSERT(aHolder);
584 :
585 0 : nsAutoString path;
586 0 : path.SetLength(aPathLength);
587 0 : size_t charSize = sizeof(nsString::char_type);
588 0 : if (!JS_ReadBytes(aReader, (void*) path.BeginWriting(),
589 : aPathLength * charSize)) {
590 0 : return nullptr;
591 : }
592 :
593 0 : nsCOMPtr<nsIFile> file;
594 0 : nsresult rv = NS_NewLocalFile(path, true, getter_AddRefs(file));
595 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
596 0 : return nullptr;
597 : }
598 :
599 : RefPtr<Directory> directory =
600 0 : Directory::Create(aHolder->ParentDuringRead(), file);
601 0 : return directory.forget();
602 : }
603 :
604 : JSObject*
605 0 : ReadDirectory(JSContext* aCx,
606 : JSStructuredCloneReader* aReader,
607 : uint32_t aPathLength,
608 : StructuredCloneHolder* aHolder)
609 : {
610 0 : MOZ_ASSERT(aCx);
611 0 : MOZ_ASSERT(aReader);
612 0 : MOZ_ASSERT(aHolder);
613 :
614 : // RefPtr<Directory> needs to go out of scope before toObject() is
615 : // called because the static analysis thinks dereferencing XPCOM objects
616 : // can GC (because in some cases it can!), and a return statement with a
617 : // JSObject* type means that JSObject* is on the stack as a raw pointer
618 : // while destructors are running.
619 0 : JS::Rooted<JS::Value> val(aCx);
620 : {
621 : RefPtr<Directory> directory =
622 0 : ReadDirectoryInternal(aReader, aPathLength, aHolder);
623 0 : if (!directory) {
624 0 : return nullptr;
625 : }
626 :
627 0 : if (!ToJSValue(aCx, directory, &val)) {
628 0 : return nullptr;
629 : }
630 : }
631 :
632 0 : return &val.toObject();
633 : }
634 :
635 : // Read the WriteFileList for the format.
636 : JSObject*
637 0 : ReadFileList(JSContext* aCx,
638 : JSStructuredCloneReader* aReader,
639 : uint32_t aCount,
640 : StructuredCloneHolder* aHolder)
641 : {
642 0 : MOZ_ASSERT(aCx);
643 0 : MOZ_ASSERT(aReader);
644 :
645 0 : JS::Rooted<JS::Value> val(aCx);
646 : {
647 0 : RefPtr<FileList> fileList = new FileList(aHolder->ParentDuringRead());
648 :
649 : uint32_t zero, index;
650 : // |index| is the index of the first blobImpl.
651 0 : if (!JS_ReadUint32Pair(aReader, &zero, &index)) {
652 0 : return nullptr;
653 : }
654 :
655 0 : MOZ_ASSERT(zero == 0);
656 :
657 : // |aCount| is the number of BlobImpls to use from the |index|.
658 0 : for (uint32_t i = 0; i < aCount; ++i) {
659 0 : uint32_t pos = index + i;
660 0 : MOZ_ASSERT(pos < aHolder->BlobImpls().Length());
661 :
662 0 : RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[pos];
663 0 : MOZ_ASSERT(blobImpl->IsFile());
664 :
665 0 : MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
666 :
667 0 : RefPtr<File> file = File::Create(aHolder->ParentDuringRead(), blobImpl);
668 0 : if (!fileList->Append(file)) {
669 0 : return nullptr;
670 : }
671 : }
672 :
673 0 : if (!ToJSValue(aCx, fileList, &val)) {
674 0 : return nullptr;
675 : }
676 : }
677 :
678 0 : return &val.toObject();
679 : }
680 :
681 : // The format of the FileList serialization is:
682 : // - pair of ints: SCTAG_DOM_FILELIST, Length of the FileList
683 : // - pair of ints: 0, The offset of the BlobImpl array
684 : bool
685 0 : WriteFileList(JSStructuredCloneWriter* aWriter,
686 : FileList* aFileList,
687 : StructuredCloneHolder* aHolder)
688 : {
689 0 : MOZ_ASSERT(aWriter);
690 0 : MOZ_ASSERT(aFileList);
691 0 : MOZ_ASSERT(aHolder);
692 :
693 : // A FileList is serialized writing the X number of elements and the offset
694 : // from mBlobImplArray. The Read will take X elements from mBlobImplArray
695 : // starting from the offset.
696 0 : if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
697 0 : aFileList->Length()) ||
698 0 : !JS_WriteUint32Pair(aWriter, 0,
699 0 : aHolder->BlobImpls().Length())) {
700 0 : return false;
701 : }
702 :
703 0 : nsTArray<RefPtr<BlobImpl>> blobImpls;
704 :
705 0 : for (uint32_t i = 0; i < aFileList->Length(); ++i) {
706 0 : RefPtr<BlobImpl> blobImpl = aFileList->Item(i)->Impl();
707 0 : MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
708 0 : blobImpls.AppendElement(blobImpl);
709 : }
710 :
711 0 : aHolder->BlobImpls().AppendElements(blobImpls);
712 0 : return true;
713 : }
714 :
715 : // Read the WriteFormData for the format.
716 : JSObject*
717 0 : ReadFormData(JSContext* aCx,
718 : JSStructuredCloneReader* aReader,
719 : uint32_t aCount,
720 : StructuredCloneHolder* aHolder)
721 : {
722 0 : MOZ_ASSERT(aCx);
723 0 : MOZ_ASSERT(aReader);
724 0 : MOZ_ASSERT(aHolder);
725 :
726 : // See the serialization of the FormData for the format.
727 0 : JS::Rooted<JS::Value> val(aCx);
728 : {
729 : RefPtr<FormData> formData =
730 0 : new FormData(aHolder->ParentDuringRead());
731 :
732 0 : Optional<nsAString> thirdArg;
733 0 : for (uint32_t i = 0; i < aCount; ++i) {
734 0 : nsAutoString name;
735 0 : if (!ReadString(aReader, name)) {
736 0 : return nullptr;
737 : }
738 :
739 : uint32_t tag, indexOrLengthOfString;
740 0 : if (!JS_ReadUint32Pair(aReader, &tag, &indexOrLengthOfString)) {
741 0 : return nullptr;
742 : }
743 :
744 0 : if (tag == SCTAG_DOM_BLOB) {
745 0 : MOZ_ASSERT(indexOrLengthOfString < aHolder->BlobImpls().Length());
746 :
747 : RefPtr<BlobImpl> blobImpl =
748 0 : aHolder->BlobImpls()[indexOrLengthOfString];
749 0 : MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
750 :
751 : RefPtr<Blob> blob =
752 0 : Blob::Create(aHolder->ParentDuringRead(), blobImpl);
753 0 : MOZ_ASSERT(blob);
754 :
755 0 : ErrorResult rv;
756 0 : formData->Append(name, *blob, thirdArg, rv);
757 0 : if (NS_WARN_IF(rv.Failed())) {
758 0 : rv.SuppressException();
759 0 : return nullptr;
760 : }
761 :
762 0 : } else if (tag == SCTAG_DOM_DIRECTORY) {
763 : RefPtr<Directory> directory =
764 0 : ReadDirectoryInternal(aReader, indexOrLengthOfString, aHolder);
765 0 : if (!directory) {
766 0 : return nullptr;
767 : }
768 :
769 0 : formData->Append(name, directory);
770 :
771 : } else {
772 0 : MOZ_ASSERT(tag == 0);
773 :
774 0 : nsAutoString value;
775 0 : value.SetLength(indexOrLengthOfString);
776 0 : size_t charSize = sizeof(nsString::char_type);
777 0 : if (!JS_ReadBytes(aReader, (void*) value.BeginWriting(),
778 : indexOrLengthOfString * charSize)) {
779 0 : return nullptr;
780 : }
781 :
782 0 : ErrorResult rv;
783 0 : formData->Append(name, value, rv);
784 0 : if (NS_WARN_IF(rv.Failed())) {
785 0 : rv.SuppressException();
786 0 : return nullptr;
787 : }
788 : }
789 : }
790 :
791 0 : if (!ToJSValue(aCx, formData, &val)) {
792 0 : return nullptr;
793 : }
794 : }
795 :
796 0 : return &val.toObject();
797 : }
798 :
799 : // The format of the FormData serialization is:
800 : // - pair of ints: SCTAG_DOM_FORMDATA, Length of the FormData elements
801 : // - for each Element element:
802 : // - name string
803 : // - if it's a blob:
804 : // - pair of ints: SCTAG_DOM_BLOB, index of the BlobImpl in the array
805 : // mBlobImplArray.
806 : // - if it's a directory (See WriteDirectory):
807 : // - pair of ints: SCTAG_DOM_DIRECTORY, path length
808 : // - path as string
809 : // - else:
810 : // - pair of ints: 0, string length
811 : // - value string
812 : bool
813 0 : WriteFormData(JSStructuredCloneWriter* aWriter,
814 : FormData* aFormData,
815 : StructuredCloneHolder* aHolder)
816 : {
817 0 : MOZ_ASSERT(aWriter);
818 0 : MOZ_ASSERT(aFormData);
819 0 : MOZ_ASSERT(aHolder);
820 :
821 0 : if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FORMDATA,
822 : aFormData->Length())) {
823 0 : return false;
824 : }
825 :
826 : class MOZ_STACK_CLASS Closure final
827 : {
828 : JSStructuredCloneWriter* mWriter;
829 : StructuredCloneHolder* mHolder;
830 :
831 : public:
832 0 : Closure(JSStructuredCloneWriter* aWriter,
833 : StructuredCloneHolder* aHolder)
834 0 : : mWriter(aWriter),
835 0 : mHolder(aHolder)
836 0 : { }
837 :
838 : static bool
839 0 : Write(const nsString& aName, const OwningBlobOrDirectoryOrUSVString& aValue,
840 : void* aClosure)
841 : {
842 0 : Closure* closure = static_cast<Closure*>(aClosure);
843 0 : if (!WriteString(closure->mWriter, aName)) {
844 0 : return false;
845 : }
846 :
847 0 : if (aValue.IsBlob()) {
848 0 : if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
849 0 : closure->mHolder->BlobImpls().Length())) {
850 0 : return false;
851 : }
852 :
853 0 : RefPtr<BlobImpl> blobImpl = aValue.GetAsBlob()->Impl();
854 0 : MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
855 :
856 0 : closure->mHolder->BlobImpls().AppendElement(blobImpl);
857 0 : return true;
858 : }
859 :
860 0 : if (aValue.IsDirectory()) {
861 0 : Directory* directory = aValue.GetAsDirectory();
862 0 : return WriteDirectory(closure->mWriter, directory);
863 : }
864 :
865 0 : size_t charSize = sizeof(nsString::char_type);
866 0 : if (!JS_WriteUint32Pair(closure->mWriter, 0,
867 0 : aValue.GetAsUSVString().Length()) ||
868 0 : !JS_WriteBytes(closure->mWriter, aValue.GetAsUSVString().get(),
869 0 : aValue.GetAsUSVString().Length() * charSize)) {
870 0 : return false;
871 : }
872 :
873 0 : return true;
874 : }
875 : };
876 0 : Closure closure(aWriter, aHolder);
877 0 : return aFormData->ForEach(Closure::Write, &closure);
878 : }
879 :
880 : JSObject*
881 0 : ReadWasmModule(JSContext* aCx,
882 : uint32_t aIndex,
883 : StructuredCloneHolder* aHolder)
884 : {
885 0 : MOZ_ASSERT(aHolder);
886 0 : MOZ_ASSERT(aIndex < aHolder->WasmModules().Length());
887 0 : MOZ_ASSERT(aHolder->CloneScope() == StructuredCloneHolder::StructuredCloneScope::SameProcessSameThread ||
888 : aHolder->CloneScope() == StructuredCloneHolder::StructuredCloneScope::SameProcessDifferentThread);
889 :
890 0 : RefPtr<JS::WasmModule> wasmModule = aHolder->WasmModules()[aIndex];
891 0 : return wasmModule->createObject(aCx);
892 : }
893 :
894 : bool
895 0 : WriteWasmModule(JSStructuredCloneWriter* aWriter,
896 : JS::WasmModule* aWasmModule,
897 : StructuredCloneHolder* aHolder)
898 : {
899 0 : MOZ_ASSERT(aWriter);
900 0 : MOZ_ASSERT(aWasmModule);
901 0 : MOZ_ASSERT(aHolder);
902 0 : MOZ_ASSERT(aHolder->CloneScope() == StructuredCloneHolder::StructuredCloneScope::SameProcessSameThread ||
903 : aHolder->CloneScope() == StructuredCloneHolder::StructuredCloneScope::SameProcessDifferentThread);
904 :
905 : // We store the position of the wasmModule in the array as index.
906 0 : if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM,
907 0 : aHolder->WasmModules().Length())) {
908 0 : aHolder->WasmModules().AppendElement(aWasmModule);
909 0 : return true;
910 : }
911 :
912 0 : return false;
913 : }
914 :
915 : JSObject*
916 0 : ReadInputStream(JSContext* aCx,
917 : uint32_t aIndex,
918 : StructuredCloneHolder* aHolder)
919 : {
920 0 : MOZ_ASSERT(aHolder);
921 0 : MOZ_ASSERT(aIndex < aHolder->InputStreams().Length());
922 0 : nsCOMPtr<nsIInputStream> inputStream = aHolder->InputStreams()[aIndex];
923 :
924 0 : JS::RootedValue result(aCx);
925 0 : nsresult rv = nsContentUtils::WrapNative(aCx, inputStream,
926 : &NS_GET_IID(nsIInputStream),
927 0 : &result);
928 0 : if (NS_FAILED(rv)) {
929 0 : return nullptr;
930 : }
931 :
932 0 : return &result.toObject();
933 : }
934 :
935 : bool
936 0 : WriteInputStream(JSStructuredCloneWriter* aWriter,
937 : nsIInputStream* aInputStream,
938 : StructuredCloneHolder* aHolder)
939 : {
940 0 : MOZ_ASSERT(aWriter);
941 0 : MOZ_ASSERT(aInputStream);
942 0 : MOZ_ASSERT(aHolder);
943 :
944 : // We store the position of the inputStream in the array as index.
945 0 : if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_INPUTSTREAM,
946 0 : aHolder->InputStreams().Length())) {
947 0 : aHolder->InputStreams().AppendElement(aInputStream);
948 0 : return true;
949 : }
950 :
951 0 : return false;
952 : }
953 :
954 : } // anonymous namespace
955 :
956 : JSObject*
957 1 : StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
958 : JSStructuredCloneReader* aReader,
959 : uint32_t aTag,
960 : uint32_t aIndex)
961 : {
962 1 : MOZ_ASSERT(mSupportsCloning);
963 :
964 1 : if (aTag == SCTAG_DOM_BLOB) {
965 0 : return ReadBlob(aCx, aIndex, this);
966 : }
967 :
968 1 : if (aTag == SCTAG_DOM_DIRECTORY) {
969 0 : return ReadDirectory(aCx, aReader, aIndex, this);
970 : }
971 :
972 1 : if (aTag == SCTAG_DOM_FILELIST) {
973 0 : return ReadFileList(aCx, aReader, aIndex, this);
974 : }
975 :
976 1 : if (aTag == SCTAG_DOM_FORMDATA) {
977 0 : return ReadFormData(aCx, aReader, aIndex, this);
978 : }
979 :
980 1 : if (aTag == SCTAG_DOM_IMAGEBITMAP) {
981 0 : MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
982 : mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
983 :
984 : // Get the current global object.
985 : // This can be null.
986 0 : nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(mParent);
987 : // aIndex is the index of the cloned image.
988 0 : return ImageBitmap::ReadStructuredClone(aCx, aReader,
989 0 : parent, GetSurfaces(), aIndex);
990 : }
991 :
992 1 : if (aTag == SCTAG_DOM_STRUCTURED_CLONE_HOLDER) {
993 0 : return StructuredCloneBlob::ReadStructuredClone(aCx, aReader, this);
994 : }
995 :
996 1 : if (aTag == SCTAG_DOM_WASM) {
997 0 : return ReadWasmModule(aCx, aIndex, this);
998 : }
999 :
1000 1 : if (aTag == SCTAG_DOM_INPUTSTREAM) {
1001 0 : return ReadInputStream(aCx, aIndex, this);
1002 : }
1003 :
1004 1 : return ReadFullySerializableObjects(aCx, aReader, aTag);
1005 : }
1006 :
1007 : bool
1008 1 : StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
1009 : JSStructuredCloneWriter* aWriter,
1010 : JS::Handle<JSObject*> aObj)
1011 : {
1012 1 : if (!mSupportsCloning) {
1013 0 : return false;
1014 : }
1015 :
1016 2 : JS::Rooted<JSObject*> obj(aCx, aObj);
1017 :
1018 : // See if this is a File/Blob object.
1019 : {
1020 1 : Blob* blob = nullptr;
1021 1 : if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
1022 0 : return WriteBlob(aWriter, blob, this);
1023 : }
1024 : }
1025 :
1026 : // See if this is a Directory object.
1027 : {
1028 1 : Directory* directory = nullptr;
1029 1 : if (NS_SUCCEEDED(UNWRAP_OBJECT(Directory, &obj, directory))) {
1030 0 : return WriteDirectory(aWriter, directory);
1031 : }
1032 : }
1033 :
1034 : // See if this is a FileList object.
1035 : {
1036 1 : FileList* fileList = nullptr;
1037 1 : if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, &obj, fileList))) {
1038 0 : return WriteFileList(aWriter, fileList, this);
1039 : }
1040 : }
1041 :
1042 : // See if this is a FormData object.
1043 : {
1044 1 : FormData* formData = nullptr;
1045 1 : if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, &obj, formData))) {
1046 0 : return WriteFormData(aWriter, formData, this);
1047 : }
1048 : }
1049 :
1050 : // See if this is an ImageBitmap object.
1051 2 : if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
1052 1 : mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
1053 0 : ImageBitmap* imageBitmap = nullptr;
1054 0 : if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, &obj, imageBitmap))) {
1055 0 : return ImageBitmap::WriteStructuredClone(aWriter,
1056 : GetSurfaces(),
1057 0 : imageBitmap);
1058 : }
1059 : }
1060 :
1061 : // See if this is a StructuredCloneBlob object.
1062 : {
1063 1 : StructuredCloneBlob* holder = nullptr;
1064 1 : if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneHolder, &obj, holder))) {
1065 0 : return holder->WriteStructuredClone(aCx, aWriter, this);
1066 : }
1067 : }
1068 :
1069 : // See if this is a WasmModule.
1070 5 : if ((mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
1071 2 : mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) &&
1072 1 : JS::IsWasmModuleObject(obj)) {
1073 0 : RefPtr<JS::WasmModule> module = JS::GetWasmModule(obj);
1074 0 : MOZ_ASSERT(module);
1075 :
1076 0 : return WriteWasmModule(aWriter, module, this);
1077 : }
1078 :
1079 : {
1080 2 : nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(aObj);
1081 2 : nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(base);
1082 1 : if (inputStream) {
1083 0 : return WriteInputStream(aWriter, inputStream, this);
1084 : }
1085 : }
1086 :
1087 1 : return WriteFullySerializableObjects(aCx, aWriter, aObj);
1088 : }
1089 :
1090 : bool
1091 0 : StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx,
1092 : JSStructuredCloneReader* aReader,
1093 : uint32_t aTag,
1094 : void* aContent,
1095 : uint64_t aExtraData,
1096 : JS::MutableHandleObject aReturnObject)
1097 : {
1098 0 : MOZ_ASSERT(mSupportsTransferring);
1099 :
1100 0 : if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
1101 0 : MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
1102 0 : const MessagePortIdentifier& portIdentifier = mPortIdentifiers[aExtraData];
1103 :
1104 0 : nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
1105 :
1106 0 : ErrorResult rv;
1107 : RefPtr<MessagePort> port =
1108 0 : MessagePort::Create(global, portIdentifier, rv);
1109 0 : if (NS_WARN_IF(rv.Failed())) {
1110 0 : rv.SuppressException();
1111 0 : return false;
1112 : }
1113 :
1114 0 : mTransferredPorts.AppendElement(port);
1115 :
1116 0 : JS::Rooted<JS::Value> value(aCx);
1117 0 : if (!GetOrCreateDOMReflector(aCx, port, &value)) {
1118 0 : JS_ClearPendingException(aCx);
1119 0 : return false;
1120 : }
1121 :
1122 0 : aReturnObject.set(&value.toObject());
1123 0 : return true;
1124 : }
1125 :
1126 0 : if (aTag == SCTAG_DOM_CANVAS) {
1127 0 : MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
1128 : mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
1129 0 : MOZ_ASSERT(aContent);
1130 : OffscreenCanvasCloneData* data =
1131 0 : static_cast<OffscreenCanvasCloneData*>(aContent);
1132 0 : nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(mParent);
1133 0 : RefPtr<OffscreenCanvas> canvas = OffscreenCanvas::CreateFromCloneData(parent, data);
1134 0 : delete data;
1135 :
1136 0 : JS::Rooted<JS::Value> value(aCx);
1137 0 : if (!GetOrCreateDOMReflector(aCx, canvas, &value)) {
1138 0 : JS_ClearPendingException(aCx);
1139 0 : return false;
1140 : }
1141 :
1142 0 : aReturnObject.set(&value.toObject());
1143 0 : return true;
1144 : }
1145 :
1146 0 : if (aTag == SCTAG_DOM_IMAGEBITMAP) {
1147 0 : MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
1148 : mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
1149 0 : MOZ_ASSERT(aContent);
1150 : ImageBitmapCloneData* data =
1151 0 : static_cast<ImageBitmapCloneData*>(aContent);
1152 0 : nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(mParent);
1153 0 : RefPtr<ImageBitmap> bitmap = ImageBitmap::CreateFromCloneData(parent, data);
1154 0 : delete data;
1155 :
1156 0 : JS::Rooted<JS::Value> value(aCx);
1157 0 : if (!GetOrCreateDOMReflector(aCx, bitmap, &value)) {
1158 0 : JS_ClearPendingException(aCx);
1159 0 : return false;
1160 : }
1161 :
1162 0 : aReturnObject.set(&value.toObject());
1163 0 : return true;
1164 : }
1165 :
1166 0 : return false;
1167 : }
1168 :
1169 : bool
1170 0 : StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
1171 : JS::Handle<JSObject*> aObj,
1172 : uint32_t* aTag,
1173 : JS::TransferableOwnership* aOwnership,
1174 : void** aContent,
1175 : uint64_t* aExtraData)
1176 : {
1177 0 : if (!mSupportsTransferring) {
1178 0 : return false;
1179 : }
1180 :
1181 0 : JS::Rooted<JSObject*> obj(aCx, aObj);
1182 :
1183 : {
1184 0 : MessagePort* port = nullptr;
1185 0 : nsresult rv = UNWRAP_OBJECT(MessagePort, &obj, port);
1186 0 : if (NS_SUCCEEDED(rv)) {
1187 : // We use aExtraData to store the index of this new port identifier.
1188 0 : *aExtraData = mPortIdentifiers.Length();
1189 0 : MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement();
1190 :
1191 0 : port->CloneAndDisentangle(*identifier);
1192 :
1193 0 : *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
1194 0 : *aOwnership = JS::SCTAG_TMO_CUSTOM;
1195 0 : *aContent = nullptr;
1196 :
1197 0 : return true;
1198 : }
1199 :
1200 0 : if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
1201 0 : mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
1202 0 : OffscreenCanvas* canvas = nullptr;
1203 0 : rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
1204 0 : if (NS_SUCCEEDED(rv)) {
1205 0 : MOZ_ASSERT(canvas);
1206 :
1207 0 : *aExtraData = 0;
1208 0 : *aTag = SCTAG_DOM_CANVAS;
1209 0 : *aOwnership = JS::SCTAG_TMO_CUSTOM;
1210 0 : *aContent = canvas->ToCloneData();
1211 0 : MOZ_ASSERT(*aContent);
1212 0 : canvas->SetNeutered();
1213 :
1214 0 : return true;
1215 : }
1216 :
1217 0 : ImageBitmap* bitmap = nullptr;
1218 0 : rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap);
1219 0 : if (NS_SUCCEEDED(rv)) {
1220 0 : MOZ_ASSERT(bitmap);
1221 :
1222 0 : *aExtraData = 0;
1223 0 : *aTag = SCTAG_DOM_IMAGEBITMAP;
1224 0 : *aOwnership = JS::SCTAG_TMO_CUSTOM;
1225 0 : *aContent = bitmap->ToCloneData().release();
1226 0 : MOZ_ASSERT(*aContent);
1227 0 : bitmap->Close();
1228 :
1229 0 : return true;
1230 : }
1231 : }
1232 : }
1233 :
1234 0 : return false;
1235 : }
1236 :
1237 : void
1238 0 : StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
1239 : JS::TransferableOwnership aOwnership,
1240 : void* aContent,
1241 : uint64_t aExtraData)
1242 : {
1243 0 : MOZ_ASSERT(mSupportsTransferring);
1244 :
1245 0 : if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
1246 0 : MOZ_ASSERT(!aContent);
1247 0 : MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
1248 0 : MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
1249 0 : return;
1250 : }
1251 :
1252 0 : if (aTag == SCTAG_DOM_CANVAS) {
1253 0 : MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
1254 : mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
1255 0 : MOZ_ASSERT(aContent);
1256 : OffscreenCanvasCloneData* data =
1257 0 : static_cast<OffscreenCanvasCloneData*>(aContent);
1258 0 : delete data;
1259 0 : return;
1260 : }
1261 :
1262 0 : if (aTag == SCTAG_DOM_IMAGEBITMAP) {
1263 0 : MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
1264 : mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
1265 0 : MOZ_ASSERT(aContent);
1266 : ImageBitmapCloneData* data =
1267 0 : static_cast<ImageBitmapCloneData*>(aContent);
1268 0 : delete data;
1269 0 : return;
1270 : }
1271 : }
1272 :
1273 : bool
1274 0 : StructuredCloneHolder::TakeTransferredPortsAsSequence(Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts)
1275 : {
1276 0 : nsTArray<RefPtr<MessagePort>> ports = TakeTransferredPorts();
1277 :
1278 0 : aPorts.Clear();
1279 0 : for (uint32_t i = 0, len = ports.Length(); i < len; ++i) {
1280 0 : if (!aPorts.AppendElement(ports[i].forget(), fallible)) {
1281 0 : return false;
1282 : }
1283 : }
1284 :
1285 0 : return true;
1286 : }
1287 :
1288 : } // dom namespace
1289 : } // mozilla namespace
|