mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Backed out changeset 5c836acf3197 (bug 906420) on developer request by baku
--HG-- extra : rebase_source : 9f109cdb706feef6d2bcd9a2e71f8c4d3c17ebdf
This commit is contained in:
parent
cec713e0c7
commit
afff301b32
@ -691,8 +691,8 @@ nsCopySupport::FireClipboardEvent(EventMessage aEventMessage,
|
||||
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);
|
||||
|
@ -30,22 +30,30 @@
|
||||
#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)
|
||||
@ -53,6 +61,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
|
||||
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)
|
||||
@ -96,7 +105,6 @@ DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
|
||||
, 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.
|
||||
@ -123,7 +131,7 @@ DataTransfer::DataTransfer(nsISupports* aParent,
|
||||
bool aUserCancelled,
|
||||
bool aIsCrossDomainSubFrameDrop,
|
||||
int32_t aClipboardType,
|
||||
DataTransferItemList* aItems,
|
||||
nsTArray<nsTArray<TransferItem> >& aItems,
|
||||
Element* aDragImage,
|
||||
uint32_t aDragImageX,
|
||||
uint32_t aDragImageY)
|
||||
@ -137,16 +145,12 @@ DataTransfer::DataTransfer(nsISupports* aParent,
|
||||
, 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
|
||||
@ -288,76 +292,102 @@ DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
|
||||
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;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
RefPtr<DOMStringList> types = GetTypes(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
RefPtr<DOMStringList> types = Types();
|
||||
types.forget(aTypes);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -445,7 +475,7 @@ DataTransfer::ClearData(const Optional<nsAString>& aFormat, ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
|
||||
if (MozItemCount() == 0) {
|
||||
if (mItems.Length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -534,18 +564,29 @@ DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv) const
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
@ -580,7 +621,7 @@ DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aIndex >= MozItemCount()) {
|
||||
if (aIndex >= mItems.Length()) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
@ -594,11 +635,15 @@ DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -613,44 +658,43 @@ DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (item->Principal() && checkFormatItemPrincipal &&
|
||||
!aSubjectPrincipal->Subsumes(item->Principal())) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIVariant> data = item->Data();
|
||||
MOZ_ASSERT(data);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -694,7 +738,7 @@ DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -752,7 +796,7 @@ DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
|
||||
return;
|
||||
}
|
||||
|
||||
if (aIndex >= MozItemCount()) {
|
||||
if (aIndex >= mItems.Length()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
}
|
||||
@ -766,17 +810,6 @@ DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
|
||||
}
|
||||
|
||||
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
|
||||
@ -784,7 +817,7 @@ 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));
|
||||
@ -792,7 +825,40 @@ DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
|
||||
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
|
||||
@ -845,17 +911,19 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -894,13 +962,14 @@ 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;
|
||||
}
|
||||
|
||||
@ -932,7 +1001,7 @@ DataTransfer::GetTransferables(nsILoadContext* aLoadContext)
|
||||
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) {
|
||||
@ -946,11 +1015,11 @@ DataTransfer::GetTransferables(nsILoadContext* aLoadContext)
|
||||
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;
|
||||
@ -1002,18 +1071,15 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@ -1023,7 +1089,7 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
|
||||
nsCOMPtr<nsISupports> convertedData;
|
||||
|
||||
if (handlingCustomFormats) {
|
||||
if (!ConvertFromVariant(formatitem->Data(), getter_AddRefs(convertedData),
|
||||
if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData),
|
||||
&lengthInBytes)) {
|
||||
continue;
|
||||
}
|
||||
@ -1050,11 +1116,12 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
|
||||
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);
|
||||
@ -1108,7 +1175,7 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
|
||||
} 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;
|
||||
}
|
||||
@ -1116,7 +1183,7 @@ DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
|
||||
// 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 {
|
||||
@ -1168,7 +1235,7 @@ DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
|
||||
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);
|
||||
@ -1224,13 +1291,7 @@ DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
|
||||
void
|
||||
DataTransfer::ClearAll()
|
||||
{
|
||||
mItems->ClearAllItems();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DataTransfer::MozItemCount() const
|
||||
{
|
||||
return mItems->MozItemCount();
|
||||
mItems.Clear();
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1242,10 +1303,49 @@ DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
|
||||
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
|
||||
@ -1302,12 +1402,6 @@ DataTransfer::CacheExternalData(const char* aFormat, uint32_t 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()
|
||||
{
|
||||
@ -1349,11 +1443,11 @@ DataTransfer::CacheExternalDragFormats()
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1402,16 +1496,100 @@ DataTransfer::CacheExternalClipboardFormats()
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1421,16 +1599,15 @@ 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
|
||||
|
@ -32,17 +32,28 @@ 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
|
||||
@ -77,7 +88,7 @@ protected:
|
||||
bool aUserCancelled,
|
||||
bool aIsCrossDomainSubFrameDrop,
|
||||
int32_t aClipboardType,
|
||||
DataTransferItemList* aItems,
|
||||
nsTArray<nsTArray<TransferItem> >& aItems,
|
||||
Element* aDragImage,
|
||||
uint32_t aDragImageX,
|
||||
uint32_t aDragImageY);
|
||||
@ -87,6 +98,7 @@ protected:
|
||||
static const char sEffects[8][9];
|
||||
|
||||
public:
|
||||
|
||||
// Constructor for DataTransfer.
|
||||
//
|
||||
// aIsExternal must only be true when used to create a dataTransfer for a
|
||||
@ -137,7 +149,7 @@ public:
|
||||
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);
|
||||
|
||||
@ -153,7 +165,10 @@ public:
|
||||
|
||||
void AddElement(Element& aElement, mozilla::ErrorResult& aRv);
|
||||
|
||||
uint32_t MozItemCount() const;
|
||||
uint32_t MozItemCount() const
|
||||
{
|
||||
return mItems.Length();
|
||||
}
|
||||
|
||||
void GetMozCursor(nsString& aCursor)
|
||||
{
|
||||
@ -195,14 +210,8 @@ public:
|
||||
|
||||
// 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);
|
||||
@ -251,12 +260,12 @@ public:
|
||||
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,
|
||||
@ -269,7 +278,14 @@ protected:
|
||||
// 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);
|
||||
@ -321,8 +337,12 @@ protected:
|
||||
// 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;
|
||||
|
@ -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
|
@ -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 */
|
@ -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
|
@ -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
|
@ -1812,7 +1812,7 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
|
@ -44,8 +44,6 @@ EXPORTS.mozilla.dom += [
|
||||
'CustomEvent.h',
|
||||
'DataContainerEvent.h',
|
||||
'DataTransfer.h',
|
||||
'DataTransferItem.h',
|
||||
'DataTransferItemList.h',
|
||||
'DeviceMotionEvent.h',
|
||||
'DragEvent.h',
|
||||
'Event.h',
|
||||
@ -124,8 +122,6 @@ UNIFIED_SOURCES += [
|
||||
|
||||
# nsEventStateManager.cpp should be built separately because of Mac OS X headers.
|
||||
SOURCES += [
|
||||
'DataTransferItem.cpp',
|
||||
'DataTransferItemList.cpp',
|
||||
'EventStateManager.cpp',
|
||||
]
|
||||
|
||||
|
@ -25,4 +25,3 @@ support-files =
|
||||
[test_bug1128787-2.html]
|
||||
[test_bug1128787-3.html]
|
||||
[test_eventctors.xul]
|
||||
[test_DataTransferItemList.html]
|
@ -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>
|
@ -358,19 +358,14 @@ function test_DataTransfer(dt)
|
||||
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
|
||||
|
@ -232,10 +232,3 @@ FileLastModifiedDateWarning=File.lastModifiedDate is deprecated. Use File.lastMo
|
||||
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
|
||||
|
@ -664,7 +664,7 @@ function checkCachedDataTransfer(cd, eventtype)
|
||||
|
||||
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);
|
||||
|
@ -385,10 +385,6 @@ var interfaceNamesInGlobalScope =
|
||||
{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!
|
||||
|
@ -12,12 +12,11 @@ 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);
|
||||
|
@ -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);
|
@ -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();
|
||||
};
|
@ -110,8 +110,6 @@ WEBIDL_FILES = [
|
||||
'CSSValueList.webidl',
|
||||
'DataContainerEvent.webidl',
|
||||
'DataTransfer.webidl',
|
||||
'DataTransferItem.webidl',
|
||||
'DataTransferItemList.webidl',
|
||||
'DecoderDoctorNotification.webidl',
|
||||
'DedicatedWorkerGlobalScope.webidl',
|
||||
'DelayNode.webidl',
|
||||
|
@ -939,11 +939,7 @@ nsEditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
|
||||
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.
|
||||
|
@ -294,12 +294,7 @@ nsFileControlFrame::DnDListener::IsValidDropData(nsIDOMDataTransfer* aDOMDataTra
|
||||
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"));
|
||||
}
|
||||
|
||||
|
@ -1705,6 +1705,60 @@
|
||||
[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
|
||||
@ -2482,6 +2536,12 @@
|
||||
[DrawingStyle interface object name]
|
||||
expected: FAIL
|
||||
|
||||
[DataTransferItemList interface object name]
|
||||
expected: FAIL
|
||||
|
||||
[DataTransferItem interface object name]
|
||||
expected: FAIL
|
||||
|
||||
[ApplicationCache interface object name]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -272,18 +272,12 @@ nsClipboard::GetData(nsITransferable *aTransferable,
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user