author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Thu, 09 Jun 2016 15:30:53 +0200 | |
changeset 341277 | f8e3b81a79f45ef8647c98281a9a00d1ddb28b73 |
parent 341276 | f3ff62941927bab2862e525c1b68864e59cdc2c3 |
child 341278 | 3ccccf8e5036179a3178437cabc154b5e04b333d |
child 341293 | 4678ba5309817e01839b86f14cbc9469e78c8ae8 |
child 341388 | 42c6d8f364b68549a4fabce6e9c71600fbbbe784 |
push id | 6389 |
push user | raliiev@mozilla.com |
push date | Mon, 19 Sep 2016 13:38:22 +0000 |
treeherder | mozilla-beta@01d67bfe6c81 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 906420 |
milestone | 50.0a1 |
backs out | 5c836acf3197c5f30be8832e9f822bfeb175dc24 |
first release with | nightly linux32
f8e3b81a79f4
/
50.0a1
/
20160609064045
/
files
nightly linux64
f8e3b81a79f4
/
50.0a1
/
20160609064045
/
files
nightly mac
f8e3b81a79f4
/
50.0a1
/
20160609064045
/
files
nightly win32
f8e3b81a79f4
/
50.0a1
/
20160609064045
/
files
nightly win64
f8e3b81a79f4
/
50.0a1
/
20160609064045
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
50.0a1
/
20160609064045
/
pushlog to previous
nightly linux64
50.0a1
/
20160609064045
/
pushlog to previous
nightly mac
50.0a1
/
20160609064045
/
pushlog to previous
nightly win32
50.0a1
/
20160609064045
/
pushlog to previous
nightly win64
50.0a1
/
20160609064045
/
pushlog to previous
|
--- a/dom/base/nsCopySupport.cpp +++ b/dom/base/nsCopySupport.cpp @@ -686,18 +686,18 @@ nsCopySupport::FireClipboardEvent(EventM const bool chromeShell = docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome; // next, fire the cut, copy or paste event bool doDefault = true; RefPtr<DataTransfer> clipboardData; if (chromeShell || Preferences::GetBool("dom.event.clipboardevents.enabled", true)) { clipboardData = - new DataTransfer(doc->GetScopeObject(), aEventMessage, - aEventMessage == ePaste, aClipboardType); + new DataTransfer(piWindow, aEventMessage, aEventMessage == ePaste, + aClipboardType); nsEventStatus status = nsEventStatus_eIgnore; InternalClipboardEvent evt(true, aEventMessage); evt.mClipboardData = clipboardData; EventDispatcher::Dispatch(content, presShell->GetPresContext(), &evt, nullptr, &status); // If the event was cancelled, don't do the clipboard operation doDefault = (status != nsEventStatus_eConsumeNoDefault);
--- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -25,39 +25,48 @@ #include "nsCRT.h" #include "nsIScriptObjectPrincipal.h" #include "nsIScriptContext.h" #include "nsIDocument.h" #include "nsIScriptGlobalObject.h" #include "nsVariant.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/DataTransferBinding.h" -#include "mozilla/dom/DataTransferItemList.h" #include "mozilla/dom/Directory.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/FileList.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/OSFileSystem.h" #include "mozilla/dom/Promise.h" -#include "nsNetUtil.h" namespace mozilla { namespace dom { +inline void +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, + TransferItem& aField, + const char* aName, + uint32_t aFlags = 0) +{ + ImplCycleCollectionTraverse(aCallback, aField.mData, aName, aFlags); +} + NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer) NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList) NS_IMPL_CYCLE_COLLECTION_UNLINK(mItems) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mItems) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DataTransfer) NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransfer) @@ -91,17 +100,16 @@ DataTransfer::DataTransfer(nsISupports* , mReadOnly(true) , mIsExternal(aIsExternal) , mUserCancelled(false) , mIsCrossDomainSubFrameDrop(false) , mClipboardType(aClipboardType) , mDragImageX(0) , mDragImageY(0) { - mItems = new DataTransferItemList(this, aIsExternal, false /* aIsCrossDomainSubFrameDrop */); // For these events, we want to be able to add data to the data transfer, so // clear the readonly state. Otherwise, the data is already present. For // external usage, cache the data from the native clipboard or drag. if (aEventMessage == eCut || aEventMessage == eCopy || aEventMessage == eDragStart || aEventMessage == eLegacyDragGesture) { mReadOnly = false; @@ -118,40 +126,36 @@ DataTransfer::DataTransfer(nsISupports* DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage, const uint32_t aEffectAllowed, bool aCursorState, bool aIsExternal, bool aUserCancelled, bool aIsCrossDomainSubFrameDrop, int32_t aClipboardType, - DataTransferItemList* aItems, + nsTArray<nsTArray<TransferItem> >& aItems, Element* aDragImage, uint32_t aDragImageX, uint32_t aDragImageY) : mParent(aParent) , mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE) , mEffectAllowed(aEffectAllowed) , mEventMessage(aEventMessage) , mCursorState(aCursorState) , mReadOnly(true) , mIsExternal(aIsExternal) , mUserCancelled(aUserCancelled) , mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop) , mClipboardType(aClipboardType) + , mItems(aItems) , mDragImage(aDragImage) , mDragImageX(aDragImageX) , mDragImageY(aDragImageY) { MOZ_ASSERT(mParent); - MOZ_ASSERT(aItems); - - // We clone the items array after everything else, so that it has a valid - // mParent value - mItems = aItems->Clone(this); // The items are copied from aItems into mItems. There is no need to copy // the actual data in the items as the data transfer will be read only. The // draggesture and dragstart events are the only times when items are // modifiable, but those events should have been using the first constructor // above. NS_ASSERTION(aEventMessage != eLegacyDragGesture && aEventMessage != eDragStart, "invalid event type for DataTransfer constructor"); @@ -283,86 +287,112 @@ DataTransfer::GetMozUserCancelled(bool* { *aUserCancelled = MozUserCancelled(); return NS_OK; } FileList* DataTransfer::GetFiles(ErrorResult& aRv) { - return mItems->Files(); + return GetFileListInternal(aRv, nsContentUtils::SubjectPrincipal()); +} + +FileList* +DataTransfer::GetFileListInternal(ErrorResult& aRv, + nsIPrincipal* aSubjectPrincipal) +{ + if (mEventMessage != eDrop && + mEventMessage != eLegacyDragDrop && + mEventMessage != ePaste) { + return nullptr; + } + + if (!mFileList) { + mFileList = new FileList(static_cast<nsIDOMDataTransfer*>(this)); + + uint32_t count = mItems.Length(); + + for (uint32_t i = 0; i < count; i++) { + nsCOMPtr<nsIVariant> variant; + aRv = GetDataAtInternal(NS_ConvertUTF8toUTF16(kFileMime), i, + aSubjectPrincipal, getter_AddRefs(variant)); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + if (!variant) { + continue; + } + + nsCOMPtr<nsISupports> supports; + nsresult rv = variant->GetAsISupports(getter_AddRefs(supports)); + + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + + nsCOMPtr<nsIFile> file = do_QueryInterface(supports); + + RefPtr<File> domFile; + if (file) { + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default, + "nsIFile objects are not expected on the content process"); + + bool isDir; + aRv = file->IsDirectory(&isDir); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + if (isDir) { + continue; + } + + domFile = File::CreateFromFile(GetParentObject(), file); + } else { + nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(supports); + if (!blobImpl) { + continue; + } + + MOZ_ASSERT(blobImpl->IsFile()); + + domFile = File::Create(GetParentObject(), blobImpl); + MOZ_ASSERT(domFile); + } + + mFileList->Append(domFile); + } + } + + return mFileList; } NS_IMETHODIMP DataTransfer::GetFiles(nsIDOMFileList** aFileList) { - if (!aFileList) { - return NS_ERROR_FAILURE; - } - ErrorResult rv; - RefPtr<FileList> files = GetFiles(rv); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - files.forget(aFileList); - return NS_OK; + NS_IF_ADDREF(*aFileList = + GetFileListInternal(rv, nsContentUtils::GetSystemPrincipal())); + return rv.StealNSResult(); } already_AddRefed<DOMStringList> -DataTransfer::GetTypes(ErrorResult& aRv) const +DataTransfer::Types() const { - RefPtr<DOMStringList> types = new DOMStringList(); - - const nsTArray<RefPtr<DataTransferItem>>* items = mItems->MozItemsAt(0); - if (!items || items->IsEmpty()) { - return types.forget(); - } - - bool addFile = false; - for (uint32_t i = 0; i < items->Length(); i++) { - DataTransferItem* item = items->ElementAt(i); - MOZ_ASSERT(item); - - nsAutoString type; - item->GetType(type); - if (NS_WARN_IF(!types->Add(type))) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - if (!addFile) { - addFile = item->Kind() == DataTransferItem::KIND_FILE; - } - } - - // If we have any files, we need to also add the "Files" type! - if (addFile && NS_WARN_IF(!types->Add(NS_LITERAL_STRING("Files")))) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - return types.forget(); + ErrorResult rv; + return MozTypesAt(0, rv); } NS_IMETHODIMP DataTransfer::GetTypes(nsISupports** aTypes) { - if (NS_WARN_IF(!aTypes)) { - return NS_ERROR_FAILURE; - } + RefPtr<DOMStringList> types = Types(); + types.forget(aTypes); - ErrorResult rv; - RefPtr<DOMStringList> types = GetTypes(rv); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - types.forget(aTypes); return NS_OK; } void DataTransfer::GetData(const nsAString& aFormat, nsAString& aData, ErrorResult& aRv) { // return an empty string if data for the format was not found @@ -440,17 +470,17 @@ DataTransfer::SetData(const nsAString& a void DataTransfer::ClearData(const Optional<nsAString>& aFormat, ErrorResult& aRv) { if (mReadOnly) { aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return; } - if (MozItemCount() == 0) { + if (mItems.Length() == 0) { return; } if (aFormat.WasPassed()) { MozClearDataAtHelper(aFormat.Value(), 0, aRv); } else { MozClearDataAtHelper(EmptyString(), 0, aRv); } @@ -529,27 +559,38 @@ DataTransfer::MozTypesAt(uint32_t aIndex if (aIndex > 0 && (mEventMessage == eCut || mEventMessage == eCopy || mEventMessage == ePaste)) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return nullptr; } RefPtr<DOMStringList> types = new DOMStringList(); - if (aIndex < MozItemCount()) { + if (aIndex < mItems.Length()) { + bool addFile = false; // note that you can retrieve the types regardless of their principal - const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(aIndex); + const nsTArray<TransferItem>& item = mItems[aIndex]; + for (uint32_t i = 0; i < item.Length(); i++) { + const nsString& format = item[i].mFormat; + types->Add(format); + if (!addFile) { + addFile = format.EqualsASCII(kFileMime); + } + } - for (uint32_t i = 0; i < items.Length(); i++) { - nsAutoString type; - items[i]->GetType(type); - if (NS_WARN_IF(!types->Add(type))) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; + if (addFile) { + // If this is a content caller, and a file is in the data transfer, remove + // the non-file types. This prevents alternate text forms of the file + // from being returned. + if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) { + types->Clear(); + types->Add(NS_LITERAL_STRING(kFileMime)); } + + types->Add(NS_LITERAL_STRING("Files")); } } return types.forget(); } NS_IMETHODIMP DataTransfer::MozTypesAt(uint32_t aIndex, nsISupports** aTypes) @@ -575,87 +616,90 @@ DataTransfer::GetDataAtInternal(const ns nsIVariant** aData) { *aData = nullptr; if (aFormat.IsEmpty()) { return NS_OK; } - if (aIndex >= MozItemCount()) { + if (aIndex >= mItems.Length()) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } // Only the first item is valid for clipboard events if (aIndex > 0 && (mEventMessage == eCut || mEventMessage == eCopy || mEventMessage == ePaste)) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } nsAutoString format; GetRealFormat(aFormat, format); - const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(aIndex); - if (!aFormat.EqualsLiteral(kFileMime) && + nsTArray<TransferItem>& item = mItems[aIndex]; + + // If this is a content caller, and a file is in the data transfer, only + // return the file type. + if (!format.EqualsLiteral(kFileMime) && !nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) { - for (uint32_t i = 0; i < items.Length(); ++i) { - if (items[i]->IsFile()) { + uint32_t count = item.Length(); + for (uint32_t i = 0; i < count; i++) { + if (item[i].mFormat.EqualsLiteral(kFileMime)) { return NS_OK; } } } // Check if the caller is allowed to access the drag data. Callers with // chrome privileges can always read the data. During the // drop event, allow retrieving the data except in the case where the // source of the drag is in a child frame of the caller. In that case, // we only allow access to data of the same principal. During other events, // only allow access to the data with the same principal. bool checkFormatItemPrincipal = mIsCrossDomainSubFrameDrop || (mEventMessage != eDrop && mEventMessage != eLegacyDragDrop && mEventMessage != ePaste); - MOZ_ASSERT(aSubjectPrincipal); - RefPtr<DataTransferItem> item = mItems->MozItemByTypeAt(format, aIndex); - if (!item) { - // The index exists but there's no data for the specified format, in this - // case we just return undefined - return NS_OK; - } - - if (item->Principal() && checkFormatItemPrincipal && - !aSubjectPrincipal->Subsumes(item->Principal())) { - return NS_ERROR_DOM_SECURITY_ERR; - } - - nsCOMPtr<nsIVariant> data = item->Data(); - MOZ_ASSERT(data); + uint32_t count = item.Length(); + for (uint32_t i = 0; i < count; i++) { + TransferItem& formatitem = item[i]; + if (formatitem.mFormat.Equals(format)) { + if (formatitem.mPrincipal && checkFormatItemPrincipal && + !aSubjectPrincipal->Subsumes(formatitem.mPrincipal)) { + return NS_ERROR_DOM_SECURITY_ERR; + } - nsCOMPtr<nsISupports> isupportsData; - nsresult rv = data->GetAsISupports(getter_AddRefs(isupportsData)); - - if (NS_SUCCEEDED(rv) && isupportsData) { - // Make sure the code that is calling us is same-origin with the data. - nsCOMPtr<EventTarget> pt = do_QueryInterface(isupportsData); - if (pt) { - nsresult rv = NS_OK; - nsIScriptContext* c = pt->GetContextForEventHandlers(&rv); - NS_ENSURE_TRUE(c && NS_SUCCEEDED(rv), NS_ERROR_DOM_SECURITY_ERR); - nsIGlobalObject* go = c->GetGlobalObject(); - NS_ENSURE_TRUE(go, NS_ERROR_DOM_SECURITY_ERR); - nsCOMPtr<nsIScriptObjectPrincipal> sp = do_QueryInterface(go); - MOZ_ASSERT(sp, "This cannot fail on the main thread."); - nsIPrincipal* dataPrincipal = sp->GetPrincipal(); - NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR); - NS_ENSURE_TRUE(aSubjectPrincipal->Subsumes(dataPrincipal), NS_ERROR_DOM_SECURITY_ERR); + if (!formatitem.mData) { + FillInExternalData(formatitem, aIndex); + } else { + nsCOMPtr<nsISupports> data; + formatitem.mData->GetAsISupports(getter_AddRefs(data)); + // Make sure the code that is calling us is same-origin with the data. + nsCOMPtr<EventTarget> pt = do_QueryInterface(data); + if (pt) { + nsresult rv = NS_OK; + nsIScriptContext* c = pt->GetContextForEventHandlers(&rv); + NS_ENSURE_TRUE(c && NS_SUCCEEDED(rv), NS_ERROR_DOM_SECURITY_ERR); + nsIGlobalObject* go = c->GetGlobalObject(); + NS_ENSURE_TRUE(go, NS_ERROR_DOM_SECURITY_ERR); + nsCOMPtr<nsIScriptObjectPrincipal> sp = do_QueryInterface(go); + MOZ_ASSERT(sp, "This cannot fail on the main thread."); + nsIPrincipal* dataPrincipal = sp->GetPrincipal(); + NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR); + NS_ENSURE_TRUE(aSubjectPrincipal->Subsumes(dataPrincipal), + NS_ERROR_DOM_SECURITY_ERR); + } + } + *aData = formatitem.mData; + NS_IF_ADDREF(*aData); + return NS_OK; } } - data.forget(aData); return NS_OK; } void DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat, uint32_t aIndex, JS::MutableHandle<JS::Value> aRetval, mozilla::ErrorResult& aRv) @@ -689,17 +733,17 @@ DataTransfer::SetDataAtInternal(const ns } if (mReadOnly) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; } // Specifying an index less than the current length will replace an existing // item. Specifying an index equal to the current length will add a new item. - if (aIndex > MozItemCount()) { + if (aIndex > mItems.Length()) { return NS_ERROR_DOM_INDEX_SIZE_ERR; } // Only the first item is valid for clipboard events if (aIndex > 0 && (mEventMessage == eCut || mEventMessage == eCopy || mEventMessage == ePaste)) { return NS_ERROR_DOM_INDEX_SIZE_ERR; @@ -747,57 +791,79 @@ void DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex, ErrorResult& aRv) { if (mReadOnly) { aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return; } - if (aIndex >= MozItemCount()) { + if (aIndex >= mItems.Length()) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; } // Only the first item is valid for clipboard events if (aIndex > 0 && (mEventMessage == eCut || mEventMessage == eCopy || mEventMessage == ePaste)) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; } MozClearDataAtHelper(aFormat, aIndex, aRv); - - // If we just cleared the 0-th index, and there are still more than 1 indexes - // remaining, MozClearDataAt should cause the 1st index to become the 0th - // index. This should _only_ happen when the MozClearDataAt function is - // explicitly called by script, as this behavior is inconsistent with spec. - // (however, so is the MozClearDataAt API) - - if (aIndex == 0 && mItems->MozItemCount() > 1 && - mItems->MozItemsAt(0)->Length() == 0) { - mItems->PopIndexZero(); - } } void DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex, ErrorResult& aRv) { MOZ_ASSERT(!mReadOnly); - MOZ_ASSERT(aIndex < MozItemCount()); + MOZ_ASSERT(aIndex < mItems.Length()); MOZ_ASSERT(aIndex == 0 || (mEventMessage != eCut && mEventMessage != eCopy && mEventMessage != ePaste)); nsAutoString format; GetRealFormat(aFormat, format); - mItems->MozRemoveByTypeAt(format, aIndex, aRv); + nsIPrincipal* principal = nsContentUtils::SubjectPrincipal(); + + // if the format is empty, clear all formats + bool clearall = format.IsEmpty(); + + nsTArray<TransferItem>& item = mItems[aIndex]; + // count backwards so that the count and index don't have to be adjusted + // after removing an element + for (int32_t i = item.Length() - 1; i >= 0; i--) { + TransferItem& formatitem = item[i]; + if (clearall || formatitem.mFormat.Equals(format)) { + // don't allow removing data that has a stronger principal + bool subsumes; + if (formatitem.mPrincipal && principal && + (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || + !subsumes)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + item.RemoveElementAt(i); + + // if a format was specified, break out. Otherwise, loop around until + // all formats have been removed + if (!clearall) { + break; + } + } + } + + // if the last format for an item is removed, remove the entire item + if (!item.Length()) { + mItems.RemoveElementAt(aIndex); + } } NS_IMETHODIMP DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex) { ErrorResult rv; MozClearDataAt(aFormat, aIndex, rv); return rv.StealNSResult(); @@ -840,27 +906,29 @@ DataTransfer::GetFilesAndDirectories(Err nsCOMPtr<nsIGlobalObject> global = parentNode->OwnerDoc()->GetScopeObject(); MOZ_ASSERT(global); if (!global) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } RefPtr<Promise> p = Promise::Create(global, aRv); - if (NS_WARN_IF(aRv.Failed())) { + if (aRv.Failed()) { return nullptr; } - RefPtr<FileList> files = mItems->Files(); - if (NS_WARN_IF(!files)) { - return nullptr; + if (!mFileList) { + GetFiles(aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } } Sequence<RefPtr<File>> filesSeq; - files->ToSequence(filesSeq, aRv); + mFileList->ToSequence(filesSeq, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } p->MaybeResolve(filesSeq); return p.forget(); } @@ -889,23 +957,24 @@ DataTransfer::AddElement(nsIDOMElement* return rv.StealNSResult(); } nsresult DataTransfer::Clone(nsISupports* aParent, EventMessage aEventMessage, bool aUserCancelled, bool aIsCrossDomainSubFrameDrop, DataTransfer** aNewDataTransfer) { - RefPtr<DataTransfer> newDataTransfer = + DataTransfer* newDataTransfer = new DataTransfer(aParent, aEventMessage, mEffectAllowed, mCursorState, mIsExternal, aUserCancelled, aIsCrossDomainSubFrameDrop, mClipboardType, mItems, mDragImage, mDragImageX, mDragImageY); - newDataTransfer.forget(aNewDataTransfer); + *aNewDataTransfer = newDataTransfer; + NS_ADDREF(*aNewDataTransfer); return NS_OK; } already_AddRefed<nsISupportsArray> DataTransfer::GetTransferables(nsIDOMNode* aDragTarget) { MOZ_ASSERT(aDragTarget); @@ -927,35 +996,35 @@ DataTransfer::GetTransferables(nsILoadCo { nsCOMPtr<nsISupportsArray> transArray = do_CreateInstance("@mozilla.org/supports-array;1"); if (!transArray) { return nullptr; } - uint32_t count = MozItemCount(); + uint32_t count = mItems.Length(); for (uint32_t i = 0; i < count; i++) { nsCOMPtr<nsITransferable> transferable = GetTransferable(i, aLoadContext); if (transferable) { transArray->AppendElement(transferable); } } return transArray.forget(); } already_AddRefed<nsITransferable> DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext) { - if (aIndex >= MozItemCount()) { + if (aIndex >= mItems.Length()) { return nullptr; } - const nsTArray<RefPtr<DataTransferItem>>& item = *mItems->MozItemsAt(aIndex); + nsTArray<TransferItem>& item = mItems[aIndex]; uint32_t count = item.Length(); if (!count) { return nullptr; } nsCOMPtr<nsITransferable> transferable = do_CreateInstance("@mozilla.org/widget/transferable;1"); if (!transferable) { @@ -997,38 +1066,35 @@ DataTransfer::GetTransferable(uint32_t a * <wide string> format * <32-bit> length of data * <wide string> data * A type of eCustomClipboardTypeId_None ends the list, without any following * data. */ do { for (uint32_t f = 0; f < count; f++) { - RefPtr<DataTransferItem> formatitem = item[f]; - if (!formatitem->Data()) { // skip empty items + const TransferItem& formatitem = item[f]; + if (!formatitem.mData) { // skip empty items continue; } - nsAutoString type; - formatitem->GetType(type); - // If the data is of one of the well-known formats, use it directly. bool isCustomFormat = true; for (uint32_t f = 0; f < ArrayLength(knownFormats); f++) { - if (type.EqualsASCII(knownFormats[f])) { + if (formatitem.mFormat.EqualsASCII(knownFormats[f])) { isCustomFormat = false; break; } } uint32_t lengthInBytes; nsCOMPtr<nsISupports> convertedData; if (handlingCustomFormats) { - if (!ConvertFromVariant(formatitem->Data(), getter_AddRefs(convertedData), + if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &lengthInBytes)) { continue; } // When handling custom types, add the data to the stream if this is a // custom type. if (isCustomFormat) { // If it isn't a string, just ignore it. The dataTransfer is cached in @@ -1045,21 +1111,22 @@ DataTransfer::GetTransferable(uint32_t a nsCOMPtr<nsIOutputStream> outputStream; storageStream->GetOutputStream(0, getter_AddRefs(outputStream)); stream = do_CreateInstance("@mozilla.org/binaryoutputstream;1"); stream->SetOutputStream(outputStream); } - int32_t formatLength = type.Length() * sizeof(nsString::char_type); + int32_t formatLength = + formatitem.mFormat.Length() * sizeof(nsString::char_type); stream->Write32(eCustomClipboardTypeId_String); stream->Write32(formatLength); - stream->WriteBytes((const char *)type.get(), + stream->WriteBytes((const char *)formatitem.mFormat.get(), formatLength); stream->Write32(lengthInBytes); stream->WriteBytes((const char *)data.get(), lengthInBytes); // The total size of the stream is the format length, the data // length, two integers to hold the lengths and one integer for the // string flag. totalCustomLength += @@ -1103,25 +1170,25 @@ DataTransfer::GetTransferable(uint32_t a added = true; // Clear the stream so it doesn't get used again. stream = nullptr; } else { // This is the second pass of the loop and a known type is encountered. // Add it as is. - if (!ConvertFromVariant(formatitem->Data(), getter_AddRefs(convertedData), + if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &lengthInBytes)) { continue; } // The underlying drag code uses text/unicode, so use that instead of // text/plain const char* format; - NS_ConvertUTF16toUTF8 utf8format(type); + NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat); if (utf8format.EqualsLiteral(kTextMime)) { format = kUnicodeMime; } else { format = utf8format.get(); } // If a converter is set for a format, set the converter for the // transferable and don't add the item @@ -1163,17 +1230,17 @@ DataTransfer::ConvertFromVariant(nsIVari *aLength = 0; uint16_t type; aVariant->GetDataType(&type); if (type == nsIDataType::VTYPE_INTERFACE || type == nsIDataType::VTYPE_INTERFACE_IS) { nsCOMPtr<nsISupports> data; if (NS_FAILED(aVariant->GetAsISupports(getter_AddRefs(data)))) { - return false; + return false; } nsCOMPtr<nsIFlavorDataProvider> fdp = do_QueryInterface(data); if (fdp) { // for flavour data providers, use kFlavorHasDataProvider (which has the // value 0) as the length. fdp.forget(aSupports); *aLength = nsITransferable::kFlavorHasDataProvider; @@ -1219,38 +1286,71 @@ DataTransfer::ConvertFromVariant(nsIVari *aLength = str.Length() << 1; return true; } void DataTransfer::ClearAll() { - mItems->ClearAllItems(); -} - -uint32_t -DataTransfer::MozItemCount() const -{ - return mItems->MozItemCount(); + mItems.Clear(); } nsresult DataTransfer::SetDataWithPrincipal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal) { nsAutoString format; GetRealFormat(aFormat, format); - ErrorResult rv; - RefPtr<DataTransferItem> item = - mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal, false, rv); - return rv.StealNSResult(); + // check if the item for the format already exists. In that case, + // just replace it. + TransferItem* formatitem; + if (aIndex < mItems.Length()) { + nsTArray<TransferItem>& item = mItems[aIndex]; + uint32_t count = item.Length(); + for (uint32_t i = 0; i < count; i++) { + TransferItem& itemformat = item[i]; + if (itemformat.mFormat.Equals(format)) { + // don't allow replacing data that has a stronger principal + bool subsumes; + if (itemformat.mPrincipal && aPrincipal && + (NS_FAILED(aPrincipal->Subsumes(itemformat.mPrincipal, + &subsumes)) || !subsumes)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + itemformat.mPrincipal = aPrincipal; + itemformat.mData = aData; + return NS_OK; + } + } + + // add a new format + formatitem = item.AppendElement(); + } + else { + NS_ASSERTION(aIndex == mItems.Length(), "Index out of range"); + + // add a new index + nsTArray<TransferItem>* item = mItems.AppendElement(); + NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY); + + formatitem = item->AppendElement(); + } + + NS_ENSURE_TRUE(formatitem, NS_ERROR_OUT_OF_MEMORY); + + formatitem->mFormat = format; + formatitem->mPrincipal = aPrincipal; + formatitem->mData = aData; + + return NS_OK; } void DataTransfer::SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal) { @@ -1297,22 +1397,16 @@ DataTransfer::CacheExternalData(const ch aPrincipal); return; } SetDataWithPrincipal(NS_ConvertUTF8toUTF16(aFormat), nullptr, aIndex, aPrincipal); } -// there isn't a way to get a list of the formats that might be available on -// all platforms, so just check for the types that can actually be imported -// XXXndeakin there are some other formats but those are platform specific. -const char* kFormats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime, - kUnicodeMime }; - void DataTransfer::CacheExternalDragFormats() { // Called during the constructor to cache the formats available from an // external drag. The data associated with each format will be set to null. // This data will instead only be retrieved in FillInExternalDragData when // asked for, as it may be time consuming for the source application to // generate it. @@ -1344,21 +1438,21 @@ DataTransfer::CacheExternalDragFormats() } for (uint32_t f = 0; f < ArrayLength(formats); f++) { // IsDataFlavorSupported doesn't take an index as an argument and just // checks if any of the items support a particular flavor, even though // the GetData method does take an index. Here, we just assume that // every item being dragged has the same set of flavors. bool supported; - dragSession->IsDataFlavorSupported(kFormats[f], &supported); + dragSession->IsDataFlavorSupported(formats[f], &supported); // if the format is supported, add an item to the array with null as // the data. When retrieved, GetRealData will read the data. if (supported) { - CacheExternalData(kFormats[f], c, sysPrincipal); + CacheExternalData(formats[f], c, sysPrincipal); } } } } void DataTransfer::CacheExternalClipboardFormats() { @@ -1398,44 +1492,127 @@ DataTransfer::CacheExternalClipboardForm } else { CacheExternalData(formats[f], 0, sysPrincipal); } } } } void +DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex) +{ + NS_PRECONDITION(mIsExternal, "Not an external data transfer"); + + if (aItem.mData) { + return; + } + + // only drag and paste events should be calling FillInExternalData + NS_ASSERTION(mEventMessage != eCut && mEventMessage != eCopy, + "clipboard event with empty data"); + + NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat); + const char* format = utf8format.get(); + if (strcmp(format, "text/plain") == 0) { + format = kUnicodeMime; + } else if (strcmp(format, "text/uri-list") == 0) { + format = kURLDataMime; + } + + nsCOMPtr<nsITransferable> trans = + do_CreateInstance("@mozilla.org/widget/transferable;1"); + if (!trans) { + return; + } + + trans->Init(nullptr); + trans->AddDataFlavor(format); + + if (mEventMessage == ePaste) { + MOZ_ASSERT(aIndex == 0, "index in clipboard must be 0"); + + nsCOMPtr<nsIClipboard> clipboard = + do_GetService("@mozilla.org/widget/clipboard;1"); + if (!clipboard || mClipboardType < 0) { + return; + } + + clipboard->GetData(trans, mClipboardType); + } else { + nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); + if (!dragSession) { + return; + } + +#ifdef DEBUG + // Since this is an external drag, the source document will always be null. + nsCOMPtr<nsIDOMDocument> domDoc; + dragSession->GetSourceDocument(getter_AddRefs(domDoc)); + MOZ_ASSERT(!domDoc); +#endif + + dragSession->GetData(trans, aIndex); + } + + uint32_t length = 0; + nsCOMPtr<nsISupports> data; + trans->GetTransferData(format, getter_AddRefs(data), &length); + if (!data) + return; + + RefPtr<nsVariantCC> variant = new nsVariantCC(); + + nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data); + if (supportsstr) { + nsAutoString str; + supportsstr->GetData(str); + variant->SetAsAString(str); + } + else { + nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data); + if (supportscstr) { + nsAutoCString str; + supportscstr->GetData(str); + variant->SetAsACString(str); + } else { + variant->SetAsISupports(data); + } + } + + aItem.mData = variant; +} + +void DataTransfer::FillAllExternalData() { if (mIsExternal) { - for (uint32_t i = 0; i < MozItemCount(); ++i) { - const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(i); - for (uint32_t j = 0; j < items.Length(); ++j) { - MOZ_ASSERT(items[j]->Index() == i); - - items[j]->FillInExternalData(); + for (uint32_t i = 0; i < mItems.Length(); ++i) { + nsTArray<TransferItem>& itemArray = mItems[i]; + for (uint32_t j = 0; j < itemArray.Length(); ++j) { + if (!itemArray[j].mData) { + FillInExternalData(itemArray[j], i); + } } } } } void DataTransfer::FillInExternalCustomTypes(uint32_t aIndex, nsIPrincipal* aPrincipal) { - RefPtr<DataTransferItem> item = new DataTransferItem(mItems, - NS_LITERAL_STRING(kCustomTypesMime)); - item->SetKind(DataTransferItem::KIND_STRING); - item->SetIndex(aIndex); + TransferItem item; + item.mFormat.AssignLiteral(kCustomTypesMime); - if (!item->Data()) { + FillInExternalData(item, aIndex); + if (!item.mData) { return; } - FillInExternalCustomTypes(item->Data(), aIndex, aPrincipal); + FillInExternalCustomTypes(item.mData, aIndex, aPrincipal); } void DataTransfer::FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal) { char* chrs; uint32_t len = 0;
--- a/dom/events/DataTransfer.h +++ b/dom/events/DataTransfer.h @@ -27,27 +27,38 @@ class nsISupportsArray; class nsILoadContext; namespace mozilla { class EventStateManager; namespace dom { -class DataTransferItem; -class DataTransferItemList; class DOMStringList; class Element; class FileList; class Promise; template<typename T> class Optional; +/** + * TransferItem is used to hold data for a particular format. Each piece of + * data has a principal set from the caller which added it. This allows a + * caller that wishes to retrieve the data to only be able to access the data + * it is allowed to, yet still allow a chrome caller to retrieve any of the + * data. + */ +struct TransferItem { + nsString mFormat; + nsCOMPtr<nsIPrincipal> mPrincipal; + nsCOMPtr<nsIVariant> mData; +}; + #define NS_DATATRANSFER_IID \ -{ 0x6c5f90d1, 0xa886, 0x42c8, \ - { 0x85, 0x06, 0x10, 0xbe, 0x5c, 0x0d, 0xc6, 0x77 } } +{ 0x43ee0327, 0xde5d, 0x463d, \ + { 0x9b, 0xd0, 0xf1, 0x79, 0x09, 0x69, 0xf2, 0xfb } } class DataTransfer final : public nsIDOMDataTransfer, public nsWrapperCache { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_DATATRANSFER_IID) NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -72,26 +83,27 @@ protected: DataTransfer(nsISupports* aParent, EventMessage aEventMessage, const uint32_t aEffectAllowed, bool aCursorState, bool aIsExternal, bool aUserCancelled, bool aIsCrossDomainSubFrameDrop, int32_t aClipboardType, - DataTransferItemList* aItems, + nsTArray<nsTArray<TransferItem> >& aItems, Element* aDragImage, uint32_t aDragImageX, uint32_t aDragImageY); ~DataTransfer(); static const char sEffects[8][9]; public: + // Constructor for DataTransfer. // // aIsExternal must only be true when used to create a dataTransfer for a // paste or a drag that was started without using a data transfer. The // latter will occur when an external drag occurs, that is, a drag where the // source is another application, or a drag is started by calling the drag // service directly. For clipboard operations, aClipboardType indicates // which clipboard to use, from nsIClipboard, or -1 for non-clipboard @@ -132,33 +144,36 @@ public: } else { aEffectAllowed.AssignASCII(sEffects[mEffectAllowed]); } } void SetDragImage(Element& aElement, int32_t aX, int32_t aY, ErrorResult& aRv); - already_AddRefed<DOMStringList> GetTypes(ErrorResult& rv) const; + already_AddRefed<DOMStringList> Types() const; void GetData(const nsAString& aFormat, nsAString& aData, ErrorResult& aRv); void SetData(const nsAString& aFormat, const nsAString& aData, ErrorResult& aRv); void ClearData(const mozilla::dom::Optional<nsAString>& aFormat, mozilla::ErrorResult& aRv); FileList* GetFiles(mozilla::ErrorResult& aRv); already_AddRefed<Promise> GetFilesAndDirectories(ErrorResult& aRv); void AddElement(Element& aElement, mozilla::ErrorResult& aRv); - uint32_t MozItemCount() const; + uint32_t MozItemCount() const + { + return mItems.Length(); + } void GetMozCursor(nsString& aCursor) { if (mCursorState) { aCursor.AssignLiteral("default"); } else { aCursor.AssignLiteral("auto"); } @@ -190,24 +205,18 @@ public: return mDragTarget; } nsresult GetDataAtNoSecurityCheck(const nsAString& aFormat, uint32_t aIndex, nsIVariant** aData); // a readonly dataTransfer cannot have new data added or existing data // removed. Only the dropEffect and effectAllowed may be modified. - DataTransferItemList* Items() const { return mItems; } - - bool IsReadOnly() const { return mReadOnly; } void SetReadOnly() { mReadOnly = true; } - int32_t ClipboardType() const { return mClipboardType; } - EventMessage GetEventMessage() const { return mEventMessage; } - // converts the data into an array of nsITransferable objects to be used for // drag and drop or clipboard operations. already_AddRefed<nsISupportsArray> GetTransferables(nsIDOMNode* aDragTarget); already_AddRefed<nsISupportsArray> GetTransferables(nsILoadContext* aLoadContext); // converts the data for a single item at aIndex into an nsITransferable @@ -246,35 +255,42 @@ public: *aY = mDragImageY; return mDragImage; } nsresult Clone(nsISupports* aParent, EventMessage aEventMessage, bool aUserCancelled, bool aIsCrossDomainSubFrameDrop, DataTransfer** aResult); +protected: + // converts some formats used for compatibility in aInFormat into aOutFormat. // Text and text/unicode become text/plain, and URL becomes text/uri-list void GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat) const; -protected: - // caches text and uri-list data formats that exist in the drag service or // clipboard for retrieval later. void CacheExternalData(const char* aFormat, uint32_t aIndex, nsIPrincipal* aPrincipal); // caches the formats that exist in the drag service that were added by an // external drag void CacheExternalDragFormats(); // caches the formats that exist in the clipboard void CacheExternalClipboardFormats(); - FileList* GetFilesInternal(ErrorResult& aRv, nsIPrincipal* aSubjectPrincipal); + // fills in the data field of aItem with the data from the drag service or + // clipboard for a given index. + void FillInExternalData(TransferItem& aItem, uint32_t aIndex); + + + FileList* GetFileListInternal(ErrorResult& aRv, + nsIPrincipal* aSubjectPrincipal); + nsresult GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex, nsIPrincipal* aSubjectPrincipal, nsIVariant** aData); nsresult SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aSubjectPrincipal); friend class ContentParent; @@ -316,18 +332,22 @@ protected: // true if this is a cross-domain drop from a subframe where access to the // data should be prevented bool mIsCrossDomainSubFrameDrop; // Indicates which clipboard type to use for clipboard operations. Ignored for // drag and drop. int32_t mClipboardType; - // The items contained with the DataTransfer - RefPtr<DataTransferItemList> mItems; + // array of items, each containing an array of format->data pairs + nsTArray<nsTArray<TransferItem> > mItems; + + // array of files and directories, containing only the files present in the + // dataTransfer + RefPtr<FileList> mFileList; // the target of the drag. The drag and dragend events will fire at this. nsCOMPtr<mozilla::dom::Element> mDragTarget; // the custom drag image and coordinates within the image. If mDragImage is // null, the default image is created from the drag target. nsCOMPtr<mozilla::dom::Element> mDragImage; uint32_t mDragImageX;
deleted file mode 100644 --- a/dom/events/DataTransferItem.cpp +++ /dev/null @@ -1,365 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "DataTransferItem.h" -#include "DataTransferItemList.h" - -#include "mozilla/ContentEvents.h" -#include "mozilla/EventForwards.h" -#include "mozilla/dom/DataTransferItemBinding.h" -#include "nsIClipboard.h" -#include "nsISupportsPrimitives.h" -#include "nsNetUtil.h" -#include "nsQueryObject.h" -#include "nsContentUtils.h" -#include "nsVariant.h" - -namespace { - -struct FileMimeNameData -{ - const char* mMimeName; - const char* mFileName; -}; - -FileMimeNameData kFileMimeNameMap[] = { - { kFileMime, "GenericFileName" }, -}; - -already_AddRefed<mozilla::dom::File> -FileFromISupports(nsISupports* aSupports) -{ - MOZ_ASSERT(aSupports); - - nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(aSupports); - if (domBlob) { - // Get out the blob - this is OK, because nsIDOMBlob is a builtinclass - // and the only implementer is Blob. - mozilla::dom::Blob* blob = static_cast<mozilla::dom::Blob*>(domBlob.get()); - return blob->ToFile(); - } - - return nullptr; -} - -} // anonymous namespace - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DataTransferItem, mData, - mPrincipal, mParent) -NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransferItem) -NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransferItem) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransferItem) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -JSObject* -DataTransferItem::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return DataTransferItemBinding::Wrap(aCx, this, aGivenProto); -} - -already_AddRefed<DataTransferItem> -DataTransferItem::Clone(DataTransferItemList* aParent) const -{ - MOZ_ASSERT(aParent); - - RefPtr<DataTransferItem> it = new DataTransferItem(aParent, mType); - - // Copy over all of the fields - it->mKind = mKind; - it->mIndex = mIndex; - it->mData = mData; - it->mPrincipal = mPrincipal; - - return it.forget(); -} - -void -DataTransferItem::SetType(const nsAString& aType) -{ - mType = aType; -} - -void -DataTransferItem::SetData(nsIVariant* aData) -{ - if (!aData) { - // We are holding a temporary null which will later be filled. - // These are provided by the system, and have guaranteed properties about - // their kind based on their type. - MOZ_ASSERT(!mType.IsEmpty()); - - mKind = KIND_STRING; - for (uint32_t i = 0; i < ArrayLength(kFileMimeNameMap); ++i) { - if (mType.EqualsASCII(kFileMimeNameMap[i].mMimeName)) { - mKind = KIND_FILE; - break; - } - } - - mData = nullptr; - return; - } - - mKind = KIND_OTHER; - mData = aData; - - nsCOMPtr<nsISupports> supports; - nsresult rv = aData->GetAsISupports(getter_AddRefs(supports)); - if (NS_SUCCEEDED(rv) && supports) { - RefPtr<File> file = FileFromISupports(supports); - if (file) { - mKind = KIND_FILE; - return; - } - } - - nsAutoString string; - // If we can't get the data type as a string, that means that the object - // should be considered to be of the "other" type. This is impossible - // through the APIs defined by the spec, but we provide extra Moz* APIs, - // which allow setting of non-string data. We determine whether we can - // consider it a string, by calling GetAsAString, and checking for success. - rv = aData->GetAsAString(string); - if (NS_SUCCEEDED(rv)) { - mKind = KIND_STRING; - } -} - -void -DataTransferItem::FillInExternalData() -{ - if (mData) { - return; - } - - NS_ConvertUTF16toUTF8 utf8format(mType); - const char* format = utf8format.get(); - if (strcmp(format, "text/plain") == 0) { - format = kUnicodeMime; - } else if (strcmp(format, "text/uri-list") == 0) { - format = kURLDataMime; - } - - nsCOMPtr<nsITransferable> trans = - do_CreateInstance("@mozilla.org/widget/transferable;1"); - if (NS_WARN_IF(!trans)) { - return; - } - - trans->Init(nullptr); - trans->AddDataFlavor(format); - - if (mParent->GetEventMessage() == ePaste) { - MOZ_ASSERT(mIndex == 0, "index in clipboard must be 0"); - - nsCOMPtr<nsIClipboard> clipboard = - do_GetService("@mozilla.org/widget/clipboard;1"); - if (!clipboard || mParent->ClipboardType() < 0) { - return; - } - - nsresult rv = clipboard->GetData(trans, mParent->ClipboardType()); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - } else { - nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); - if (!dragSession) { - return; - } - - nsresult rv = dragSession->GetData(trans, mIndex); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - } - - uint32_t length = 0; - nsCOMPtr<nsISupports> data; - nsresult rv = trans->GetTransferData(format, getter_AddRefs(data), &length); - if (NS_WARN_IF(NS_FAILED(rv) || !data)) { - return; - } - - if (Kind() == KIND_FILE) { - // Because this is an external piece of data, mType is kFileMime. We want to - // convert whatever type happens to actually be stored into a dom::File. - - RefPtr<File> file = FileFromISupports(data); - if (!file) { - if (nsCOMPtr<nsIFile> ifile = do_QueryInterface(data)) { - file = File::CreateFromFile(GetParentObject(), ifile); - } else if (nsCOMPtr<nsIInputStream> stream = do_QueryInterface(data)) { - // This consumes the stream object - ErrorResult rv; - file = CreateFileFromInputStream(GetParentObject(), stream, rv); - if (NS_WARN_IF(rv.Failed())) { - rv.SuppressException(); - } - } else if (nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(data)) { - MOZ_ASSERT(blobImpl->IsFile()); - file = File::Create(GetParentObject(), blobImpl); - } - } - - MOZ_ASSERT(file, "Invalid format for Kind() == KIND_FILE"); - - data = do_QueryObject(file); - } - - RefPtr<nsVariantCC> variant = new nsVariantCC(); - - nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data); - if (supportsstr) { - MOZ_ASSERT(Kind() == KIND_STRING); - nsAutoString str; - supportsstr->GetData(str); - variant->SetAsAString(str); - } else { - nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data); - if (supportscstr) { - MOZ_ASSERT(Kind() == KIND_STRING); - nsAutoCString str; - supportscstr->GetData(str); - variant->SetAsACString(str); - } else { - MOZ_ASSERT(Kind() == KIND_FILE); - variant->SetAsISupports(data); - } - } - - SetData(variant); -} - -already_AddRefed<File> -DataTransferItem::GetAsFile(ErrorResult& aRv) -{ - if (mKind != KIND_FILE) { - return nullptr; - } - - nsIVariant* data = Data(); - if (NS_WARN_IF(!data)) { - return nullptr; - } - - nsCOMPtr<nsISupports> supports; - aRv = data->GetAsISupports(getter_AddRefs(supports)); - MOZ_ASSERT(!aRv.Failed() && supports, - "Files should be stored with type dom::File!"); - if (aRv.Failed() || !supports) { - return nullptr; - } - - RefPtr<File> file = FileFromISupports(supports); - MOZ_ASSERT(file, "Files should be stored with type dom::File!"); - if (!file) { - return nullptr; - } - - // The File object should have been stored as a File in the nsIVariant. If it - // was stored as a Blob, with a file BlobImpl, we could still get to this - // point, except that file is a new File object, with a different identity - // then the original blob ibject. This should never happen so we assert - // against it. - MOZ_ASSERT(SameCOMIdentity(supports, NS_ISUPPORTS_CAST(nsIDOMBlob*, file)), - "Got back a new File object from FileFromISupports in GetAsFile!"); - - return file.forget(); -} - -already_AddRefed<File> -DataTransferItem::CreateFileFromInputStream(nsISupports* aParent, - nsIInputStream* aStream, - ErrorResult& aRv) -{ - const char* key = nullptr; - for (uint32_t i = 0; i < ArrayLength(kFileMimeNameMap); ++i) { - if (mType.EqualsASCII(kFileMimeNameMap[i].mMimeName)) { - key = kFileMimeNameMap[i].mFileName; - break; - } - } - if (!key) { - MOZ_ASSERT_UNREACHABLE("Unsupported mime type"); - key = "GenericFileName"; - } - - nsXPIDLString fileName; - aRv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, - key, fileName); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - uint64_t available; - aRv = aStream->Available(&available); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - void* data = nullptr; - aRv = NS_ReadInputStreamToBuffer(aStream, &data, available); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - return File::CreateMemoryFile(aParent, data, available, fileName, - mType, PR_Now()); -} - -void -DataTransferItem::GetAsString(const RefPtr<FunctionStringCallback>& aCallback, - ErrorResult& aRv) -{ - if (!aCallback || mKind != KIND_STRING) { - return; - } - - nsIVariant* data = Data(); - if (NS_WARN_IF(!data)) { - return; - } - - nsAutoString stringData; - data->GetAsAString(stringData); - - // Dispatch the callback to the main thread - class GASRunnable final : public Runnable - { - public: - GASRunnable(const RefPtr<FunctionStringCallback>& aCallback, - const nsAString& aStringData) - : mCallback(aCallback), mStringData(aStringData) - {} - - NS_IMETHOD Run() override - { - ErrorResult rv; - mCallback->Call(mStringData, rv); - NS_WARN_IF(rv.Failed()); - return rv.StealNSResult(); - } - private: - RefPtr<FunctionStringCallback> mCallback; - nsString mStringData; - }; - - RefPtr<GASRunnable> runnable = new GASRunnable(aCallback, stringData); - nsresult rv = NS_DispatchToMainThread(runnable); - if (NS_FAILED(rv)) { - NS_WARNING("NS_DispatchToMainThread Failed in " - "DataTransferItem::GetAsString!"); - } -} - -} // namespace dom -} // namespace mozilla
deleted file mode 100644 --- a/dom/events/DataTransferItem.h +++ /dev/null @@ -1,130 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_DataTransferItem_h -#define mozilla_dom_DataTransferItem_h - -#include "mozilla/ErrorResult.h" -#include "mozilla/dom/DataTransfer.h" -#include "mozilla/dom/DOMString.h" -#include "mozilla/dom/File.h" - -namespace mozilla { -namespace dom { - -class FunctionStringCallback; - -class DataTransferItem final : public nsISupports - , public nsWrapperCache -{ -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DataTransferItem); - -public: - // The spec only talks about the "file" and "string" kinds. Due to the Moz* - // APIs, it is possible to attach any type to a DataTransferItem, meaning that - // we can have other kinds then just FILE and STRING. These others are simply - // marked as "other" and can only be produced throug the Moz* APIs. - enum eKind { - KIND_FILE, - KIND_STRING, - KIND_OTHER, - }; - - DataTransferItem(DataTransferItemList* aParent, const nsAString& aType) - : mIndex(0), mKind(KIND_OTHER), mType(aType), mParent(aParent) - {} - - already_AddRefed<DataTransferItem> Clone(DataTransferItemList* aParent) const; - - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - void GetAsString(const RefPtr<FunctionStringCallback>& aCallback, - ErrorResult& aRv); - void GetKind(nsAString& aKind) const - { - switch (mKind) { - case KIND_FILE: - aKind = NS_LITERAL_STRING("file"); - return; - case KIND_STRING: - aKind = NS_LITERAL_STRING("string"); - return; - default: - aKind = NS_LITERAL_STRING("other"); - return; - } - } - - void GetType(nsAString& aType) const - { - aType = mType; - } - void SetType(const nsAString& aType); - - eKind Kind() const - { - return mKind; - } - void SetKind(eKind aKind) - { - mKind = aKind; - } - - already_AddRefed<File> GetAsFile(ErrorResult& aRv); - - DataTransferItemList* GetParentObject() const - { - return mParent; - } - - nsIPrincipal* Principal() const - { - return mPrincipal; - } - void SetPrincipal(nsIPrincipal* aPrincipal) - { - mPrincipal = aPrincipal; - } - - nsIVariant* Data() - { - if (!mData) { - FillInExternalData(); - } - return mData; - } - void SetData(nsIVariant* aData); - - uint32_t Index() const - { - return mIndex; - } - void SetIndex(uint32_t aIndex) - { - mIndex = aIndex; - } - void FillInExternalData(); - -private: - ~DataTransferItem() {} - already_AddRefed<File> CreateFileFromInputStream(nsISupports* aParent, - nsIInputStream* aStream, - ErrorResult& aRv); - - // The index in the 2d mIndexedItems array - uint32_t mIndex; - - eKind mKind; - nsString mType; - nsCOMPtr<nsIVariant> mData; - nsCOMPtr<nsIPrincipal> mPrincipal; - RefPtr<DataTransferItemList> mParent; -}; - -} // namespace dom -} // namespace mozilla - -#endif /* mozilla_dom_DataTransferItem_h */
deleted file mode 100644 --- a/dom/events/DataTransferItemList.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "DataTransferItemList.h" - -#include "nsContentUtils.h" -#include "nsIGlobalObject.h" -#include "nsIClipboard.h" -#include "nsIScriptObjectPrincipal.h" -#include "nsIScriptGlobalObject.h" -#include "nsIScriptContext.h" -#include "nsISupportsPrimitives.h" -#include "nsQueryObject.h" -#include "nsVariant.h" -#include "mozilla/ContentEvents.h" -#include "mozilla/EventForwards.h" -#include "mozilla/storage/Variant.h" -#include "mozilla/dom/DataTransferItemListBinding.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DataTransferItemList, mParent, mItems, - mIndexedItems, mFiles) -NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransferItemList) -NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransferItemList) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransferItemList) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -JSObject* -DataTransferItemList::WrapObject(JSContext* aCx, - JS::Handle<JSObject*> aGivenProto) -{ - return DataTransferItemListBinding::Wrap(aCx, this, aGivenProto); -} - -already_AddRefed<DataTransferItemList> -DataTransferItemList::Clone(DataTransfer* aParent) const -{ - RefPtr<DataTransferItemList> list = - new DataTransferItemList(aParent, mIsExternal, mIsCrossDomainSubFrameDrop); - - // We need to clone the mItems and mIndexedItems lists while keeping the same - // correspondences between the mIndexedItems and mItems lists (namely, if an - // item is in mIndexedItems, and mItems it must have the same new identity) - - // First, we copy over indexedItems, and clone every entry. Then, we go over - // mItems. For every entry, we use its mIndex property to locate it in - // mIndexedItems on the original DataTransferItemList, and then copy over the - // reference from the same index pair on the new DataTransferItemList - - list->mIndexedItems.SetLength(mIndexedItems.Length()); - list->mItems.SetLength(mItems.Length()); - - // Copy over mIndexedItems, cloning every entry - for (uint32_t i = 0; i < mIndexedItems.Length(); i++) { - const nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i]; - nsTArray<RefPtr<DataTransferItem>>& newItems = list->mIndexedItems[i]; - newItems.SetLength(items.Length()); - for (uint32_t j = 0; j < items.Length(); j++) { - newItems[j] = items[j]->Clone(list); - } - } - - // Copy over mItems, getting the actual entries from mIndexedItems - for (uint32_t i = 0; i < mItems.Length(); i++) { - uint32_t index = mItems[i]->Index(); - MOZ_ASSERT(index < mIndexedItems.Length()); - uint32_t subIndex = mIndexedItems[index].IndexOf(mItems[i]); - - // Copy over the reference - list->mItems[i] = list->mIndexedItems[index][subIndex]; - } - - return list.forget(); -} - -void -DataTransferItemList::Remove(uint32_t aIndex, ErrorResult& aRv) -{ - if (IsReadOnly()) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return; - } - - if (aIndex >= Length()) { - aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); - return; - } - - ClearDataHelper(mItems[aIndex], aIndex, -1, aRv); -} - -DataTransferItem* -DataTransferItemList::IndexedGetter(uint32_t aIndex, bool& aFound, ErrorResult& aRv) const -{ - if (aIndex >= mItems.Length()) { - aFound = false; - return nullptr; - } - - RefPtr<DataTransferItem> item = mItems[aIndex]; - - // Check if the caller is allowed to access the drag data. Callers with - // chrome privileges can always read the data. During the - // drop event, allow retrieving the data except in the case where the - // source of the drag is in a child frame of the caller. In that case, - // we only allow access to data of the same principal. During other events, - // only allow access to the data with the same principal. - nsIPrincipal* principal = nullptr; - if (mIsCrossDomainSubFrameDrop) { - principal = nsContentUtils::SubjectPrincipal(); - } - - if (item->Principal() && principal && - !principal->Subsumes(item->Principal())) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - aFound = false; - return nullptr; - } - - nsCOMPtr<nsIVariant> variantData = item->Data(); - nsCOMPtr<nsISupports> data; - if (variantData && - NS_SUCCEEDED(variantData->GetAsISupports(getter_AddRefs(data))) && - data) { - // Make sure the code that is calling us is same-origin with the data. - nsCOMPtr<EventTarget> pt = do_QueryInterface(data); - if (pt) { - nsresult rv = NS_OK; - nsIScriptContext* c = pt->GetContextForEventHandlers(&rv); - if (NS_WARN_IF(NS_FAILED(rv) || !c)) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } - - nsIGlobalObject* go = c->GetGlobalObject(); - if (NS_WARN_IF(!go)) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } - - nsCOMPtr<nsIScriptObjectPrincipal> sp = do_QueryInterface(go); - MOZ_ASSERT(sp, "This cannot fail on the main thread."); - - nsIPrincipal* dataPrincipal = sp->GetPrincipal(); - if (!principal) { - principal = nsContentUtils::SubjectPrincipal(); - } - if (NS_WARN_IF(!dataPrincipal || !principal->Equals(dataPrincipal))) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } - } - } - - aFound = true; - return item; -} - -uint32_t -DataTransferItemList::MozItemCount() const -{ - uint32_t length = mIndexedItems.Length(); - // XXX: Compat hack - Index 0 always exists due to changes in internals, but - // if it is empty, scripts using the moz* APIs should see it as not existing. - if (length == 1 && mIndexedItems[0].IsEmpty()) { - return 0; - } - return length; -} - -void -DataTransferItemList::Clear(ErrorResult& aRv) -{ - if (NS_WARN_IF(IsReadOnly())) { - return; - } - - uint32_t count = Length(); - for (uint32_t i = 0; i < count; i++) { - // We always remove the last item first, to avoid moving items around in - // memory as much - Remove(Length() - 1, aRv); - ENSURE_SUCCESS_VOID(aRv); - } - - MOZ_ASSERT(Length() == 0); -} - -DataTransferItem* -DataTransferItemList::Add(const nsAString& aData, - const nsAString& aType, - ErrorResult& aRv) -{ - if (NS_WARN_IF(IsReadOnly())) { - return nullptr; - } - - nsCOMPtr<nsIVariant> data(new storage::TextVariant(aData)); - - nsAutoString format; - mParent->GetRealFormat(aType, format); - - // We add the textual data to index 0. We set aInsertOnly to true, as we don't - // want to update an existing entry if it is already present, as per the spec. - RefPtr<DataTransferItem> item = - SetDataWithPrincipal(format, data, 0, - nsContentUtils::SubjectPrincipal(), - true, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - MOZ_ASSERT(item->Kind() != DataTransferItem::KIND_FILE); - - return item; -} - -DataTransferItem* -DataTransferItemList::Add(File& aData, ErrorResult& aRv) -{ - if (IsReadOnly()) { - return nullptr; - } - - nsCOMPtr<nsISupports> supports = do_QueryObject(&aData); - nsCOMPtr<nsIWritableVariant> data = new nsVariant(); - data->SetAsISupports(supports); - - nsAutoString type; - aData.GetType(type); - - - // We need to add this as a new item, as multiple files can't exist in the - // same item in the Moz DataTransfer layout. It will be appended at the end of - // the internal specced layout. - uint32_t index = mIndexedItems.Length(); - RefPtr<DataTransferItem> item = - SetDataWithPrincipal(type, data, index, - nsContentUtils::SubjectPrincipal(), - true, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - MOZ_ASSERT(item->Kind() == DataTransferItem::KIND_FILE); - - return item; -} - -FileList* -DataTransferItemList::Files() -{ - if (!mFiles) { - mFiles = new FileList(static_cast<nsIDOMDataTransfer*>(mParent)); - RegenerateFiles(); - } - - return mFiles; -} - -void -DataTransferItemList::MozRemoveByTypeAt(const nsAString& aType, - uint32_t aIndex, - ErrorResult& aRv) -{ - if (NS_WARN_IF(IsReadOnly() || - aIndex >= mIndexedItems.Length())) { - return; - } - - bool removeAll = aType.IsEmpty(); - - nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aIndex]; - uint32_t count = items.Length(); - // We remove the last item of the list repeatedly - that way we don't - // have to worry about modifying the loop iterator - if (removeAll) { - for (uint32_t i = 0; i < count; ++i) { - uint32_t index = items.Length() - 1; - MOZ_ASSERT(index == count - i - 1); - - ClearDataHelper(items[index], -1, index, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - } - - // items is no longer a valid reference, as removing the last element from - // it via ClearDataHelper invalidated it. so we can't MOZ_ASSERT that the - // length is now 0. - return; - } - - for (uint32_t i = 0; i < count; ++i) { - nsAutoString type; - items[i]->GetType(type); - if (type == aType) { - ClearDataHelper(items[i], -1, i, aRv); - return; - } - } -} - -DataTransferItem* -DataTransferItemList::MozItemByTypeAt(const nsAString& aType, uint32_t aIndex) -{ - if (NS_WARN_IF(aIndex >= mIndexedItems.Length())) { - return nullptr; - } - - uint32_t count = mIndexedItems[aIndex].Length(); - for (uint32_t i = 0; i < count; i++) { - RefPtr<DataTransferItem> item = mIndexedItems[aIndex][i]; - nsString type; - item->GetType(type); - if (type.Equals(aType)) { - return item; - } - } - - return nullptr; -} - -already_AddRefed<DataTransferItem> -DataTransferItemList::SetDataWithPrincipal(const nsAString& aType, - nsIVariant* aData, - uint32_t aIndex, - nsIPrincipal* aPrincipal, - bool aInsertOnly, - ErrorResult& aRv) -{ - if (aIndex < mIndexedItems.Length()) { - nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aIndex]; - uint32_t count = items.Length(); - for (uint32_t i = 0; i < count; i++) { - RefPtr<DataTransferItem> item = items[i]; - nsString type; - item->GetType(type); - if (type.Equals(aType)) { - if (NS_WARN_IF(aInsertOnly)) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } - - // don't allow replacing data that has a stronger principal - bool subsumes; - if (NS_WARN_IF(item->Principal() && aPrincipal && - (NS_FAILED(aPrincipal->Subsumes(item->Principal(), - &subsumes)) - || !subsumes))) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return nullptr; - } - item->SetPrincipal(aPrincipal); - - DataTransferItem::eKind oldKind = item->Kind(); - item->SetData(aData); - - if (aIndex != 0) { - // If the item changes from being a file to not a file or vice-versa, - // its presence in the mItems array may need to change. - if (item->Kind() == DataTransferItem::KIND_FILE && - oldKind != DataTransferItem::KIND_FILE) { - // not file => file - mItems.AppendElement(item); - } else if (item->Kind() != DataTransferItem::KIND_FILE && - oldKind == DataTransferItem::KIND_FILE) { - // file => not file - mItems.RemoveElement(item); - } - } - - // Regenerate the Files array if we have modified a file's status - if (item->Kind() == DataTransferItem::KIND_FILE || - oldKind == DataTransferItem::KIND_FILE) { - RegenerateFiles(); - } - - return item.forget(); - } - } - } else { - // Make sure that we aren't adding past the end of the mIndexedItems array. - // XXX Should this be a MOZ_ASSERT instead? - aIndex = mIndexedItems.Length(); - } - - // Add the new item - RefPtr<DataTransferItem> item = AppendNewItem(aIndex, aType, aData, aPrincipal); - - if (item->Kind() == DataTransferItem::KIND_FILE) { - RegenerateFiles(); - } - - return item.forget(); -} - -DataTransferItem* -DataTransferItemList::AppendNewItem(uint32_t aIndex, - const nsAString& aType, - nsIVariant* aData, - nsIPrincipal* aPrincipal) -{ - if (mIndexedItems.Length() <= aIndex) { - MOZ_ASSERT(mIndexedItems.Length() == aIndex); - mIndexedItems.AppendElement(); - } - RefPtr<DataTransferItem> item = new DataTransferItem(this, aType); - item->SetIndex(aIndex); - item->SetPrincipal(aPrincipal); - item->SetData(aData); - - mIndexedItems[aIndex].AppendElement(item); - - // We only want to add the item to the main mItems list if the index we are - // adding to is 0, or the item we are adding is a file. If we add an item - // which is not a file to a non-zero index, invariants could be broken. - // (namely the invariant that there are not 2 non-file entries in the items - // array with the same type) - if (item->Kind() == DataTransferItem::KIND_FILE || aIndex == 0) { - mItems.AppendElement(item); - } - - return item; -} - -const nsTArray<RefPtr<DataTransferItem>>* -DataTransferItemList::MozItemsAt(uint32_t aIndex) // -- INDEXED -{ - if (aIndex >= mIndexedItems.Length()) { - return nullptr; - } - - return &mIndexedItems[aIndex]; -} - -bool -DataTransferItemList::IsReadOnly() const -{ - MOZ_ASSERT(mParent); - return mParent->IsReadOnly(); -} - -int32_t -DataTransferItemList::ClipboardType() const -{ - MOZ_ASSERT(mParent); - return mParent->ClipboardType(); -} - -EventMessage -DataTransferItemList::GetEventMessage() const -{ - MOZ_ASSERT(mParent); - return mParent->GetEventMessage(); -} - -void -DataTransferItemList::PopIndexZero() -{ - MOZ_ASSERT(mIndexedItems.Length() > 1); - MOZ_ASSERT(mIndexedItems[0].IsEmpty()); - - mIndexedItems.RemoveElementAt(0); - - // Update the index of every element which has now been shifted - for (uint32_t i = 0; i < mIndexedItems.Length(); i++) { - nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i]; - for (uint32_t j = 0; j < items.Length(); j++) { - items[j]->SetIndex(i); - } - } -} - -void -DataTransferItemList::ClearAllItems() -{ - // We always need to have index 0, so don't delete that one - mItems.Clear(); - mIndexedItems.Clear(); - mIndexedItems.SetLength(1); - - // Re-generate files (into an empty list) - RegenerateFiles(); -} - -void -DataTransferItemList::ClearDataHelper(DataTransferItem* aItem, - uint32_t aIndexHint, - uint32_t aMozOffsetHint, - ErrorResult& aRv) -{ - MOZ_ASSERT(aItem); - if (NS_WARN_IF(IsReadOnly())) { - return; - } - - nsIPrincipal* principal = nsContentUtils::SubjectPrincipal(); - if (aItem->Principal() && principal && - !principal->Subsumes(aItem->Principal())) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return; - } - - // Check if the aIndexHint is actually the index, and then remove the item - // from aItems - ErrorResult rv; - bool found; - if (IndexedGetter(aIndexHint, found, rv) == aItem) { - mItems.RemoveElementAt(aIndexHint); - } else { - mItems.RemoveElement(aItem); - } - rv.SuppressException(); - - // Check if the aMozIndexHint and aMozOffsetHint are actually the index and - // offset, and then remove them from mIndexedItems - MOZ_ASSERT(aItem->Index() < mIndexedItems.Length()); - nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aItem->Index()]; - if (aMozOffsetHint < items.Length() && aItem == items[aMozOffsetHint]) { - items.RemoveElementAt(aMozOffsetHint); - } else { - items.RemoveElement(aItem); - } - - // Check if we should remove the index. We never remove index 0. - if (items.Length() == 0 && aItem->Index() != 0) { - mIndexedItems.RemoveElementAt(aItem->Index()); - - // Update the index of every element which has now been shifted - for (uint32_t i = aItem->Index(); i < mIndexedItems.Length(); i++) { - nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i]; - for (uint32_t j = 0; j < items.Length(); j++) { - items[j]->SetIndex(i); - } - } - } - - // Give the removed item the invalid index - aItem->SetIndex(-1); - - if (aItem->Kind() == DataTransferItem::KIND_FILE) { - RegenerateFiles(); - } -} - -void -DataTransferItemList::RegenerateFiles() -{ - // We don't want to regenerate the files list unless we already have a files - // list. That way we can avoid the unnecessary work if the user never touches - // the files list. - if (mFiles) { - // We clear the list rather than performing smaller updates, because it - // simplifies the logic greatly on this code path, which should be very - // infrequently used. - mFiles->Clear(); - - uint32_t count = Length(); - for (uint32_t i = 0; i < count; i++) { - ErrorResult rv; - bool found; - RefPtr<DataTransferItem> item = IndexedGetter(i, found, rv); - if (NS_WARN_IF(!found || rv.Failed())) { - continue; - } - - if (item->Kind() == DataTransferItem::KIND_FILE) { - RefPtr<File> file = item->GetAsFile(rv); - if (NS_WARN_IF(rv.Failed() || !file)) { - continue; - } - mFiles->Append(file); - } - } - } -} - -} // namespace mozilla -} // namespace dom
deleted file mode 100644 --- a/dom/events/DataTransferItemList.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_DataTransferItemList_h -#define mozilla_dom_DataTransferItemList_h - -#include "mozilla/dom/DataTransfer.h" -#include "mozilla/dom/DataTransferItem.h" -#include "mozilla/dom/FileList.h" - -namespace mozilla { -namespace dom { - -class DataTransferItem; - -class DataTransferItemList final : public nsISupports - , public nsWrapperCache -{ -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DataTransferItemList); - - DataTransferItemList(DataTransfer* aParent, bool aIsExternal, - bool aIsCrossDomainSubFrameDrop) - : mParent(aParent) - , mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop) - , mIsExternal(aIsExternal) - { - // We always allocate an index 0 in our DataTransferItemList. This is done - // in order to maintain the invariants according to the spec. Mainly, within - // the spec's list, there is intended to be a single copy of each mime type, - // for string typed items. File typed items are allowed to have duplicates. - // In the old moz* system, this was modeled by having multiple indexes, each - // of which was independent. Files were fetched from all indexes, but - // strings were only fetched from the first index. In order to maintain this - // correlation and avoid breaking code with the new changes, index 0 is now - // always present and used to store strings, and all file items are given - // their own index starting at index 1. - mIndexedItems.SetLength(1); - } - - already_AddRefed<DataTransferItemList> Clone(DataTransfer* aParent) const; - - virtual JSObject* WrapObject(JSContext* aCx, - JS::Handle<JSObject*> aGivenProto) override; - - uint32_t Length() const - { - return mItems.Length(); - }; - - DataTransferItem* Add(const nsAString& aData, const nsAString& aType, - ErrorResult& rv); - DataTransferItem* Add(File& aData, ErrorResult& aRv); - - void Remove(uint32_t aIndex, ErrorResult& aRv); - - DataTransferItem* IndexedGetter(uint32_t aIndex, bool& aFound, - ErrorResult& aRv) const; - - void Clear(ErrorResult& aRv); - - DataTransfer* GetParentObject() const - { - return mParent; - } - - // Accessors for data from ParentObject - bool IsReadOnly() const; - int32_t ClipboardType() const; - EventMessage GetEventMessage() const; - - already_AddRefed<DataTransferItem> - SetDataWithPrincipal(const nsAString& aType, nsIVariant* aData, - uint32_t aIndex, nsIPrincipal* aPrincipal, - bool aInsertOnly, ErrorResult& aRv); - - FileList* Files(); - - // Moz-style helper methods for interacting with the stored data - void MozRemoveByTypeAt(const nsAString& aType, uint32_t aIndex, - ErrorResult& aRv); - DataTransferItem* MozItemByTypeAt(const nsAString& aType, uint32_t aIndex); - const nsTArray<RefPtr<DataTransferItem>>* MozItemsAt(uint32_t aIndex); - uint32_t MozItemCount() const; - - // Causes everything in indexes above 0 to shift down one index. - void PopIndexZero(); - - // Delete every item in the DataTransferItemList, without checking for - // permissions or read-only status (for internal use only). - void ClearAllItems(); - -private: - void ClearDataHelper(DataTransferItem* aItem, uint32_t aIndexHint, - uint32_t aMozOffsetHint, ErrorResult& aRv); - DataTransferItem* AppendNewItem(uint32_t aIndex, const nsAString& aType, - nsIVariant* aData, nsIPrincipal* aPrincipal); - void RegenerateFiles(); - - ~DataTransferItemList() {} - - RefPtr<DataTransfer> mParent; - bool mIsCrossDomainSubFrameDrop; - bool mIsExternal; - RefPtr<FileList> mFiles; - nsTArray<RefPtr<DataTransferItem>> mItems; - nsTArray<nsTArray<RefPtr<DataTransferItem>>> mIndexedItems; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_DataTransferItemList_h
--- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -1807,17 +1807,17 @@ EventStateManager::GenerateDragGesture(n // Emit observer event to allow addons to modify the DataTransfer object. if (observerService) { observerService->NotifyObservers(dataTransfer, "on-datatransfer-available", nullptr); } // now that the dataTransfer has been updated in the dragstart and - // draggesture events, make it readonly so that the data doesn't + // draggesture events, make it read only so that the data doesn't // change during the drag. dataTransfer->SetReadOnly(); if (status != nsEventStatus_eConsumeNoDefault) { bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer, targetContent, selection); if (dragStarted) { sActiveESM = nullptr;
--- a/dom/events/moz.build +++ b/dom/events/moz.build @@ -39,18 +39,16 @@ EXPORTS.mozilla.dom += [ 'BeforeAfterKeyboardEvent.h', 'BeforeUnloadEvent.h', 'ClipboardEvent.h', 'CommandEvent.h', 'CompositionEvent.h', 'CustomEvent.h', 'DataContainerEvent.h', 'DataTransfer.h', - 'DataTransferItem.h', - 'DataTransferItemList.h', 'DeviceMotionEvent.h', 'DragEvent.h', 'Event.h', 'EventTarget.h', 'FocusEvent.h', 'ImageCaptureError.h', 'InputEvent.h', 'KeyboardEvent.h', @@ -119,18 +117,16 @@ UNIFIED_SOURCES += [ 'UIEvent.cpp', 'WheelEvent.cpp', 'WheelHandlingHelper.cpp', 'XULCommandEvent.cpp', ] # nsEventStateManager.cpp should be built separately because of Mac OS X headers. SOURCES += [ - 'DataTransferItem.cpp', - 'DataTransferItemList.cpp', 'EventStateManager.cpp', ] if CONFIG['MOZ_WEBSPEECH']: UNIFIED_SOURCES += ['SpeechRecognitionError.cpp'] include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/events/test/chrome.ini +++ b/dom/events/test/chrome.ini @@ -20,9 +20,8 @@ support-files = [test_bug602962.xul] [test_bug617528.xul] [test_bug679494.xul] [test_bug930374-chrome.html] [test_bug1128787-1.html] [test_bug1128787-2.html] [test_bug1128787-3.html] [test_eventctors.xul] -[test_DataTransferItemList.html] \ No newline at end of file
deleted file mode 100644 --- a/dom/events/test/test_DataTransferItemList.html +++ /dev/null @@ -1,227 +0,0 @@ -<html> -<head> - <title>Tests for the DatTransferItemList object</title> - <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> - <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script> - <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> -</head> -<body style="height: 300px; overflow: auto;"> -<p id="display"> </p> -<img id="image" draggable="true" src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82"> -<div id="over" "style="width: 100px; height: 100px; border: 2px black dashed;"> - drag over here -</div> - -<script> - function spin() { - // Defer to the event loop twice to wait for any events to be flushed out. - return new Promise(function(a) { - SimpleTest.executeSoon(function() { - SimpleTest.executeSoon(a) - }); - }); - } - - add_task(function* () { - yield spin(); - var draggable = document.getElementById('image'); - var over = document.getElementById('over'); - - var dragstartFired = 0; - draggable.addEventListener('dragstart', onDragStart); - function onDragStart(e) { - draggable.removeEventListener('dragstart', onDragStart); - - var dt = e.dataTransfer; - dragstartFired++; - - ok(true, "dragStart event fired"); - var dtList = e.dataTransfer.items; - ok(dtList instanceof DataTransferItemList, - "DataTransfer.items returns a DataTransferItemList"); - - for (var i = 0; i < dtList.length; i++) { - var item = dtList[i]; - ok(item instanceof DataTransferItem, - "operator[] returns DataTransferItem objects"); - if (item.kind == "file") { - var file = item.getAsFile(); - ok(file instanceof File, "getAsFile() returns File objects"); - } - } - - dtList.clear(); - is(dtList.length, 0, "after .clear() DataTransferItemList should be empty"); - - dtList.add("this is some text", "text/plain"); - dtList.add("<a href='www.mozilla.org'>this is a link</a>", "text/html"); - dtList.add("http://www.mozilla.org", "text/uri-list"); - dtList.add("this is custom-data", "custom-data"); - - - var file = new File(['<a id="a"><b id="b">hey!</b></a>'], "myfile.html", - {type: "text/html"}); - - dtList.add(file); - - checkTypes(["text/plain", "text/html", "text/uri-list", "custom-data", "text/html"], - dtList, "DataTransferItemList.add test"); - - var files = e.dataTransfer.files; - is(files.length, 1, "DataTransfer.files should contain the one file we added earlier"); - is(files[0], file, "It should be the same file as the file we originally created"); - is(file, e.dataTransfer.mozGetDataAt("text/html", 1), - "It should be stored in index 1 for mozGetDataAt"); - - var file2 = new File(['<a id="c"><b id="d">yo!</b></a>'], "myotherfile.html", - {type: "text/html"}); - dtList.add(file2); - - is(files.length, 2, "The files property should have been updated in place"); - is(files[1], file2, "It should be the same file as the file we originally created"); - is(file2, e.dataTransfer.mozGetDataAt("text/html", 2), - "It should be stored in index 2 for mozGetDataAt"); - - var oldLength = dtList.length; - var randomString = "foo!"; - e.dataTransfer.mozSetDataAt("random/string", randomString, 3); - is(oldLength, dtList.length, - "Adding a non-file entry to a non-zero index should not add an item to the items list"); - - var file3 = new File(['<a id="e"><b id="f">heya!</b></a>'], "yetanotherfile.html", - {type: "text/html"}); - e.dataTransfer.mozSetDataAt("random/string", file3, 3); - is(oldLength + 1, dtList.length, - "Replacing the entry with a file should add it to the list!"); - is(dtList[oldLength].getAsFile(), file3, "It should be stored in the last index as a file"); - is(dtList[oldLength].type, "random/string", "It should have the correct type"); - is(dtList[oldLength].kind, "file", "It should have the correct kind"); - is(files[files.length - 1], file3, "It should also be in the files list"); - - oldLength = dtList.length; - var nonstring = {}; - e.dataTransfer.mozSetDataAt("jsobject", nonstring, 0); - is(oldLength + 1, dtList.length, - "Adding a non-string object using the mozAPIs to index 0 should add an item to the dataTransfer"); - is(dtList[oldLength].type, "jsobject", "It should have the correct type"); - is(dtList[oldLength].kind, "other", "It should have the correct kind"); - - // Clear the event's data and get it set up so we can read it later! - dtList.clear(); - - dtList.add(file); - dtList.add("this is some text", "text/plain"); - is(e.dataTransfer.mozGetDataAt("text/html", 1), file); - } - - var getAsStringCalled = 0; - var dragenterFired = 0; - over.addEventListener('dragenter', onDragEnter); - function onDragEnter(e) { - over.removeEventListener('dragenter', onDragEnter); - - var dt = e.dataTransfer; - dragenterFired++; - - readOnly(e); - } - - var dropFired = 0; - over.addEventListener('drop', onDrop); - function onDrop(e) { - over.removeEventListener('drop', onDrop); - - var dt = e.dataTransfer; - dropFired++; - e.preventDefault(); - - readOnly(e); - } - - - function readOnly(e) { - var dtList = e.dataTransfer.items; - var num = dtList.length; - - // .clear() should have no effect - dtList.clear(); - is(dtList.length, num, - ".clear() should have no effect on the object during a readOnly event"); - - // .remove(i) should throw InvalidStateError - for (var i = 0; i < dtList.length; i++) { - expectError(function() { dtList.remove(i); }, - "InvalidStateError", ".remove(" + i + ") during a readOnly event"); - } - - // .add() should return null and have no effect - var data = [["This is a plain string", "text/plain"], - ["This is <em>HTML!</em>", "text/html"], - ["http://www.mozilla.org/", "text/uri-list"], - ["this is some custom data", "custom-data"]]; - - for (var i = 0; i < data.length; i++) { - is(dtList.add(data[i][0], data[i][1]), null, - ".add() should return null during a readOnly event"); - - is(dtList.length, num, ".add() should have no effect during a readOnly event"); - } - - // .add() with a file should return null and have no effect - var file = new File(['<a id="a"><b id="b">hey!</b></a>'], "myfile.html", - {type: "text/html"}); - is(dtList.add(file), null, ".add() with a file should return null during a readOnly event"); - is(dtList.length, num, ".add() should have no effect during a readOnly event"); - - // We should be able to access the files - is(e.dataTransfer.files.length, 1, "Should be able to access files"); - ok(e.dataTransfer.files[0], "File should be the same file!"); - is(e.dataTransfer.items.length, 2, "Should be able to see there are 2 items"); - - is(e.dataTransfer.items[0].kind, "file", "First item should be a file"); - is(e.dataTransfer.items[1].kind, "string", "Second item should be a string"); - - is(e.dataTransfer.items[0].type, "text/html", "first item should be text/html"); - is(e.dataTransfer.items[1].type, "text/plain", "second item should be text/plain"); - - ok(e.dataTransfer.items[0].getAsFile(), "Should be able to get file"); - e.dataTransfer.items[1].getAsString(function(s) { - getAsStringCalled++; - is(s, "this is some text", "Should provide the correct string"); - }); - } - - synthesizeDrop(draggable, over, null, null); - - // Wait for the getAsString callbacks to complete - yield spin(); - is(getAsStringCalled, 2, "getAsString should be called twice"); - - // Sanity-check to make sure that the events were actually run - is(dragstartFired, 1, "dragstart fired"); - is(dragenterFired, 1, "dragenter fired"); - is(dropFired, 1, "drop fired"); - }); - - function expectError(fn, eid, testid) { - var error = ""; - try { - fn(); - } catch (ex) { - error = ex.name; - } - is(error, eid, testid + " causes exception " + eid); - } - - function checkTypes(aExpectedList, aDtList, aTestid) { - is(aDtList.length, aExpectedList.length, aTestid + " length test"); - for (var i = 0; i < aExpectedList.length; i++) { - is(aDtList[i].type, aExpectedList[i], aTestid + " type " + i); - } - } -</script> - -</body> -</html>
--- a/dom/events/test/test_dragstart.html +++ b/dom/events/test/test_dragstart.html @@ -353,29 +353,24 @@ function test_DataTransfer(dt) checkOneDataItem(dt, ["text/plain", "text/html"], ["First Item", "Changed with setData"], 0, "clearData type that does not exist item at index 0"); checkOneDataItem(dt, ["text/unknown"], ["Unknown type"], 1, "clearData type that does not exist item at index 1"); expectError(() => dt.mozClearDataAt("text/plain", 3), "IndexSizeError", "clearData index too high with two items"); - // ensure that clearData() removes all data associated with the first item, but doesn't - // shift the second item down into the first item's slot. + // ensure that clearData() removes all data associated with the first item dt.clearData(); - is(dt.mozItemCount, 2, "clearData no argument with multiple items itemCount"); - checkOneDataItem(dt, [], [], 0, - "clearData no argument with multiple items item at index 0"); + is(dt.mozItemCount, 1, "clearData no argument with multiple items itemCount"); checkOneDataItem(dt, ["text/unknown"], - ["Unknown type"], 1, "clearData no argument with multiple items item at index 1"); + ["Unknown type"], 0, "clearData no argument with multiple items item at index 1"); - // remove tha remaining data in index 1. As index 0 is empty at this point, this will actually - // drop mozItemCount to 0. (XXX: This is because of spec-compliance reasons related - // to the more-recent dt.item API. It's an unfortunate, but hopefully rare edge case) - dt.mozClearDataAt("", 1); + // remove tha remaining data + dt.mozClearDataAt("", 0); is(dt.mozItemCount, 0, "all data cleared"); // now check the effectAllowed and dropEffect properties is(dt.dropEffect, "none", "initial dropEffect"); is(dt.effectAllowed, "uninitialized", "initial effectAllowed"); ["copy", "none", "link", "", "other", "copyMove", "all", "uninitialized", "move"].forEach( function (i) {
--- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -227,15 +227,8 @@ RewriteYoutubeEmbedInvalidQuery=Rewritin # LOCALIZATION NOTE: Do not translate "ServiceWorker". %1$S is the ServiceWorker scope URL. %2$S is an error string. PushMessageDecryptionFailure=The ServiceWorker for scope ‘%1$S’ encountered an error decrypting a push message: ‘%2$S’. For help with encryption, please see https://developer.mozilla.org/en-US/docs/Web/API/Push_API/Using_the_Push_API#Encryption # LOCALIZATION NOTE: %1$S is the type of a DOM event. 'passive' is a literal parameter from the DOM spec. PreventDefaultFromPassiveListenerWarning=Ignoring ‘preventDefault()’ call on event of type ‘%1$S’ from a listener registered as ‘passive’. FileLastModifiedDateWarning=File.lastModifiedDate is deprecated. Use File.lastModified instead. ChromeScriptedDOMParserWithoutPrincipal=Creating DOMParser without a principal is deprecated. IIRFilterChannelCountChangeWarning=IIRFilterNode channel count changes may produce audio glitches. BiquadFilterChannelCountChangeWarning=BiquadFilterNode channel count changes may produce audio glitches. -# LOCALIZATION NOTE: Do not translate ".jpeg" -GenericImageNameJPEG=image.jpeg -# LOCALIZATION NOTE: Do not translate ".gif" -GenericImageNameGIF=image.gif -# LOCALIZATION NOTE: Do not translate ".png" -GenericImageNamePNG=image.png -GenericFileName=file
--- a/dom/tests/mochitest/general/test_clipboard_events.html +++ b/dom/tests/mochitest/general/test_clipboard_events.html @@ -659,17 +659,17 @@ function checkCachedDataTransfer(cd, eve ok(oldtext != "Some Clipboard Text", "clipboard get using " + testprefix); var exh = false; try { cd.mozSetDataAt("text/plain", "Test Cache Data", 0); } catch (ex) { exh = true; } ok(eventtype == "paste" ? exh : !exh, "exception occured setting " + testprefix); var newtext = (eventtype == "paste") ? cd.getData("text/plain") : cd.mozGetDataAt("text/plain", 0); - is(newtext, (eventtype == "paste") ? oldtext : "Test Cache Data", + is(newtext, (eventtype == "paste") ? "" : "Test Cache Data", " clipboardData not changed using " + testprefix); is(getClipboardText(), "Some Clipboard Text", "clipboard not changed using " + testprefix); var exh = false; try { cd.mozClearDataAt("text/plain", 0); } catch (ex) { exh = true; } ok(eventtype == "paste" ? exh : !exh, "exception occured clearing " + testprefix);
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -381,20 +381,16 @@ var interfaceNamesInGlobalScope = "CustomEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "DataChannel", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "DataErrorEvent", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! "DataTransfer", // IMPORTANT: Do not change this list without review from a DOM peer! - "DataTransferItem", -// IMPORTANT: Do not change this list without review from a DOM peer! - "DataTransferItemList", -// IMPORTANT: Do not change this list without review from a DOM peer! "DelayNode", // IMPORTANT: Do not change this list without review from a DOM peer! "DesktopNotification", // IMPORTANT: Do not change this list without review from a DOM peer! "DesktopNotificationCenter", // IMPORTANT: Do not change this list without review from a DOM peer! "DeviceLightEvent", // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/DataTransfer.webidl +++ b/dom/webidl/DataTransfer.webidl @@ -7,22 +7,21 @@ * http://www.whatwg.org/specs/web-apps/current-work/#the-datatransfer-interface */ [ChromeConstructor(DOMString eventType, boolean isExternal)] interface DataTransfer { attribute DOMString dropEffect; attribute DOMString effectAllowed; - readonly attribute DataTransferItemList items; + //readonly attribute DataTransferItemList items; [Throws] void setDragImage(Element image, long x, long y); - [Throws] readonly attribute DOMStringList types; [Throws] DOMString getData(DOMString format); [Throws] void setData(DOMString format, DOMString data); [Throws] void clearData(optional DOMString format); [Throws]
deleted file mode 100644 --- a/dom/webidl/DataTransferItem.webidl +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * The origin of this IDL file is: - * https://html.spec.whatwg.org/multipage/interaction.html#the-datatransferitem-interface - */ - -interface DataTransferItem { - readonly attribute DOMString kind; - readonly attribute DOMString type; - [Throws] - void getAsString(FunctionStringCallback? _callback); - [Throws] - File? getAsFile(); -}; - -callback FunctionStringCallback = void (DOMString data);
deleted file mode 100644 --- a/dom/webidl/DataTransferItemList.webidl +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * The origin of this IDL file is: - * https://html.spec.whatwg.org/multipage/interaction.html#the-datatransferitemlist-interface - */ - -interface DataTransferItemList { - readonly attribute unsigned long length; - [Throws] - getter DataTransferItem (unsigned long index); - [Throws] - DataTransferItem? add(DOMString data, DOMString type); - [Throws] - DataTransferItem? add(File data); - [Throws] - void remove(unsigned long index); - [Throws] - void clear(); -};
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -105,18 +105,16 @@ WEBIDL_FILES = [ 'CSSRuleList.webidl', 'CSSStyleDeclaration.webidl', 'CSSStyleSheet.webidl', 'CSSTransition.webidl', 'CSSValue.webidl', 'CSSValueList.webidl', 'DataContainerEvent.webidl', 'DataTransfer.webidl', - 'DataTransferItem.webidl', - 'DataTransferItemList.webidl', 'DecoderDoctorNotification.webidl', 'DedicatedWorkerGlobalScope.webidl', 'DelayNode.webidl', 'DesktopNotification.webidl', 'DeviceMotionEvent.webidl', 'DeviceStorage.webidl', 'DeviceStorageAreaListener.webidl', 'Directory.webidl',
--- a/editor/libeditor/nsEditorEventListener.cpp +++ b/editor/libeditor/nsEditorEventListener.cpp @@ -934,21 +934,17 @@ nsEditorEventListener::CanDrop(nsIDOMDra return false; } nsCOMPtr<nsIDOMDataTransfer> domDataTransfer; aEvent->GetDataTransfer(getter_AddRefs(domDataTransfer)); nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(domDataTransfer); NS_ENSURE_TRUE(dataTransfer, false); - ErrorResult err; - RefPtr<DOMStringList> types = dataTransfer->GetTypes(err); - if (NS_WARN_IF(err.Failed())) { - return false; - } + RefPtr<DOMStringList> types = dataTransfer->Types(); // Plaintext editors only support dropping text. Otherwise, HTML and files // can be dropped as well. if (!types->Contains(NS_LITERAL_STRING(kTextMime)) && !types->Contains(NS_LITERAL_STRING(kMozTextInternal)) && (mEditor->IsPlaintextEditor() || (!types->Contains(NS_LITERAL_STRING(kHTMLMime)) && !types->Contains(NS_LITERAL_STRING(kFileMime))))) {
--- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -289,22 +289,17 @@ nsFileControlFrame::DnDListener::HandleE /* static */ bool nsFileControlFrame::DnDListener::IsValidDropData(nsIDOMDataTransfer* aDOMDataTransfer) { nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(aDOMDataTransfer); NS_ENSURE_TRUE(dataTransfer, false); // We only support dropping files onto a file upload control - ErrorResult rv; - RefPtr<DOMStringList> types = dataTransfer->GetTypes(rv); - if (NS_WARN_IF(rv.Failed())) { - return false; - } - + RefPtr<DOMStringList> types = dataTransfer->Types(); return types->Contains(NS_LITERAL_STRING("Files")); } /* static */ bool nsFileControlFrame::DnDListener::CanDropTheseFiles(nsIDOMDataTransfer* aDOMDataTransfer, bool aSupportsMultiple) { nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(aDOMDataTransfer);
--- a/testing/web-platform/meta/html/dom/interfaces.html.ini +++ b/testing/web-platform/meta/html/dom/interfaces.html.ini @@ -1700,16 +1700,70 @@ expected: FAIL [Path2D interface: operation addPathByStrokingText(DOMString,CanvasDrawingStyles,SVGMatrix,Path2D,unrestricted double)] expected: FAIL [DataTransfer interface object length] expected: FAIL + [DataTransfer interface: attribute items] + expected: FAIL + + [DataTransferItemList interface: existence and properties of interface object] + expected: FAIL + + [DataTransferItemList interface object length] + expected: FAIL + + [DataTransferItemList interface: existence and properties of interface prototype object] + expected: FAIL + + [DataTransferItemList interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [DataTransferItemList interface: attribute length] + expected: FAIL + + [DataTransferItemList interface: operation add(DOMString,DOMString)] + expected: FAIL + + [DataTransferItemList interface: operation add(File)] + expected: FAIL + + [DataTransferItemList interface: operation remove(unsigned long)] + expected: FAIL + + [DataTransferItemList interface: operation clear()] + expected: FAIL + + [DataTransferItem interface: existence and properties of interface object] + expected: FAIL + + [DataTransferItem interface object length] + expected: FAIL + + [DataTransferItem interface: existence and properties of interface prototype object] + expected: FAIL + + [DataTransferItem interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [DataTransferItem interface: attribute kind] + expected: FAIL + + [DataTransferItem interface: attribute type] + expected: FAIL + + [DataTransferItem interface: operation getAsString(FunctionStringCallback)] + expected: FAIL + + [DataTransferItem interface: operation getAsFile()] + expected: FAIL + [Window interface: operation showModalDialog(DOMString,any)] disabled: if e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=981796 [Window interface: attribute onautocomplete] expected: FAIL [Window interface: attribute onautocompleteerror] @@ -2477,16 +2531,22 @@ expected: FAIL [CanvasProxy interface object name] expected: FAIL [DrawingStyle interface object name] expected: FAIL + [DataTransferItemList interface object name] + expected: FAIL + + [DataTransferItem interface object name] + expected: FAIL + [ApplicationCache interface object name] expected: FAIL [PortCollection interface object name] expected: FAIL [WorkerGlobalScope interface object name] expected: FAIL
--- a/widget/gonk/nsClipboard.cpp +++ b/widget/gonk/nsClipboard.cpp @@ -267,28 +267,22 @@ nsClipboard::GetData(nsITransferable *aT RefPtr<gfx::DataSourceSurface> image = mClipboard->GetImage(); // Encode according to MIME type. RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, image->GetSize()); nsCOMPtr<imgIContainer> imageContainer(image::ImageOps::CreateFromDrawable(drawable)); nsCOMPtr<imgITools> imgTool = do_GetService(NS_IMGTOOLS_CID); nsCOMPtr<nsIInputStream> byteStream; - nsresult rv = imgTool->EncodeImage(imageContainer, - flavorStr, - EmptyString(), - getter_AddRefs(byteStream)); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } + imgTool->EncodeImage(imageContainer, flavorStr, EmptyString(), getter_AddRefs(byteStream)); // Set transferable. - rv = aTransferable->SetTransferData(flavorStr, - byteStream, - sizeof(nsIInputStream*)); + nsresult rv = aTransferable->SetTransferData(flavorStr, + byteStream, + sizeof(nsIInputStream*)); if (NS_WARN_IF(NS_FAILED(rv))) { continue; } break; } } }