Bug 1185381 - Make FileList clonable - patch 3 - FileListClonedData implementation, r=smaug

This commit is contained in:
Andrea Marchesini 2015-07-22 17:04:22 +01:00
parent 9e06b3f460
commit 1759db26d0
3 changed files with 100 additions and 19 deletions

View File

@ -21,6 +21,30 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(FileList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(FileList)
/* static */ already_AddRefed<FileList>
FileList::Create(nsISupports* aParent, FileListClonedData* aData)
{
MOZ_ASSERT(aData);
nsRefPtr<FileList> fileList = new FileList(aParent);
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = aData->BlobImpls();
for (uint32_t i = 0; i < blobImpls.Length(); ++i) {
const nsRefPtr<BlobImpl>& blobImpl = blobImpls[i];
MOZ_ASSERT(blobImpl);
MOZ_ASSERT(blobImpl->IsFile());
nsRefPtr<File> file = File::Create(aParent, blobImpl);
MOZ_ASSERT(file);
if (NS_WARN_IF(!fileList->Append(file))) {
return nullptr;
}
}
return fileList.forget();
}
JSObject*
FileList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
@ -43,5 +67,19 @@ FileList::Item(uint32_t aIndex, nsISupports** aFile)
return NS_OK;
}
already_AddRefed<FileListClonedData>
FileList::CreateClonedData() const
{
nsTArray<nsRefPtr<BlobImpl>> blobImpls;
for (uint32_t i = 0; i < mFiles.Length(); ++i) {
blobImpls.AppendElement(mFiles[i]->Impl());
}
nsRefPtr<FileListClonedData> data = new FileListClonedData(blobImpls);
return data.forget();
}
NS_IMPL_ISUPPORTS0(FileListClonedData)
} // namespace dom
} // namespace mozilla

View File

@ -13,8 +13,30 @@
namespace mozilla {
namespace dom {
class BlobImpls;
class File;
class FileListClonedData final : public nsISupports
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
explicit FileListClonedData(const nsTArray<nsRefPtr<BlobImpl>>& aBlobImpls)
: mBlobImpls(aBlobImpls)
{}
const nsTArray<nsRefPtr<BlobImpl>>& BlobImpls() const
{
return mBlobImpls;
}
private:
~FileListClonedData()
{}
const nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
};
class FileList final : public nsIDOMFileList,
public nsWrapperCache
{
@ -28,6 +50,9 @@ public:
: mParent(aParent)
{}
static already_AddRefed<FileList>
Create(nsISupports* aParent, FileListClonedData* aData);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
@ -89,6 +114,9 @@ public:
return mFiles.Length();
}
// Useful for cloning
already_AddRefed<FileListClonedData> CreateClonedData() const;
private:
~FileList() {}

View File

@ -9,6 +9,7 @@
#include "MessageEvent.h"
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/FileList.h"
#include "mozilla/dom/FileListBinding.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/PMessagePort.h"
@ -86,12 +87,27 @@ PostMessageEvent::ReadStructuredClone(JSContext* cx,
if (tag == SCTAG_DOM_FILELIST) {
NS_ASSERTION(!data, "Data should be empty");
nsISupports* supports;
if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
// What we get back from the reader is a FileListClonedData.
// From that we create a new FileList.
FileListClonedData* fileListClonedData;
if (JS_ReadBytes(reader, &fileListClonedData, sizeof(fileListClonedData))) {
MOZ_ASSERT(fileListClonedData);
// nsRefPtr<FileList> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(cx);
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
return val.toObjectOrNull();
{
nsRefPtr<FileList> fileList =
FileList::Create(scInfo->window, fileListClonedData);
if (!fileList || !ToJSValue(cx, fileList, &val)) {
return nullptr;
}
}
return &val.toObject();
}
}
@ -127,21 +143,20 @@ PostMessageEvent::WriteStructuredClone(JSContext* cx,
}
}
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
if (wrappedNative) {
uint32_t scTag = 0;
nsISupports* supports = wrappedNative->Native();
nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
if (list)
scTag = SCTAG_DOM_FILELIST;
if (scTag)
return JS_WriteUint32Pair(writer, scTag, 0) &&
JS_WriteBytes(writer, &supports, sizeof(supports)) &&
scInfo->event->StoreISupports(supports);
// See if this is a FileList object.
{
FileList* fileList = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, obj, fileList))) {
nsRefPtr<FileListClonedData> fileListClonedData =
fileList->CreateClonedData();
MOZ_ASSERT(fileListClonedData);
FileListClonedData* ptr = fileListClonedData.get();
if (JS_WriteUint32Pair(writer, SCTAG_DOM_FILELIST, 0) &&
JS_WriteBytes(writer, &ptr, sizeof(ptr))) {
scInfo->event->StoreISupports(fileListClonedData);
return true;
}
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks =