diff --git a/dom/base/StructuredCloneHelper.cpp b/dom/base/StructuredCloneHelper.cpp index 7975e42e1bd..baad651b0a0 100644 --- a/dom/base/StructuredCloneHelper.cpp +++ b/dom/base/StructuredCloneHelper.cpp @@ -21,6 +21,8 @@ #include "mozilla/dom/StructuredClone.h" #include "mozilla/dom/MessagePort.h" #include "mozilla/dom/MessagePortBinding.h" +#include "mozilla/dom/OffscreenCanvas.h" +#include "mozilla/dom/OffscreenCanvasBinding.h" #include "mozilla/dom/PMessagePort.h" #include "mozilla/dom/StructuredCloneTags.h" #include "mozilla/dom/SubtleCryptoBinding.h" @@ -1062,6 +1064,25 @@ StructuredCloneHelper::ReadTransferCallback(JSContext* aCx, return true; } + if (aTag == SCTAG_DOM_CANVAS) { + MOZ_ASSERT(mContext == SameProcessSameThread || + mContext == SameProcessDifferentThread); + MOZ_ASSERT(aContent); + OffscreenCanvasCloneData* data = + static_cast(aContent); + nsRefPtr canvas = OffscreenCanvas::CreateFromCloneData(data); + delete data; + + JS::Rooted value(aCx); + if (!GetOrCreateDOMReflector(aCx, canvas, &value)) { + JS_ClearPendingException(aCx); + return false; + } + + aReturnObject.set(&value.toObject()); + return true; + } + return false; } @@ -1093,6 +1114,24 @@ StructuredCloneHelper::WriteTransferCallback(JSContext* aCx, return true; } + + if (mContext == SameProcessSameThread || + mContext == SameProcessDifferentThread) { + OffscreenCanvas* canvas = nullptr; + rv = UNWRAP_OBJECT(OffscreenCanvas, aObj, canvas); + if (NS_SUCCEEDED(rv)) { + MOZ_ASSERT(canvas); + + *aExtraData = 0; + *aTag = SCTAG_DOM_CANVAS; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = canvas->ToCloneData(); + MOZ_ASSERT(*aContent); + canvas->SetNeutered(); + + return true; + } + } } return false; @@ -1110,6 +1149,17 @@ StructuredCloneHelper::FreeTransferCallback(uint32_t aTag, MOZ_ASSERT(!aContent); MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); MessagePort::ForceClose(mPortIdentifiers[aExtraData]); + return; + } + + if (aTag == SCTAG_DOM_CANVAS) { + MOZ_ASSERT(mContext == SameProcessSameThread || + mContext == SameProcessDifferentThread); + MOZ_ASSERT(aContent); + OffscreenCanvasCloneData* data = + static_cast(aContent); + delete data; + return; } } diff --git a/dom/base/StructuredCloneTags.h b/dom/base/StructuredCloneTags.h index fe6ccdf371f..f1fec533d4d 100644 --- a/dom/base/StructuredCloneTags.h +++ b/dom/base/StructuredCloneTags.h @@ -48,6 +48,9 @@ enum StructuredCloneTags { SCTAG_DOM_FORMDATA, + // This tag is for OffscreenCanvas. + SCTAG_DOM_CANVAS, + SCTAG_DOM_MAX }; diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index e95b4ef8345..fb72fb3ed6c 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -195,17 +195,20 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); // Copy some memory. It will be automatically freed by the destructor. - bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION); + bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, + const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); // Adopt some memory. It will be automatically freed by the destructor. // data must have been allocated by the JS engine (e.g., extracted via // JSAutoStructuredCloneBuffer::steal). - void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION); + void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, + const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); // Release the buffer and transfer ownership to the caller. The caller is // responsible for calling JS_ClearStructuredClone or feeding the memory // back to JSAutoStructuredCloneBuffer::adopt. - void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr); + void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr, + const JSStructuredCloneCallbacks** callbacks=nullptr, void** closure=nullptr); // Abandon ownership of any transferable objects stored in the buffer, // without freeing the buffer itself. Useful when copying the data out into diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 00c916eb73d..505b3198e6c 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -2054,7 +2054,7 @@ JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp, JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other) { ownTransferables_ = other.ownTransferables_; - other.steal(&data_, &nbytes_, &version_); + other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_); } JSAutoStructuredCloneBuffer& @@ -2063,7 +2063,7 @@ JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other) MOZ_ASSERT(&other != this); clear(); ownTransferables_ = other.ownTransferables_; - other.steal(&data_, &nbytes_, &version_); + other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_); return *this; } @@ -2088,7 +2088,9 @@ JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCal } bool -JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version) +JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version, + const JSStructuredCloneCallbacks* callbacks, + void* closure) { // transferable objects cannot be copied if (StructuredCloneHasTransferObjects(data_, nbytes_)) @@ -2104,31 +2106,45 @@ JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32 data_ = newData; nbytes_ = nbytes; version_ = version; + callbacks_ = callbacks; + closure_ = closure; ownTransferables_ = NoTransferables; return true; } void -JSAutoStructuredCloneBuffer::adopt(uint64_t* data, size_t nbytes, uint32_t version) +JSAutoStructuredCloneBuffer::adopt(uint64_t* data, size_t nbytes, uint32_t version, + const JSStructuredCloneCallbacks* callbacks, + void* closure) { clear(); data_ = data; nbytes_ = nbytes; version_ = version; + callbacks_ = callbacks; + closure_ = closure; ownTransferables_ = OwnsTransferablesIfAny; } void -JSAutoStructuredCloneBuffer::steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp) +JSAutoStructuredCloneBuffer::steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp, + const JSStructuredCloneCallbacks** callbacks, + void** closure) { *datap = data_; *nbytesp = nbytes_; if (versionp) *versionp = version_; + if (callbacks) + *callbacks = callbacks_; + if (closure) + *closure = closure_; data_ = nullptr; nbytes_ = 0; version_ = 0; + callbacks_ = 0; + closure_ = 0; ownTransferables_ = NoTransferables; }