Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* vim: set sw=4 ts=8 et tw=80 : */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "StructuredCloneUtils.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "nsIDOMFile.h" |
michael@0 | 10 | #include "nsIDOMDOMException.h" |
michael@0 | 11 | #include "nsIMutable.h" |
michael@0 | 12 | #include "nsIXPConnect.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "nsContentUtils.h" |
michael@0 | 15 | #include "nsJSEnvironment.h" |
michael@0 | 16 | #include "MainThreadUtils.h" |
michael@0 | 17 | #include "StructuredCloneTags.h" |
michael@0 | 18 | #include "jsapi.h" |
michael@0 | 19 | |
michael@0 | 20 | using namespace mozilla::dom; |
michael@0 | 21 | |
michael@0 | 22 | namespace { |
michael@0 | 23 | |
michael@0 | 24 | void |
michael@0 | 25 | Error(JSContext* aCx, uint32_t aErrorId) |
michael@0 | 26 | { |
michael@0 | 27 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 28 | NS_DOMStructuredCloneError(aCx, aErrorId); |
michael@0 | 29 | } |
michael@0 | 30 | |
michael@0 | 31 | JSObject* |
michael@0 | 32 | Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, |
michael@0 | 33 | uint32_t aData, void* aClosure) |
michael@0 | 34 | { |
michael@0 | 35 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 36 | MOZ_ASSERT(aClosure); |
michael@0 | 37 | |
michael@0 | 38 | StructuredCloneClosure* closure = |
michael@0 | 39 | static_cast<StructuredCloneClosure*>(aClosure); |
michael@0 | 40 | |
michael@0 | 41 | if (aTag == SCTAG_DOM_FILE) { |
michael@0 | 42 | MOZ_ASSERT(aData < closure->mBlobs.Length()); |
michael@0 | 43 | |
michael@0 | 44 | nsCOMPtr<nsIDOMFile> file = do_QueryInterface(closure->mBlobs[aData]); |
michael@0 | 45 | MOZ_ASSERT(file); |
michael@0 | 46 | |
michael@0 | 47 | #ifdef DEBUG |
michael@0 | 48 | { |
michael@0 | 49 | // File should not be mutable. |
michael@0 | 50 | nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file); |
michael@0 | 51 | bool isMutable; |
michael@0 | 52 | MOZ_ASSERT(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable))); |
michael@0 | 53 | MOZ_ASSERT(!isMutable); |
michael@0 | 54 | } |
michael@0 | 55 | #endif |
michael@0 | 56 | |
michael@0 | 57 | JS::Rooted<JS::Value> wrappedFile(aCx); |
michael@0 | 58 | nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile), |
michael@0 | 59 | &wrappedFile); |
michael@0 | 60 | if (NS_FAILED(rv)) { |
michael@0 | 61 | Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR); |
michael@0 | 62 | return nullptr; |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | return &wrappedFile.toObject(); |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | if (aTag == SCTAG_DOM_BLOB) { |
michael@0 | 69 | MOZ_ASSERT(aData < closure->mBlobs.Length()); |
michael@0 | 70 | |
michael@0 | 71 | nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(closure->mBlobs[aData]); |
michael@0 | 72 | MOZ_ASSERT(blob); |
michael@0 | 73 | |
michael@0 | 74 | #ifdef DEBUG |
michael@0 | 75 | { |
michael@0 | 76 | // Blob should not be mutable. |
michael@0 | 77 | nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob); |
michael@0 | 78 | bool isMutable; |
michael@0 | 79 | MOZ_ASSERT(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable))); |
michael@0 | 80 | MOZ_ASSERT(!isMutable); |
michael@0 | 81 | } |
michael@0 | 82 | #endif |
michael@0 | 83 | |
michael@0 | 84 | JS::Rooted<JS::Value> wrappedBlob(aCx); |
michael@0 | 85 | nsresult rv = nsContentUtils::WrapNative(aCx, blob, &NS_GET_IID(nsIDOMBlob), |
michael@0 | 86 | &wrappedBlob); |
michael@0 | 87 | if (NS_FAILED(rv)) { |
michael@0 | 88 | Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR); |
michael@0 | 89 | return nullptr; |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | return &wrappedBlob.toObject(); |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr); |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | bool |
michael@0 | 99 | Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, |
michael@0 | 100 | JS::Handle<JSObject*> aObj, void* aClosure) |
michael@0 | 101 | { |
michael@0 | 102 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 103 | MOZ_ASSERT(aClosure); |
michael@0 | 104 | |
michael@0 | 105 | StructuredCloneClosure* closure = |
michael@0 | 106 | static_cast<StructuredCloneClosure*>(aClosure); |
michael@0 | 107 | |
michael@0 | 108 | // See if this is a wrapped native. |
michael@0 | 109 | nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative; |
michael@0 | 110 | nsContentUtils::XPConnect()-> |
michael@0 | 111 | GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative)); |
michael@0 | 112 | |
michael@0 | 113 | if (wrappedNative) { |
michael@0 | 114 | // Get the raw nsISupports out of it. |
michael@0 | 115 | nsISupports* wrappedObject = wrappedNative->Native(); |
michael@0 | 116 | MOZ_ASSERT(wrappedObject); |
michael@0 | 117 | |
michael@0 | 118 | // See if the wrapped native is a nsIDOMFile. |
michael@0 | 119 | nsCOMPtr<nsIDOMFile> file = do_QueryInterface(wrappedObject); |
michael@0 | 120 | if (file) { |
michael@0 | 121 | nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file); |
michael@0 | 122 | if (mutableFile && |
michael@0 | 123 | NS_SUCCEEDED(mutableFile->SetMutable(false)) && |
michael@0 | 124 | JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILE, |
michael@0 | 125 | closure->mBlobs.Length())) { |
michael@0 | 126 | closure->mBlobs.AppendElement(file); |
michael@0 | 127 | return true; |
michael@0 | 128 | } |
michael@0 | 129 | } |
michael@0 | 130 | |
michael@0 | 131 | // See if the wrapped native is a nsIDOMBlob. |
michael@0 | 132 | nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(wrappedObject); |
michael@0 | 133 | if (blob) { |
michael@0 | 134 | nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob); |
michael@0 | 135 | if (mutableBlob && |
michael@0 | 136 | NS_SUCCEEDED(mutableBlob->SetMutable(false)) && |
michael@0 | 137 | JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, |
michael@0 | 138 | closure->mBlobs.Length())) { |
michael@0 | 139 | closure->mBlobs.AppendElement(blob); |
michael@0 | 140 | return true; |
michael@0 | 141 | } |
michael@0 | 142 | } |
michael@0 | 143 | } |
michael@0 | 144 | |
michael@0 | 145 | return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | JSStructuredCloneCallbacks gCallbacks = { |
michael@0 | 149 | Read, |
michael@0 | 150 | Write, |
michael@0 | 151 | Error, |
michael@0 | 152 | nullptr, |
michael@0 | 153 | nullptr, |
michael@0 | 154 | nullptr |
michael@0 | 155 | }; |
michael@0 | 156 | |
michael@0 | 157 | } // anonymous namespace |
michael@0 | 158 | |
michael@0 | 159 | namespace mozilla { |
michael@0 | 160 | namespace dom { |
michael@0 | 161 | |
michael@0 | 162 | bool |
michael@0 | 163 | ReadStructuredClone(JSContext* aCx, uint64_t* aData, size_t aDataLength, |
michael@0 | 164 | const StructuredCloneClosure& aClosure, |
michael@0 | 165 | JS::MutableHandle<JS::Value> aClone) |
michael@0 | 166 | { |
michael@0 | 167 | void* closure = &const_cast<StructuredCloneClosure&>(aClosure); |
michael@0 | 168 | return !!JS_ReadStructuredClone(aCx, aData, aDataLength, |
michael@0 | 169 | JS_STRUCTURED_CLONE_VERSION, aClone, |
michael@0 | 170 | &gCallbacks, closure); |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | bool |
michael@0 | 174 | WriteStructuredClone(JSContext* aCx, JS::Handle<JS::Value> aSource, |
michael@0 | 175 | JSAutoStructuredCloneBuffer& aBuffer, |
michael@0 | 176 | StructuredCloneClosure& aClosure) |
michael@0 | 177 | { |
michael@0 | 178 | return aBuffer.write(aCx, aSource, &gCallbacks, &aClosure); |
michael@0 | 179 | } |
michael@0 | 180 | |
michael@0 | 181 | } // namespace dom |
michael@0 | 182 | } // namespace mozilla |