bool StructuredCloneHelper::WriteCallback(JSContext* aCx, JSStructuredCloneWriter* aWriter, JS::Handle<JSObject*> aObj) { if (!mSupportsCloning) { return false; } // See if this is a File/Blob object. { Blob* blob = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) { BlobImpl* blobImpl = blob->Impl(); if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, mBlobImplArray.Length())) { mBlobImplArray.AppendElement(blobImpl); return true; } return false; } } { FileList* fileList = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) { // A FileList is serialized writing the X number of elements and the offset // from mBlobImplArray. The Read will take X elements from mBlobImplArray // starting from the offset. if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST, fileList->Length()) || !JS_WriteUint32Pair(aWriter, 0, mBlobImplArray.Length())) { return false; } for (uint32_t i = 0; i < fileList->Length(); ++i) { mBlobImplArray.AppendElement(fileList->Item(i)->Impl()); } return true; } } // See if this is an ImageBitmap object. { ImageBitmap* imageBitmap = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) { return ImageBitmap::WriteStructuredClone(aWriter, GetImages(), imageBitmap); } } return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); }
nsresult nsFileControlFrame::DnDListener::GetBlobImplForWebkitDirectory(nsIDOMFileList* aFileList, BlobImpl** aBlobImpl) { *aBlobImpl = nullptr; HTMLInputElement* inputElement = HTMLInputElement::FromContent(mFrame->GetContent()); bool webkitDirPicker = Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) && inputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory); if (!webkitDirPicker) { return NS_OK; } if (!aFileList) { return NS_ERROR_FAILURE; } FileList* files = static_cast<FileList*>(aFileList); // webkitdirectory doesn't care about the length of the file list but // only about the first item on it. uint32_t len = files->Length(); if (len) { File* file = files->Item(0); if (file) { BlobImpl* impl = file->Impl(); if (impl && impl->IsDirectory()) { RefPtr<BlobImpl> retVal = impl; retVal.swap(*aBlobImpl); return NS_OK; } } } return NS_ERROR_FAILURE; }
/** * This is called when we receive a drop or a dragover. */ NS_IMETHODIMP nsFileControlFrame::DnDListener::HandleEvent(nsIDOMEvent* aEvent) { NS_ASSERTION(mFrame, "We should have been unregistered"); bool defaultPrevented = false; aEvent->GetDefaultPrevented(&defaultPrevented); if (defaultPrevented) { return NS_OK; } nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent); if (!dragEvent) { return NS_OK; } nsCOMPtr<nsIDOMDataTransfer> dataTransfer; dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer)); if (!IsValidDropData(dataTransfer)) { return NS_OK; } nsCOMPtr<nsIContent> content = mFrame->GetContent(); bool supportsMultiple = content && content->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple); if (!CanDropTheseFiles(dataTransfer, supportsMultiple)) { dataTransfer->SetDropEffect(NS_LITERAL_STRING("none")); aEvent->StopPropagation(); return NS_OK; } nsAutoString eventType; aEvent->GetType(eventType); if (eventType.EqualsLiteral("dragover")) { // Prevent default if we can accept this drag data aEvent->PreventDefault(); return NS_OK; } if (eventType.EqualsLiteral("drop")) { aEvent->StopPropagation(); aEvent->PreventDefault(); NS_ASSERTION(content, "The frame has no content???"); HTMLInputElement* inputElement = HTMLInputElement::FromContent(content); NS_ASSERTION(inputElement, "No input element for this file upload control frame!"); nsCOMPtr<nsIDOMFileList> fileList; dataTransfer->GetFiles(getter_AddRefs(fileList)); RefPtr<BlobImpl> webkitDir; nsresult rv = GetBlobImplForWebkitDirectory(fileList, getter_AddRefs(webkitDir)); NS_ENSURE_SUCCESS(rv, NS_OK); nsTArray<OwningFileOrDirectory> array; if (webkitDir) { AppendBlobImplAsDirectory(array, webkitDir, content); inputElement->MozSetDndFilesAndDirectories(array); } else { bool blinkFileSystemEnabled = Preferences::GetBool("dom.webkitBlink.filesystem.enabled", false); if (blinkFileSystemEnabled) { FileList* files = static_cast<FileList*>(fileList.get()); if (files) { for (uint32_t i = 0; i < files->Length(); ++i) { File* file = files->Item(i); if (file) { if (file->Impl() && file->Impl()->IsDirectory()) { AppendBlobImplAsDirectory(array, file->Impl(), content); } else { OwningFileOrDirectory* element = array.AppendElement(); element->SetAsFile() = file; } } } } } // This is rather ugly. Pass the directories as Files using SetFiles, // but then if blink filesystem API is enabled, it wants // FileOrDirectory array. inputElement->SetFiles(fileList, true); if (blinkFileSystemEnabled) { inputElement->UpdateEntries(array); } nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(), content, NS_LITERAL_STRING("input"), true, false); nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(), content, NS_LITERAL_STRING("change"), true, false); } } return NS_OK; }