mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
801ccd962d
@ -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,80 +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);
|
||||
|
||||
if (item->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -449,7 +475,7 @@ DataTransfer::ClearData(const Optional<nsAString>& aFormat, ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
|
||||
if (MozItemCount() == 0) {
|
||||
if (mItems.Length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -538,29 +564,27 @@ DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv) const
|
||||
}
|
||||
|
||||
RefPtr<DOMStringList> types = new DOMStringList();
|
||||
if (aIndex < MozItemCount()) {
|
||||
// note that you can retrieve the types regardless of their principal
|
||||
const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(aIndex);
|
||||
|
||||
if (aIndex < mItems.Length()) {
|
||||
bool addFile = false;
|
||||
for (uint32_t i = 0; i < items.Length(); i++) {
|
||||
if (items[i]->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoString type;
|
||||
items[i]->GetType(type);
|
||||
if (NS_WARN_IF(!types->Add(type))) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (items[i]->Kind() == DataTransferItem::KIND_FILE) {
|
||||
addFile = true;
|
||||
// note that you can retrieve the types regardless of their principal
|
||||
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"));
|
||||
}
|
||||
}
|
||||
@ -597,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;
|
||||
}
|
||||
|
||||
@ -611,6 +635,20 @@ DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsAutoString format;
|
||||
GetRealFormat(aFormat, format);
|
||||
|
||||
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)) {
|
||||
uint32_t count = item.Length();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (item[i].mFormat.EqualsLiteral(kFileMime)) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the caller is allowed to access the drag data. Callers with
|
||||
// chrome privileges can always read the data. During the
|
||||
// drop event, allow retrieving the data except in the case where the
|
||||
@ -620,49 +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 we have chrome only content, and we aren't chrome, don't allow access
|
||||
if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal) && item->ChromeOnly()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (item->Principal() && checkFormatItemPrincipal &&
|
||||
!aSubjectPrincipal->Subsumes(item->Principal())) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIVariant> data = item->Data();
|
||||
MOZ_ASSERT(data);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -706,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;
|
||||
}
|
||||
|
||||
@ -764,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;
|
||||
}
|
||||
@ -778,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
|
||||
@ -796,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));
|
||||
@ -804,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
|
||||
@ -857,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;
|
||||
}
|
||||
@ -906,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;
|
||||
}
|
||||
|
||||
@ -944,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) {
|
||||
@ -958,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;
|
||||
@ -1014,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;
|
||||
}
|
||||
@ -1035,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;
|
||||
}
|
||||
@ -1062,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);
|
||||
@ -1120,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;
|
||||
}
|
||||
@ -1128,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 {
|
||||
@ -1180,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);
|
||||
@ -1236,13 +1291,7 @@ DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
|
||||
void
|
||||
DataTransfer::ClearAll()
|
||||
{
|
||||
mItems->ClearAllItems();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DataTransfer::MozItemCount() const
|
||||
{
|
||||
return mItems->MozItemCount();
|
||||
mItems.Clear();
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1254,13 +1303,49 @@ DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
|
||||
nsAutoString format;
|
||||
GetRealFormat(aFormat, format);
|
||||
|
||||
ErrorResult rv;
|
||||
RefPtr<DataTransferItem> item =
|
||||
mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal,
|
||||
/* aInsertOnly = */ false,
|
||||
/* aHidden= */ 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
|
||||
@ -1297,48 +1382,26 @@ DataTransfer::GetRealFormat(const nsAString& aInFormat,
|
||||
aOutFormat.Assign(lowercaseFormat);
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal, bool aHidden)
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
ErrorResult rv;
|
||||
RefPtr<DataTransferItem> item;
|
||||
|
||||
if (strcmp(aFormat, kUnicodeMime) == 0) {
|
||||
item = mItems->SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr,
|
||||
aIndex, aPrincipal, false, aHidden, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
return NS_OK;
|
||||
SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr, aIndex,
|
||||
aPrincipal);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(aFormat, kURLDataMime) == 0) {
|
||||
item = mItems->SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr,
|
||||
aIndex, aPrincipal, false, aHidden, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
return NS_OK;
|
||||
SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr, aIndex,
|
||||
aPrincipal);
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString format;
|
||||
GetRealFormat(NS_ConvertUTF8toUTF16(aFormat), format);
|
||||
item = mItems->SetDataWithPrincipal(format, nullptr, aIndex,
|
||||
aPrincipal, false, aHidden, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
return NS_OK;
|
||||
SetDataWithPrincipal(NS_ConvertUTF8toUTF16(aFormat), nullptr, aIndex,
|
||||
aPrincipal);
|
||||
}
|
||||
|
||||
// there isn't a way to get a list of the formats that might be available on
|
||||
// all platforms, so just check for the types that can actually be imported
|
||||
// XXXndeakin there are some other formats but those are platform specific.
|
||||
const char* kFormats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime,
|
||||
kUnicodeMime, kPNGImageMime, kJPEGImageMime,
|
||||
kGIFImageMime };
|
||||
|
||||
void
|
||||
DataTransfer::CacheExternalDragFormats()
|
||||
{
|
||||
@ -1367,9 +1430,6 @@ DataTransfer::CacheExternalDragFormats()
|
||||
uint32_t count;
|
||||
dragSession->GetNumDropItems(&count);
|
||||
for (uint32_t c = 0; c < count; c++) {
|
||||
bool hasFileData = false;
|
||||
dragSession->IsDataFlavorSupported(kFileMime, &hasFileData);
|
||||
|
||||
// First, check for the special format that holds custom types.
|
||||
bool supported;
|
||||
dragSession->IsDataFlavorSupported(kCustomTypesMime, &supported);
|
||||
@ -1383,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, /* hidden = */ f && hasFileData);
|
||||
CacheExternalData(formats[f], c, sysPrincipal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1413,17 +1473,11 @@ DataTransfer::CacheExternalClipboardFormats()
|
||||
nsCOMPtr<nsIPrincipal> sysPrincipal;
|
||||
ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
|
||||
|
||||
// Check if the clipboard has any files
|
||||
bool hasFileData = false;
|
||||
const char *fileMime[] = { kFileMime };
|
||||
clipboard->HasDataMatchingFlavors(fileMime, 1, mClipboardType, &hasFileData);
|
||||
|
||||
// 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.
|
||||
// Note that the loop below assumes that kCustomTypesMime will be first.
|
||||
const char* formats[] = { kCustomTypesMime, kFileMime, kHTMLMime, kRTFMime,
|
||||
kURLMime, kURLDataMime, kUnicodeMime, kPNGImageMime,
|
||||
kJPEGImageMime, kGIFImageMime };
|
||||
kURLMime, kURLDataMime, kUnicodeMime };
|
||||
|
||||
for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) {
|
||||
// check each format one at a time
|
||||
@ -1436,23 +1490,106 @@ DataTransfer::CacheExternalClipboardFormats()
|
||||
if (f == 0) {
|
||||
FillInExternalCustomTypes(0, sysPrincipal);
|
||||
} else {
|
||||
// If we aren't the file data, and we have file data, we want to be hidden
|
||||
CacheExternalData(formats[f], 0, sysPrincipal, /* hidden = */ f != 1 && hasFileData);
|
||||
CacheExternalData(formats[f], 0, sysPrincipal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
|
||||
{
|
||||
NS_PRECONDITION(mIsExternal, "Not an external data transfer");
|
||||
|
||||
if (aItem.mData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only drag and paste events should be calling FillInExternalData
|
||||
NS_ASSERTION(mEventMessage != eCut && mEventMessage != eCopy,
|
||||
"clipboard event with empty data");
|
||||
|
||||
NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat);
|
||||
const char* format = utf8format.get();
|
||||
if (strcmp(format, "text/plain") == 0) {
|
||||
format = kUnicodeMime;
|
||||
} else if (strcmp(format, "text/uri-list") == 0) {
|
||||
format = kURLDataMime;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITransferable> trans =
|
||||
do_CreateInstance("@mozilla.org/widget/transferable;1");
|
||||
if (!trans) {
|
||||
return;
|
||||
}
|
||||
|
||||
trans->Init(nullptr);
|
||||
trans->AddDataFlavor(format);
|
||||
|
||||
if (mEventMessage == ePaste) {
|
||||
MOZ_ASSERT(aIndex == 0, "index in clipboard must be 0");
|
||||
|
||||
nsCOMPtr<nsIClipboard> clipboard =
|
||||
do_GetService("@mozilla.org/widget/clipboard;1");
|
||||
if (!clipboard || mClipboardType < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
clipboard->GetData(trans, mClipboardType);
|
||||
} else {
|
||||
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
|
||||
if (!dragSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Since this is an external drag, the source document will always be null.
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
dragSession->GetSourceDocument(getter_AddRefs(domDoc));
|
||||
MOZ_ASSERT(!domDoc);
|
||||
#endif
|
||||
|
||||
dragSession->GetData(trans, aIndex);
|
||||
}
|
||||
|
||||
uint32_t length = 0;
|
||||
nsCOMPtr<nsISupports> data;
|
||||
trans->GetTransferData(format, getter_AddRefs(data), &length);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
RefPtr<nsVariantCC> variant = new nsVariantCC();
|
||||
|
||||
nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
|
||||
if (supportsstr) {
|
||||
nsAutoString str;
|
||||
supportsstr->GetData(str);
|
||||
variant->SetAsAString(str);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsISupportsCString> supportscstr = do_QueryInterface(data);
|
||||
if (supportscstr) {
|
||||
nsAutoCString str;
|
||||
supportscstr->GetData(str);
|
||||
variant->SetAsACString(str);
|
||||
} else {
|
||||
variant->SetAsISupports(data);
|
||||
}
|
||||
}
|
||||
|
||||
aItem.mData = variant;
|
||||
}
|
||||
|
||||
void
|
||||
DataTransfer::FillAllExternalData()
|
||||
{
|
||||
if (mIsExternal) {
|
||||
for (uint32_t i = 0; i < MozItemCount(); ++i) {
|
||||
const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(i);
|
||||
for (uint32_t j = 0; j < items.Length(); ++j) {
|
||||
MOZ_ASSERT(items[j]->Index() == i);
|
||||
|
||||
items[j]->FillInExternalData();
|
||||
for (uint32_t i = 0; i < mItems.Length(); ++i) {
|
||||
nsTArray<TransferItem>& itemArray = mItems[i];
|
||||
for (uint32_t j = 0; j < itemArray.Length(); ++j) {
|
||||
if (!itemArray[j].mData) {
|
||||
FillInExternalData(itemArray[j], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1462,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,16 +260,16 @@ 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.
|
||||
nsresult CacheExternalData(const char* aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal, bool aHidden);
|
||||
void CacheExternalData(const char* aFormat, uint32_t aIndex,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
// caches the formats that exist in the drag service that were added by an
|
||||
// external drag
|
||||
@ -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,368 +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" },
|
||||
{ kJPEGImageMime, "GenericImageNameJPEG" },
|
||||
{ kGIFImageMime, "GenericImageNameGIF" },
|
||||
{ kPNGImageMime, "GenericImageNamePNG" },
|
||||
};
|
||||
|
||||
} // 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 one of kFileMime,
|
||||
// kPNGImageMime, kJPEGImageMime, or kGIFImageMime. We want to convert
|
||||
// whatever type happens to actually be stored into a dom::File.
|
||||
|
||||
RefPtr<File> file = FileFromISupports(data);
|
||||
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::FileFromISupports(nsISupports* aSupports)
|
||||
{
|
||||
MOZ_ASSERT(aSupports);
|
||||
|
||||
RefPtr<File> file;
|
||||
|
||||
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.
|
||||
Blob* blob = static_cast<Blob*>(domBlob.get());
|
||||
file = blob->ToFile();
|
||||
} else if (nsCOMPtr<nsIFile> ifile = do_QueryInterface(aSupports)) {
|
||||
printf("Creating a File from a nsIFile!\n");
|
||||
file = File::CreateFromFile(GetParentObject(), ifile);
|
||||
} else if (nsCOMPtr<nsIInputStream> stream = do_QueryInterface(aSupports)) {
|
||||
// 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(aSupports)) {
|
||||
MOZ_ASSERT(blobImpl->IsFile());
|
||||
file = File::Create(GetParentObject(), blobImpl);
|
||||
}
|
||||
|
||||
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(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(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,140 +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), mChromeOnly(false), 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(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();
|
||||
|
||||
bool ChromeOnly() const
|
||||
{
|
||||
return mChromeOnly;
|
||||
}
|
||||
void SetChromeOnly(bool aChromeOnly)
|
||||
{
|
||||
mChromeOnly = aChromeOnly;
|
||||
}
|
||||
|
||||
private:
|
||||
~DataTransferItem() {}
|
||||
already_AddRefed<File> FileFromISupports(nsISupports* aParent);
|
||||
already_AddRefed<File> CreateFileFromInputStream(nsISupports* aParent,
|
||||
nsIInputStream* aStream,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// The index in the 2d mIndexedItems array
|
||||
uint32_t mIndex;
|
||||
|
||||
bool mChromeOnly;
|
||||
eKind mKind;
|
||||
nsString mType;
|
||||
nsCOMPtr<nsIVariant> mData;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
RefPtr<DataTransferItemList> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_DataTransferItem_h */
|
@ -1,590 +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(),
|
||||
/* aInsertOnly = */ true,
|
||||
/* aHidden = */ false,
|
||||
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, false, 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,
|
||||
bool aHidden,
|
||||
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, aHidden);
|
||||
|
||||
if (item->Kind() == DataTransferItem::KIND_FILE) {
|
||||
RegenerateFiles();
|
||||
}
|
||||
|
||||
return item.forget();
|
||||
}
|
||||
|
||||
DataTransferItem*
|
||||
DataTransferItemList::AppendNewItem(uint32_t aIndex,
|
||||
const nsAString& aType,
|
||||
nsIVariant* aData,
|
||||
nsIPrincipal* aPrincipal,
|
||||
bool aHidden)
|
||||
{
|
||||
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);
|
||||
item->SetChromeOnly(aHidden);
|
||||
|
||||
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 (!aHidden && (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,117 +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, bool aHidden, 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,
|
||||
bool aHidden);
|
||||
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]
|
@ -200,4 +200,3 @@ skip-if = buildapp == 'b2g' # no wheel events on b2g
|
||||
[test_bug1264380.html]
|
||||
run-if = (e10s && os != "win") # Bug 1270043, crash at windows platforms; Bug1264380 comment 20, nsDragService::InvokeDragSessionImpl behaves differently among platform implementations in non-e10s mode which prevents us to check the validity of nsIDragService::getCurrentSession() consistently via synthesize mouse clicks in non-e10s mode.
|
||||
[test_passive_listeners.html]
|
||||
[test_paste_image.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
|
||||
|
@ -1,196 +0,0 @@
|
||||
<html><head>
|
||||
<title>Test for bug 891247</title>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
function ImageTester() {
|
||||
var counter = 0;
|
||||
var images = [];
|
||||
var that = this;
|
||||
|
||||
this.add = function(aFile) {
|
||||
images.push(aFile);
|
||||
};
|
||||
|
||||
this.test = function() {
|
||||
for (var i = 0; i < images.length; i++) {
|
||||
testImageSize(images[i]);
|
||||
}
|
||||
};
|
||||
|
||||
this.returned = function() {
|
||||
counter++;
|
||||
info("returned=" + counter + " images.length=" + images.length);
|
||||
if (counter == images.length) {
|
||||
info("test finish");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
|
||||
function testImageSize(aFile) {
|
||||
var source = window.URL.createObjectURL(aFile);
|
||||
var image = new Image();
|
||||
image.src = source;
|
||||
var imageTester = that;
|
||||
image.onload = function() {
|
||||
is(this.width, 62, "Check generated image width");
|
||||
is(this.height, 71, "Check generated image height");
|
||||
if (aFile.type == "image/gif") {
|
||||
// this test fails for image/jpeg and image/png because the images
|
||||
// generated are slightly different
|
||||
testImageCanvas(image);
|
||||
}
|
||||
|
||||
imageTester.returned();
|
||||
}
|
||||
|
||||
document.body.appendChild(image);
|
||||
};
|
||||
|
||||
function testImageCanvas(aImage) {
|
||||
var canvas = drawToCanvas(aImage);
|
||||
|
||||
var refImage = document.getElementById('image');
|
||||
var refCanvas = drawToCanvas(refImage);
|
||||
|
||||
is(canvas.toDataURL(), refCanvas.toDataURL(), "Image should map pixel-by-pixel");
|
||||
}
|
||||
|
||||
function drawToCanvas(aImage) {
|
||||
var canvas = document.createElement("CANVAS");
|
||||
document.body.appendChild(canvas);
|
||||
canvas.width = aImage.width;
|
||||
canvas.height = aImage.height;
|
||||
canvas.getContext('2d').drawImage(aImage, 0, 0);
|
||||
return canvas;
|
||||
}
|
||||
}
|
||||
|
||||
function copyImage(aImageId) {
|
||||
// selection of the node
|
||||
var node = document.getElementById(aImageId);
|
||||
var webnav = SpecialPowers.wrap(window)
|
||||
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
|
||||
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
|
||||
|
||||
var docShell = webnav.QueryInterface(SpecialPowers.Ci.nsIDocShell);
|
||||
|
||||
// let's copy the node
|
||||
var documentViewer = docShell.contentViewer
|
||||
.QueryInterface(SpecialPowers.Ci.nsIContentViewerEdit);
|
||||
documentViewer.setCommandNode(node);
|
||||
documentViewer.copyImage(documentViewer.COPY_IMAGE_ALL);
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
copyImage('image');
|
||||
|
||||
//--------- now check the content of the clipboard
|
||||
var clipboard = SpecialPowers.Cc["@mozilla.org/widget/clipboard;1"]
|
||||
.getService(SpecialPowers.Ci.nsIClipboard);
|
||||
// does the clipboard contain text/unicode data ?
|
||||
ok(clipboard.hasDataMatchingFlavors(["text/unicode"], 1, clipboard.kGlobalClipboard),
|
||||
"clipboard contains unicode text");
|
||||
// does the clipboard contain text/html data ?
|
||||
ok(clipboard.hasDataMatchingFlavors(["text/html"], 1, clipboard.kGlobalClipboard),
|
||||
"clipboard contains html text");
|
||||
// does the clipboard contain image data ?
|
||||
ok(clipboard.hasDataMatchingFlavors(["image/png"], 1, clipboard.kGlobalClipboard),
|
||||
"clipboard contains image");
|
||||
|
||||
window.addEventListener("paste", onPaste);
|
||||
|
||||
var textarea = SpecialPowers.wrap(document.getElementById('textarea'));
|
||||
textarea.focus();
|
||||
textarea.editor.paste(clipboard.kGlobalClipboard);
|
||||
}
|
||||
|
||||
function onPaste(e) {
|
||||
var imageTester = new ImageTester;
|
||||
testFiles(e, imageTester);
|
||||
testItems(e, imageTester);
|
||||
imageTester.test();
|
||||
}
|
||||
|
||||
function testItems(e, imageTester) {
|
||||
var items = e.clipboardData.items;
|
||||
is(items, e.clipboardData.items,
|
||||
"Getting @items twice should return the same object");
|
||||
var haveFiles = false;
|
||||
ok(items instanceof DataTransferItemList, "@items implements DataTransferItemList");
|
||||
ok(items.length > 0, "@items is not empty");
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
ok(item instanceof DataTransferItem, "each element of @items must implement DataTransferItem");
|
||||
if (item.kind == "file") {
|
||||
var file = item.getAsFile();
|
||||
ok(file instanceof File, ".getAsFile() returns a File object");
|
||||
ok(file.size > 0, "Files shouldn't have size 0");
|
||||
imageTester.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testFiles(e, imageTester) {
|
||||
var files = e.clipboardData.files;
|
||||
|
||||
is(files, e.clipboardData.files,
|
||||
"Getting the files array twice should return the same array");
|
||||
ok(files.length > 0, "There should be at least one file in the clipboard");
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var file = files[i];
|
||||
ok(file instanceof File, ".files should contain only File objects");
|
||||
ok(file.size > 0, "This file shouldn't have size 0");
|
||||
if (file.name == "image.png") {
|
||||
is(file.type, "image/png", "This file should be a image/png");
|
||||
} else if (file.name == "image.jpeg") {
|
||||
is(file.type, "image/jpeg", "This file should be a image/jpeg");
|
||||
} else if (file.name == "image.gif") {
|
||||
is(file.type, "image/gif", "This file should be a image/gif");
|
||||
} else {
|
||||
info("file.name=" + file.name);
|
||||
ok(false, "Unexpected file name");
|
||||
}
|
||||
|
||||
testSlice(file);
|
||||
imageTester.add(file);
|
||||
// Adding the same image again so we can test concurrency
|
||||
imageTester.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
function testSlice(aFile) {
|
||||
var blob = aFile.slice();
|
||||
ok(blob instanceof Blob, ".slice returns a blob");
|
||||
is(blob.size, aFile.size, "the blob has the same size");
|
||||
|
||||
blob = aFile.slice(123123);
|
||||
is(blob.size, 0, ".slice overflow check");
|
||||
|
||||
blob = aFile.slice(123, 123141);
|
||||
is(blob.size, aFile.size - 123, ".slice @size check");
|
||||
|
||||
blob = aFile.slice(123, 12);
|
||||
is(blob.size, 0, ".slice @size check 2");
|
||||
|
||||
blob = aFile.slice(124, 134, "image/png");
|
||||
is(blob.size, 10, ".slice @size check 3");
|
||||
is(blob.type, "image/png", ".slice @type check");
|
||||
}
|
||||
|
||||
</script>
|
||||
<body onload="doTest();">
|
||||
<img id="image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABHCA
|
||||
IAAADQjmMaAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3goUAwAgSAORBwAAABl0RVh0Q29
|
||||
tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAABPSURBVGje7c4BDQAACAOga//OmuMbJGAurTbq
|
||||
6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6s31B0IqAY2/t
|
||||
QVCAAAAAElFTkSuQmCC" />
|
||||
<form>
|
||||
<textarea id="textarea"></textarea>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
@ -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"));
|
||||
}
|
||||
|
||||
|
117
taskcluster/scripts/builder/build-l10n.sh
Normal file
117
taskcluster/scripts/builder/build-l10n.sh
Normal file
@ -0,0 +1,117 @@
|
||||
#! /bin/bash -vex
|
||||
|
||||
set -x -e
|
||||
|
||||
echo "running as" $(id)
|
||||
|
||||
####
|
||||
# Taskcluster friendly wrapper for performing fx desktop l10n repacks via mozharness.
|
||||
# Based on ./build-linux.sh
|
||||
####
|
||||
|
||||
# Inputs, with defaults
|
||||
|
||||
: MOZHARNESS_SCRIPT ${MOZHARNESS_SCRIPT}
|
||||
: MOZHARNESS_CONFIG ${MOZHARNESS_CONFIG}
|
||||
: MOZHARNESS_ACTIONS ${MOZHARNESS_ACTIONS}
|
||||
: MOZHARNESS_OPTIONS ${MOZHARNESS_OPTIONS}
|
||||
|
||||
: TOOLTOOL_CACHE ${TOOLTOOL_CACHE:=/home/worker/tooltool-cache}
|
||||
|
||||
: NEED_XVFB ${NEED_XVFB:=false}
|
||||
|
||||
: WORKSPACE ${WORKSPACE:=/home/worker/workspace}
|
||||
|
||||
set -v
|
||||
|
||||
fail() {
|
||||
echo # make sure error message is on a new line
|
||||
echo "[build-l10n.sh:error]" "${@}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
export MOZ_CRASHREPORTER_NO_REPORT=1
|
||||
export MOZ_OBJDIR=obj-firefox
|
||||
export TINDERBOX_OUTPUT=1
|
||||
|
||||
# Ensure that in tree libraries can be found
|
||||
export LIBRARY_PATH=$LIBRARY_PATH:$WORKSPACE/src/obj-firefox:$WORKSPACE/src/gcc/lib64
|
||||
|
||||
# test required parameters are supplied
|
||||
if [[ -z ${MOZHARNESS_SCRIPT} ]]; then fail "MOZHARNESS_SCRIPT is not set"; fi
|
||||
if [[ -z ${MOZHARNESS_CONFIG} ]]; then fail "MOZHARNESS_CONFIG is not set"; fi
|
||||
|
||||
cleanup() {
|
||||
local rv=$?
|
||||
if [ -n "$xvfb_pid" ]; then
|
||||
kill $xvfb_pid || true
|
||||
fi
|
||||
exit $rv
|
||||
}
|
||||
trap cleanup EXIT INT
|
||||
|
||||
# run mozharness in XVfb, if necessary; this is an array to maintain the quoting in the -s argument
|
||||
if $NEED_XVFB; then
|
||||
# Some mozharness scripts set DISPLAY=:2
|
||||
Xvfb :2 -screen 0 1024x768x24 &
|
||||
export DISPLAY=:2
|
||||
xvfb_pid=$!
|
||||
# Only error code 255 matters, because it signifies that no
|
||||
# display could be opened. As long as we can open the display
|
||||
# tests should work. We'll retry a few times with a sleep before
|
||||
# failing.
|
||||
retry_count=0
|
||||
max_retries=2
|
||||
xvfb_test=0
|
||||
until [ $retry_count -gt $max_retries ]; do
|
||||
xvinfo || xvfb_test=$?
|
||||
if [ $xvfb_test != 255 ]; then
|
||||
retry_count=$(($max_retries + 1))
|
||||
else
|
||||
retry_count=$(($retry_count + 1))
|
||||
echo "Failed to start Xvfb, retry: $retry_count"
|
||||
sleep 2
|
||||
fi
|
||||
done
|
||||
if [ $xvfb_test == 255 ]; then fail "xvfb did not start properly"; fi
|
||||
fi
|
||||
|
||||
# set up mozharness configuration, via command line, env, etc.
|
||||
|
||||
# $TOOLTOOL_CACHE bypasses mozharness completely and is read by tooltool_wrapper.sh to set the
|
||||
# cache. However, only some mozharness scripts use tooltool_wrapper.sh, so this may not be
|
||||
# entirely effective.
|
||||
export TOOLTOOL_CACHE
|
||||
|
||||
# support multiple, space delimited, config files
|
||||
config_cmds=""
|
||||
for cfg in $MOZHARNESS_CONFIG; do
|
||||
config_cmds="${config_cmds} --config ${cfg}"
|
||||
done
|
||||
|
||||
# if MOZHARNESS_ACTIONS is given, only run those actions (completely overriding default_actions
|
||||
# in the mozharness configuration)
|
||||
if [ -n "$MOZHARNESS_ACTIONS" ]; then
|
||||
actions=""
|
||||
for action in $MOZHARNESS_ACTIONS; do
|
||||
actions="$actions --$action"
|
||||
done
|
||||
fi
|
||||
|
||||
# if MOZHARNESS_OPTIONS is given, append them to mozharness command line run
|
||||
# e.g. enable-pgo
|
||||
if [ -n "$MOZHARNESS_OPTIONS" ]; then
|
||||
options=""
|
||||
for option in $MOZHARNESS_OPTIONS; do
|
||||
options="$options --$option"
|
||||
done
|
||||
fi
|
||||
|
||||
python2.7 $WORKSPACE/build/src/testing/${MOZHARNESS_SCRIPT} \
|
||||
--disable-mock \
|
||||
--revision ${GECKO_HEAD_REV} \
|
||||
$actions \
|
||||
$options \
|
||||
${config_cmds} \
|
||||
--log-level=debug \
|
||||
--work-dir=$WORKSPACE/build \
|
@ -33,6 +33,7 @@ config = {
|
||||
'default_actions': [
|
||||
"clobber",
|
||||
"pull",
|
||||
"clone-locales",
|
||||
"list-locales",
|
||||
"setup",
|
||||
"repack",
|
||||
|
@ -31,6 +31,7 @@ config = {
|
||||
'default_actions': [
|
||||
"clobber",
|
||||
"pull",
|
||||
"clone-locales",
|
||||
"list-locales",
|
||||
"setup",
|
||||
"repack",
|
||||
|
@ -31,6 +31,7 @@ config = {
|
||||
'default_actions': [
|
||||
"clobber",
|
||||
"pull",
|
||||
"clone-locales",
|
||||
"list-locales",
|
||||
"setup",
|
||||
"repack",
|
||||
|
@ -31,6 +31,7 @@ config = {
|
||||
'default_actions': [
|
||||
"clobber",
|
||||
"pull",
|
||||
"clone-locales",
|
||||
"list-locales",
|
||||
"setup",
|
||||
"repack",
|
||||
|
@ -31,6 +31,7 @@ config = {
|
||||
'default_actions': [
|
||||
"clobber",
|
||||
"pull",
|
||||
"clone-locales",
|
||||
"list-locales",
|
||||
"setup",
|
||||
"repack",
|
||||
|
24
testing/mozharness/configs/single_locale/tc_linux64.py
Normal file
24
testing/mozharness/configs/single_locale/tc_linux64.py
Normal file
@ -0,0 +1,24 @@
|
||||
import os
|
||||
|
||||
config = {
|
||||
"locales_file": "src/browser/locales/all-locales",
|
||||
"tools_repo": "https://hg.mozilla.org/build/tools",
|
||||
"mozconfig": "src/browser/config/mozconfigs/linux64/l10n-mozconfig",
|
||||
"bootstrap_env": {
|
||||
"NO_MERCURIAL_SETUP_CHECK": "1",
|
||||
"MOZ_OBJDIR": "obj-l10n",
|
||||
"EN_US_BINARY_URL": "%(en_us_binary_url)s",
|
||||
"LOCALE_MERGEDIR": "%(abs_merge_dir)s/",
|
||||
"MOZ_UPDATE_CHANNEL": "%(update_channel)s",
|
||||
"DIST": "%(abs_objdir)s",
|
||||
"LOCALE_MERGEDIR": "%(abs_merge_dir)s/",
|
||||
"L10NBASEDIR": "../../l10n",
|
||||
"MOZ_MAKE_COMPLETE_MAR": "1",
|
||||
'TOOLTOOL_CACHE': os.environ.get('TOOLTOOL_CACHE'),
|
||||
},
|
||||
"upload_env": {
|
||||
'UPLOAD_HOST': 'localhost',
|
||||
'UPLOAD_PATH': '/home/worker/workspace/build/upload/',
|
||||
},
|
||||
"mozilla_dir": "src/",
|
||||
}
|
@ -141,20 +141,21 @@ class LocalesMixin(ChunkingMixin):
|
||||
|
||||
def run_compare_locales(self, locale, halt_on_failure=False):
|
||||
dirs = self.query_abs_dirs()
|
||||
compare_locales_script = os.path.join(dirs['abs_compare_locales_dir'],
|
||||
'scripts', 'compare-locales')
|
||||
env = self.query_env(partial_env={'PYTHONPATH':
|
||||
os.path.join(dirs['abs_compare_locales_dir'],
|
||||
'lib')})
|
||||
env = self.query_l10n_env()
|
||||
python = self.query_exe('python2.7')
|
||||
compare_locales_error_list = list(PythonErrorList)
|
||||
self.rmtree(dirs['abs_merge_dir'])
|
||||
self.mkdir_p(dirs['abs_merge_dir'])
|
||||
command = "python %s -m %s l10n.ini %s %s" % (compare_locales_script,
|
||||
dirs['abs_merge_dir'], dirs['abs_l10n_dir'], locale)
|
||||
command = [python, 'mach', 'compare-locales',
|
||||
'--merge-dir', dirs['abs_merge_dir'],
|
||||
'--l10n-ini', os.path.join(dirs['abs_locales_src_dir'], 'l10n.ini'),
|
||||
'--l10n-base', dirs['abs_l10n_dir'], locale]
|
||||
self.info("*** BEGIN compare-locales %s" % locale)
|
||||
status = self.run_command(command, error_list=compare_locales_error_list,
|
||||
cwd=dirs['abs_locales_src_dir'], env=env,
|
||||
halt_on_failure=halt_on_failure)
|
||||
status = self.run_command(command,
|
||||
halt_on_failure=halt_on_failure,
|
||||
env=env,
|
||||
cwd=dirs['abs_mozilla_dir'],
|
||||
error_list=compare_locales_error_list)
|
||||
self.info("*** END compare-locales %s" % locale)
|
||||
return status
|
||||
|
||||
@ -175,8 +176,15 @@ class LocalesMixin(ChunkingMixin):
|
||||
c['mozilla_dir'])
|
||||
dirs['abs_locales_src_dir'] = os.path.join(dirs['abs_mozilla_dir'],
|
||||
c['locales_dir'])
|
||||
dirs['abs_l10n_dir'] = os.path.join(dirs['abs_work_dir'],
|
||||
c['l10n_dir'])
|
||||
dirs['abs_compare_locales_dir'] = os.path.join(dirs['abs_mozilla_dir'],
|
||||
'python', 'compare-locales',
|
||||
'compare_locales')
|
||||
else:
|
||||
# Use old-compare-locales if no mozilla_dir set, needed
|
||||
# for clobberer, and existing mozharness tests.
|
||||
dirs['abs_compare_locales_dir'] = os.path.join(dirs['abs_work_dir'],
|
||||
'compare-locales')
|
||||
|
||||
if 'objdir' in c:
|
||||
if os.path.isabs(c['objdir']):
|
||||
dirs['abs_objdir'] = c['objdir']
|
||||
@ -187,8 +195,7 @@ class LocalesMixin(ChunkingMixin):
|
||||
'merged')
|
||||
dirs['abs_locales_dir'] = os.path.join(dirs['abs_objdir'],
|
||||
c['locales_dir'])
|
||||
dirs['abs_compare_locales_dir'] = os.path.join(dirs['abs_work_dir'],
|
||||
'compare-locales')
|
||||
|
||||
for key in dirs.keys():
|
||||
if key not in abs_dirs:
|
||||
abs_dirs[key] = dirs[key]
|
||||
|
@ -106,6 +106,9 @@ class MultiLocaleBuild(LocalesMixin, MercurialScript):
|
||||
'upload-multi', 'summary'],
|
||||
require_config_file=require_config_file)
|
||||
|
||||
def query_l10n_env(self):
|
||||
return self.query_env()
|
||||
|
||||
def clobber(self):
|
||||
c = self.config
|
||||
if c['work_dir'] != '.':
|
||||
|
@ -173,6 +173,7 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
|
||||
'all_actions': [
|
||||
"clobber",
|
||||
"pull",
|
||||
"clone-locales",
|
||||
"list-locales",
|
||||
"setup",
|
||||
"repack",
|
||||
@ -465,7 +466,7 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
|
||||
def _query_revision(self):
|
||||
""" Get the gecko revision in this order of precedence
|
||||
* cached value
|
||||
* command line arg --revision (development)
|
||||
* command line arg --revision (development, taskcluster)
|
||||
* buildbot properties (try with buildbot forced build)
|
||||
* buildbot change (try with buildbot scheduler)
|
||||
* from the en-US build (m-c & m-a)
|
||||
@ -602,8 +603,7 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
|
||||
def clobber(self):
|
||||
"""clobber"""
|
||||
dirs = self.query_abs_dirs()
|
||||
clobber_dirs = (dirs['abs_objdir'], dirs['abs_compare_locales_dir'],
|
||||
dirs['abs_upload_dir'])
|
||||
clobber_dirs = (dirs['abs_objdir'], dirs['abs_upload_dir'])
|
||||
PurgeMixin.clobber(self, always_clobber_dirs=clobber_dirs)
|
||||
|
||||
def pull(self):
|
||||
@ -637,6 +637,8 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
|
||||
self.info("repositories: %s" % repos)
|
||||
self.vcs_checkout_repos(repos, parent_dir=dirs['abs_work_dir'],
|
||||
tag_override=config.get('tag_override'))
|
||||
|
||||
def clone_locales(self):
|
||||
self.pull_locale_source()
|
||||
|
||||
def setup(self):
|
||||
|
@ -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