LCOV - code coverage report
Current view: top level - dom/base - StructuredCloneHolder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 115 544 21.1 %
Date: 2017-07-14 16:53:18 Functions: 17 47 36.2 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13