1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561 |
- /* -*- Mode: C++; tab-width: 8; 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 "mozilla/ArrayUtils.h"
- #include "mozilla/BasicEvents.h"
- #include "DataTransfer.h"
- #include "nsIDOMDocument.h"
- #include "nsISupportsPrimitives.h"
- #include "nsIScriptSecurityManager.h"
- #include "mozilla/dom/DOMStringList.h"
- #include "nsArray.h"
- #include "nsError.h"
- #include "nsIDragService.h"
- #include "nsIClipboard.h"
- #include "nsContentUtils.h"
- #include "nsIContent.h"
- #include "nsIBinaryInputStream.h"
- #include "nsIBinaryOutputStream.h"
- #include "nsIStorageStream.h"
- #include "nsStringStream.h"
- #include "nsCRT.h"
- #include "nsIScriptObjectPrincipal.h"
- #include "nsIScriptContext.h"
- #include "nsIDocument.h"
- #include "nsIScriptGlobalObject.h"
- #include "nsVariant.h"
- #include "mozilla/dom/ContentChild.h"
- #include "mozilla/dom/DataTransferBinding.h"
- #include "mozilla/dom/DataTransferItemList.h"
- #include "mozilla/dom/Directory.h"
- #include "mozilla/dom/Element.h"
- #include "mozilla/dom/FileList.h"
- #include "mozilla/dom/BindingUtils.h"
- #include "mozilla/dom/OSFileSystem.h"
- #include "mozilla/dom/Promise.h"
- #include "nsNetUtil.h"
- #include "nsReadableUtils.h"
- namespace mozilla {
- namespace dom {
- NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer)
- NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mItems)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage)
- NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
- NS_IMPL_CYCLE_COLLECTION_UNLINK_END
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mItems)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
- NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DataTransfer)
- NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransfer)
- NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransfer)
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransfer)
- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
- NS_INTERFACE_MAP_ENTRY(mozilla::dom::DataTransfer)
- NS_INTERFACE_MAP_ENTRY(nsIDOMDataTransfer)
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDataTransfer)
- NS_INTERFACE_MAP_END
- // the size of the array
- const char DataTransfer::sEffects[8][9] = {
- "none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"
- };
- // Used for custom clipboard types.
- enum CustomClipboardTypeId {
- eCustomClipboardTypeId_None,
- eCustomClipboardTypeId_String
- };
- DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
- bool aIsExternal, int32_t aClipboardType)
- : mParent(aParent)
- , mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE)
- , mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
- , mEventMessage(aEventMessage)
- , mCursorState(false)
- , mReadOnly(true)
- , mIsExternal(aIsExternal)
- , mUserCancelled(false)
- , mIsCrossDomainSubFrameDrop(false)
- , mClipboardType(aClipboardType)
- , mDragImageX(0)
- , mDragImageY(0)
- {
- mItems = new DataTransferItemList(this, aIsExternal);
- // For these events, we want to be able to add data to the data transfer, so
- // clear the readonly state. Otherwise, the data is already present. For
- // external usage, cache the data from the native clipboard or drag.
- if (aEventMessage == eCut ||
- aEventMessage == eCopy ||
- aEventMessage == eDragStart) {
- mReadOnly = false;
- } else if (mIsExternal) {
- if (aEventMessage == ePaste) {
- CacheExternalClipboardFormats();
- } else if (aEventMessage >= eDragDropEventFirst &&
- aEventMessage <= eDragDropEventLast) {
- CacheExternalDragFormats();
- }
- }
- }
- DataTransfer::DataTransfer(nsISupports* aParent,
- EventMessage aEventMessage,
- const uint32_t aEffectAllowed,
- bool aCursorState,
- bool aIsExternal,
- bool aUserCancelled,
- bool aIsCrossDomainSubFrameDrop,
- int32_t aClipboardType,
- DataTransferItemList* aItems,
- Element* aDragImage,
- uint32_t aDragImageX,
- uint32_t aDragImageY)
- : mParent(aParent)
- , mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE)
- , mEffectAllowed(aEffectAllowed)
- , mEventMessage(aEventMessage)
- , mCursorState(aCursorState)
- , mReadOnly(true)
- , mIsExternal(aIsExternal)
- , mUserCancelled(aUserCancelled)
- , mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop)
- , mClipboardType(aClipboardType)
- , 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
- // dragstart event is the only time when items are
- // modifiable, but those events should have been using the first constructor
- // above.
- NS_ASSERTION(aEventMessage != eDragStart,
- "invalid event type for DataTransfer constructor");
- }
- DataTransfer::~DataTransfer()
- {}
- // static
- already_AddRefed<DataTransfer>
- DataTransfer::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
- {
- RefPtr<DataTransfer> transfer = new DataTransfer(aGlobal.GetAsSupports(),
- eCopy, /* is external */ false, /* clipboard type */ -1);
- transfer->mEffectAllowed = nsIDragService::DRAGDROP_ACTION_NONE;
- return transfer.forget();
- }
- JSObject*
- DataTransfer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
- {
- return DataTransferBinding::Wrap(aCx, this, aGivenProto);
- }
- NS_IMETHODIMP
- DataTransfer::GetDropEffect(nsAString& aDropEffect)
- {
- nsString dropEffect;
- GetDropEffect(dropEffect);
- aDropEffect = dropEffect;
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::SetDropEffect(const nsAString& aDropEffect)
- {
- // the drop effect can only be 'none', 'copy', 'move' or 'link'.
- for (uint32_t e = 0; e <= nsIDragService::DRAGDROP_ACTION_LINK; e++) {
- if (aDropEffect.EqualsASCII(sEffects[e])) {
- // don't allow copyMove
- if (e != (nsIDragService::DRAGDROP_ACTION_COPY |
- nsIDragService::DRAGDROP_ACTION_MOVE)) {
- mDropEffect = e;
- }
- break;
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::GetEffectAllowed(nsAString& aEffectAllowed)
- {
- nsString effectAllowed;
- GetEffectAllowed(effectAllowed);
- aEffectAllowed = effectAllowed;
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::SetEffectAllowed(const nsAString& aEffectAllowed)
- {
- if (aEffectAllowed.EqualsLiteral("uninitialized")) {
- mEffectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
- return NS_OK;
- }
- static_assert(nsIDragService::DRAGDROP_ACTION_NONE == 0,
- "DRAGDROP_ACTION_NONE constant is wrong");
- static_assert(nsIDragService::DRAGDROP_ACTION_COPY == 1,
- "DRAGDROP_ACTION_COPY constant is wrong");
- static_assert(nsIDragService::DRAGDROP_ACTION_MOVE == 2,
- "DRAGDROP_ACTION_MOVE constant is wrong");
- static_assert(nsIDragService::DRAGDROP_ACTION_LINK == 4,
- "DRAGDROP_ACTION_LINK constant is wrong");
- for (uint32_t e = 0; e < ArrayLength(sEffects); e++) {
- if (aEffectAllowed.EqualsASCII(sEffects[e])) {
- mEffectAllowed = e;
- break;
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::GetDropEffectInt(uint32_t* aDropEffect)
- {
- *aDropEffect = mDropEffect;
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::SetDropEffectInt(uint32_t aDropEffect)
- {
- mDropEffect = aDropEffect;
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::GetEffectAllowedInt(uint32_t* aEffectAllowed)
- {
- *aEffectAllowed = mEffectAllowed;
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::SetEffectAllowedInt(uint32_t aEffectAllowed)
- {
- mEffectAllowed = aEffectAllowed;
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
- {
- *aUserCancelled = MozUserCancelled();
- return NS_OK;
- }
- already_AddRefed<FileList>
- DataTransfer::GetFiles(nsIPrincipal& aSubjectPrincipal,
- ErrorResult& aRv)
- {
- return mItems->Files(&aSubjectPrincipal);
- }
- NS_IMETHODIMP
- DataTransfer::GetFiles(nsIDOMFileList** aFileList)
- {
- if (!aFileList) {
- return NS_ERROR_FAILURE;
- }
- // The XPCOM interface is only avaliable to system code, and thus we can
- // assume the system principal. This is consistent with the previous behavour
- // of this function, which also assumed the system principal.
- //
- // This code is also called from C++ code, which expects it to have a System
- // Principal, and thus the SubjectPrincipal cannot be used.
- RefPtr<FileList> files = mItems->Files(nsContentUtils::GetSystemPrincipal());
- files.forget(aFileList);
- return NS_OK;
- }
- void
- DataTransfer::GetTypes(nsTArray<nsString>& aTypes,
- nsIPrincipal& aSubjectPrincipal) const
- {
- // When called from bindings, aTypes will be empty, but since we might have
- // Gecko-internal callers too, clear it to be safe.
- aTypes.Clear();
-
- const nsTArray<RefPtr<DataTransferItem>>* items = mItems->MozItemsAt(0);
- if (NS_WARN_IF(!items)) {
- return;
- }
- for (uint32_t i = 0; i < items->Length(); i++) {
- DataTransferItem* item = items->ElementAt(i);
- MOZ_ASSERT(item);
- if (item->ChromeOnly() && !nsContentUtils::IsSystemPrincipal(&aSubjectPrincipal)) {
- continue;
- }
- // NOTE: The reason why we get the internal type here is because we want
- // kFileMime to appear in the types list for backwards compatibility
- // reasons.
- nsAutoString type;
- item->GetInternalType(type);
- if (item->Kind() == DataTransferItem::KIND_STRING || type.EqualsASCII(kFileMime)) {
- // If the entry has kind KIND_STRING, we want to add it to the list.
- aTypes.AppendElement(type);
- }
- }
- for (uint32_t i = 0; i < mItems->Length(); ++i) {
- bool found = false;
- DataTransferItem* item = mItems->IndexedGetter(i, found);
- MOZ_ASSERT(found);
- if (item->Kind() != DataTransferItem::KIND_FILE) {
- continue;
- }
- aTypes.AppendElement(NS_LITERAL_STRING("Files"));
- break;
- }
- }
- void
- DataTransfer::GetData(const nsAString& aFormat, nsAString& aData,
- nsIPrincipal& aSubjectPrincipal,
- ErrorResult& aRv)
- {
- // return an empty string if data for the format was not found
- aData.Truncate();
- nsCOMPtr<nsIVariant> data;
- nsresult rv =
- GetDataAtInternal(aFormat, 0, &aSubjectPrincipal,
- getter_AddRefs(data));
- if (NS_FAILED(rv)) {
- if (rv != NS_ERROR_DOM_INDEX_SIZE_ERR) {
- aRv.Throw(rv);
- }
- return;
- }
- if (data) {
- nsAutoString stringdata;
- data->GetAsAString(stringdata);
- // for the URL type, parse out the first URI from the list. The URIs are
- // separated by newlines
- nsAutoString lowercaseFormat;
- nsContentUtils::ASCIIToLower(aFormat, lowercaseFormat);
- if (lowercaseFormat.EqualsLiteral("url")) {
- int32_t lastidx = 0, idx;
- int32_t length = stringdata.Length();
- while (lastidx < length) {
- idx = stringdata.FindChar('\n', lastidx);
- // lines beginning with # are comments
- if (stringdata[lastidx] == '#') {
- if (idx == -1) {
- break;
- }
- }
- else {
- if (idx == -1) {
- aData.Assign(Substring(stringdata, lastidx));
- } else {
- aData.Assign(Substring(stringdata, lastidx, idx - lastidx));
- }
- aData = nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(aData,
- true);
- return;
- }
- lastidx = idx + 1;
- }
- }
- else {
- aData = stringdata;
- }
- }
- }
- void
- DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData,
- nsIPrincipal& aSubjectPrincipal,
- ErrorResult& aRv)
- {
- RefPtr<nsVariantCC> variant = new nsVariantCC();
- variant->SetAsAString(aData);
- aRv = SetDataAtInternal(aFormat, variant, 0, &aSubjectPrincipal);
- }
- void
- DataTransfer::ClearData(const Optional<nsAString>& aFormat,
- nsIPrincipal& aSubjectPrincipal,
- ErrorResult& aRv)
- {
- if (mReadOnly) {
- aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
- return;
- }
- if (MozItemCount() == 0) {
- return;
- }
- if (aFormat.WasPassed()) {
- MozClearDataAtHelper(aFormat.Value(), 0, aSubjectPrincipal, aRv);
- } else {
- MozClearDataAtHelper(EmptyString(), 0, aSubjectPrincipal, aRv);
- }
- }
- NS_IMETHODIMP
- DataTransfer::GetMozItemCount(uint32_t* aCount)
- {
- *aCount = MozItemCount();
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::GetMozCursor(nsAString& aCursorState)
- {
- nsString cursor;
- GetMozCursor(cursor);
- aCursorState = cursor;
- return NS_OK;
- }
- NS_IMETHODIMP
- DataTransfer::SetMozCursor(const nsAString& aCursorState)
- {
- // Lock the cursor to an arrow during the drag.
- mCursorState = aCursorState.EqualsLiteral("default");
- return NS_OK;
- }
- already_AddRefed<nsINode>
- DataTransfer::GetMozSourceNode()
- {
- nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
- if (!dragSession) {
- return nullptr;
- }
- nsCOMPtr<nsIDOMNode> sourceNode;
- dragSession->GetSourceNode(getter_AddRefs(sourceNode));
- nsCOMPtr<nsINode> node = do_QueryInterface(sourceNode);
- if (node && !nsContentUtils::LegacyIsCallerNativeCode()
- && !nsContentUtils::CanCallerAccess(node)) {
- return nullptr;
- }
- return node.forget();
- }
- NS_IMETHODIMP
- DataTransfer::GetMozSourceNode(nsIDOMNode** aSourceNode)
- {
- nsCOMPtr<nsINode> sourceNode = GetMozSourceNode();
- if (!sourceNode) {
- *aSourceNode = nullptr;
- return NS_OK;
- }
- return CallQueryInterface(sourceNode, aSourceNode);
- }
- already_AddRefed<DOMStringList>
- DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv) const
- {
- // Only the first item is valid for clipboard events
- if (aIndex > 0 &&
- (mEventMessage == eCut || mEventMessage == eCopy ||
- mEventMessage == ePaste)) {
- aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
- return nullptr;
- }
- 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);
- bool addFile = false;
- for (uint32_t i = 0; i < items.Length(); i++) {
- if (items[i]->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
- continue;
- }
- // NOTE: The reason why we get the internal type here is because we want
- // kFileMime to appear in the types list for backwards compatibility
- // reasons.
- nsAutoString type;
- items[i]->GetInternalType(type);
- if (NS_WARN_IF(!types->Add(type))) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
- if (items[i]->Kind() == DataTransferItem::KIND_FILE) {
- addFile = true;
- }
- }
- if (addFile) {
- types->Add(NS_LITERAL_STRING("Files"));
- }
- }
- return types.forget();
- }
- NS_IMETHODIMP
- DataTransfer::MozTypesAt(uint32_t aIndex, nsISupports** aTypes)
- {
- ErrorResult rv;
- RefPtr<DOMStringList> types = MozTypesAt(aIndex, rv);
- types.forget(aTypes);
- return rv.StealNSResult();
- }
- nsresult
- DataTransfer::GetDataAtNoSecurityCheck(const nsAString& aFormat,
- uint32_t aIndex,
- nsIVariant** aData)
- {
- return GetDataAtInternal(aFormat, aIndex,
- nsContentUtils::GetSystemPrincipal(), aData);
- }
- nsresult
- DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
- nsIPrincipal* aSubjectPrincipal,
- nsIVariant** aData)
- {
- *aData = nullptr;
- if (aFormat.IsEmpty()) {
- return NS_OK;
- }
- if (aIndex >= MozItemCount()) {
- return NS_ERROR_DOM_INDEX_SIZE_ERR;
- }
- // Only the first item is valid for clipboard events
- if (aIndex > 0 &&
- (mEventMessage == eCut || mEventMessage == eCopy ||
- mEventMessage == ePaste)) {
- return NS_ERROR_DOM_INDEX_SIZE_ERR;
- }
- nsAutoString format;
- GetRealFormat(aFormat, format);
- MOZ_ASSERT(aSubjectPrincipal);
- RefPtr<DataTransferItem> item = mItems->MozItemByTypeAt(format, aIndex);
- if (!item) {
- // The index exists but there's no data for the specified format, in this
- // case we just return undefined
- return NS_OK;
- }
- // If we have chrome only content, and we aren't chrome, don't allow access
- if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal) && item->ChromeOnly()) {
- return NS_OK;
- }
- // DataTransferItem::Data() handles the principal checks
- ErrorResult result;
- nsCOMPtr<nsIVariant> data = item->Data(aSubjectPrincipal, result);
- if (NS_WARN_IF(!data || result.Failed())) {
- return result.StealNSResult();
- }
- data.forget(aData);
- return NS_OK;
- }
- void
- DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
- uint32_t aIndex,
- JS::MutableHandle<JS::Value> aRetval,
- nsIPrincipal& aSubjectPrincipal,
- mozilla::ErrorResult& aRv)
- {
- nsCOMPtr<nsIVariant> data;
- aRv = GetDataAtInternal(aFormat, aIndex, &aSubjectPrincipal,
- getter_AddRefs(data));
- if (aRv.Failed()) {
- return;
- }
- if (!data) {
- aRetval.setNull();
- return;
- }
- JS::Rooted<JS::Value> result(aCx);
- if (!VariantToJsval(aCx, data, aRetval)) {
- aRv = NS_ERROR_FAILURE;
- return;
- }
- }
- /* static */ bool
- DataTransfer::PrincipalMaySetData(const nsAString& aType,
- nsIVariant* aData,
- nsIPrincipal* aPrincipal)
- {
- if (!nsContentUtils::IsSystemPrincipal(aPrincipal)) {
- DataTransferItem::eKind kind = DataTransferItem::KindFromData(aData);
- if (kind == DataTransferItem::KIND_OTHER) {
- NS_WARNING("Disallowing adding non string/file types to DataTransfer");
- return false;
- }
- if (aType.EqualsASCII(kFileMime) ||
- aType.EqualsASCII(kFilePromiseMime)) {
- NS_WARNING("Disallowing adding x-moz-file or x-moz-file-promize types to DataTransfer");
- return false;
- }
-
- // Disallow content from creating x-moz-place flavors, so that it cannot
- // create fake Places smart queries exposing user data.
- if (StringBeginsWith(aType, NS_LITERAL_STRING("text/x-moz-place"))) {
- NS_WARNING("Disallowing adding moz-place types to DataTransfer");
- return false;
- }
- }
- return true;
- }
- void
- DataTransfer::TypesListMayHaveChanged()
- {
- DataTransferBinding::ClearCachedTypesValue(this);
- }
- nsresult
- DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
- uint32_t aIndex,
- nsIPrincipal* aSubjectPrincipal)
- {
- if (aFormat.IsEmpty()) {
- return NS_OK;
- }
- if (mReadOnly) {
- return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
- }
- // Specifying an index less than the current length will replace an existing
- // item. Specifying an index equal to the current length will add a new item.
- if (aIndex > MozItemCount()) {
- return NS_ERROR_DOM_INDEX_SIZE_ERR;
- }
- // Only the first item is valid for clipboard events
- if (aIndex > 0 &&
- (mEventMessage == eCut || mEventMessage == eCopy ||
- mEventMessage == ePaste)) {
- return NS_ERROR_DOM_INDEX_SIZE_ERR;
- }
- // Don't allow the custom type to be assigned.
- if (aFormat.EqualsLiteral(kCustomTypesMime)) {
- return NS_ERROR_TYPE_ERR;
- }
- if (!PrincipalMaySetData(aFormat, aData, aSubjectPrincipal)) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- return SetDataWithPrincipal(aFormat, aData, aIndex, aSubjectPrincipal);
- }
- void
- DataTransfer::MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
- JS::Handle<JS::Value> aData, uint32_t aIndex,
- nsIPrincipal& aSubjectPrincipal,
- ErrorResult& aRv)
- {
- nsCOMPtr<nsIVariant> data;
- aRv = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData,
- getter_AddRefs(data));
- if (!aRv.Failed()) {
- aRv = SetDataAtInternal(aFormat, data, aIndex, &aSubjectPrincipal);
- }
- }
- void
- DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
- nsIPrincipal& aSubjectPrincipal,
- ErrorResult& aRv)
- {
- if (mReadOnly) {
- aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
- return;
- }
- if (aIndex >= MozItemCount()) {
- aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
- return;
- }
- // Only the first item is valid for clipboard events
- if (aIndex > 0 &&
- (mEventMessage == eCut || mEventMessage == eCopy ||
- mEventMessage == ePaste)) {
- aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
- return;
- }
- MozClearDataAtHelper(aFormat, aIndex, aSubjectPrincipal, aRv);
- // If we just cleared the 0-th index, and there are still more than 1 indexes
- // remaining, MozClearDataAt should cause the 1st index to become the 0th
- // index. This should _only_ happen when the MozClearDataAt function is
- // explicitly called by script, as this behavior is inconsistent with spec.
- // (however, so is the MozClearDataAt API)
- if (aIndex == 0 && mItems->MozItemCount() > 1 &&
- mItems->MozItemsAt(0)->Length() == 0) {
- mItems->PopIndexZero();
- }
- }
- void
- DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
- nsIPrincipal& aSubjectPrincipal,
- ErrorResult& aRv)
- {
- MOZ_ASSERT(!mReadOnly);
- MOZ_ASSERT(aIndex < MozItemCount());
- MOZ_ASSERT(aIndex == 0 ||
- (mEventMessage != eCut && mEventMessage != eCopy &&
- mEventMessage != ePaste));
- nsAutoString format;
- GetRealFormat(aFormat, format);
- mItems->MozRemoveByTypeAt(format, aIndex, aSubjectPrincipal, aRv);
- }
- void
- DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY,
- ErrorResult& aRv)
- {
- if (mReadOnly) {
- aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
- return;
- }
- mDragImage = &aImage;
- mDragImageX = aX;
- mDragImageY = aY;
- }
- NS_IMETHODIMP
- DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY)
- {
- ErrorResult rv;
- nsCOMPtr<Element> image = do_QueryInterface(aImage);
- if (image) {
- SetDragImage(*image, aX, aY, rv);
- }
- return rv.StealNSResult();
- }
- already_AddRefed<Promise>
- DataTransfer::GetFilesAndDirectories(nsIPrincipal& aSubjectPrincipal,
- ErrorResult& aRv)
- {
- nsCOMPtr<nsINode> parentNode = do_QueryInterface(mParent);
- if (!parentNode) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
- nsCOMPtr<nsIGlobalObject> global = parentNode->OwnerDoc()->GetScopeObject();
- MOZ_ASSERT(global);
- if (!global) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
- RefPtr<Promise> p = Promise::Create(global, aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
- RefPtr<FileList> files = mItems->Files(&aSubjectPrincipal);
- if (NS_WARN_IF(!files)) {
- return nullptr;
- }
- Sequence<RefPtr<File>> filesSeq;
- files->ToSequence(filesSeq, aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
- p->MaybeResolve(filesSeq);
- return p.forget();
- }
- already_AddRefed<Promise>
- DataTransfer::GetFiles(bool aRecursiveFlag,
- nsIPrincipal& aSubjectPrincipal,
- ErrorResult& aRv)
- {
- // Currently we don't support directories.
- return GetFilesAndDirectories(aSubjectPrincipal, aRv);
- }
- void
- DataTransfer::AddElement(Element& aElement, ErrorResult& aRv)
- {
- if (mReadOnly) {
- aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
- return;
- }
- mDragTarget = &aElement;
- }
- NS_IMETHODIMP
- DataTransfer::AddElement(nsIDOMElement* aElement)
- {
- NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
- nsCOMPtr<Element> element = do_QueryInterface(aElement);
- NS_ENSURE_TRUE(element, NS_ERROR_INVALID_ARG);
- ErrorResult rv;
- AddElement(*element, rv);
- return rv.StealNSResult();
- }
- nsresult
- DataTransfer::Clone(nsISupports* aParent, EventMessage aEventMessage,
- bool aUserCancelled, bool aIsCrossDomainSubFrameDrop,
- DataTransfer** aNewDataTransfer)
- {
- RefPtr<DataTransfer> newDataTransfer =
- new DataTransfer(aParent, aEventMessage, mEffectAllowed, mCursorState,
- mIsExternal, aUserCancelled, aIsCrossDomainSubFrameDrop,
- mClipboardType, mItems, mDragImage, mDragImageX,
- mDragImageY);
- newDataTransfer.forget(aNewDataTransfer);
- return NS_OK;
- }
- already_AddRefed<nsIArray>
- DataTransfer::GetTransferables(nsIDOMNode* aDragTarget)
- {
- MOZ_ASSERT(aDragTarget);
- nsCOMPtr<nsINode> dragNode = do_QueryInterface(aDragTarget);
- if (!dragNode) {
- return nullptr;
- }
- nsIDocument* doc = dragNode->GetComposedDoc();
- if (!doc) {
- return nullptr;
- }
- return GetTransferables(doc->GetLoadContext());
- }
- already_AddRefed<nsIArray>
- DataTransfer::GetTransferables(nsILoadContext* aLoadContext)
- {
- nsCOMPtr<nsIMutableArray> transArray = nsArray::Create();
- if (!transArray) {
- return nullptr;
- }
- uint32_t count = MozItemCount();
- for (uint32_t i = 0; i < count; i++) {
- nsCOMPtr<nsITransferable> transferable = GetTransferable(i, aLoadContext);
- if (transferable) {
- transArray->AppendElement(transferable, /*weak =*/ false);
- }
- }
- return transArray.forget();
- }
- already_AddRefed<nsITransferable>
- DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
- {
- if (aIndex >= MozItemCount()) {
- return nullptr;
- }
- const nsTArray<RefPtr<DataTransferItem>>& item = *mItems->MozItemsAt(aIndex);
- uint32_t count = item.Length();
- if (!count) {
- return nullptr;
- }
- nsCOMPtr<nsITransferable> transferable =
- do_CreateInstance("@mozilla.org/widget/transferable;1");
- if (!transferable) {
- return nullptr;
- }
- transferable->Init(aLoadContext);
- nsCOMPtr<nsIStorageStream> storageStream;
- nsCOMPtr<nsIBinaryOutputStream> stream;
- bool added = false;
- bool handlingCustomFormats = true;
- // When writing the custom data, we need to ensure that there is sufficient
- // space for a (uint32_t) data ending type, and the null byte character at
- // the end of the nsCString. We claim that space upfront and store it in
- // baseLength. This value will be set to zero if a write error occurs
- // indicating that the data and length are no longer valid.
- const uint32_t baseLength = sizeof(uint32_t) + 1;
- uint32_t totalCustomLength = baseLength;
- const char* knownFormats[] = {
- kTextMime, kHTMLMime, kNativeHTMLMime, kRTFMime,
- kURLMime, kURLDataMime, kURLDescriptionMime, kURLPrivateMime,
- kPNGImageMime, kJPEGImageMime, kGIFImageMime, kNativeImageMime,
- kFileMime, kFilePromiseMime, kFilePromiseURLMime,
- kFilePromiseDestFilename, kFilePromiseDirectoryMime,
- kMozTextInternal, kHTMLContext, kHTMLInfo };
- /*
- * Two passes are made here to iterate over all of the types. First, look for
- * any types that are not in the list of known types. For this pass,
- * handlingCustomFormats will be true. Data that corresponds to unknown types
- * will be pulled out and inserted into a single type (kCustomTypesMime) by
- * writing the data into a stream.
- *
- * The second pass will iterate over the formats looking for known types.
- * These are added as is. The unknown types are all then inserted as a single
- * type (kCustomTypesMime) in the same position of the first custom type. This
- * model is used to maintain the format order as best as possible.
- *
- * The format of the kCustomTypesMime type is one or more of the following
- * stored sequentially:
- * <32-bit> type (only none or string is supported)
- * <32-bit> length of format
- * <wide string> format
- * <32-bit> length of data
- * <wide string> data
- * A type of eCustomClipboardTypeId_None ends the list, without any following
- * data.
- */
- do {
- for (uint32_t f = 0; f < count; f++) {
- RefPtr<DataTransferItem> formatitem = item[f];
- nsCOMPtr<nsIVariant> variant = formatitem->DataNoSecurityCheck();
- if (!variant) { // skip empty items
- continue;
- }
- nsAutoString type;
- formatitem->GetInternalType(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])) {
- isCustomFormat = false;
- break;
- }
- }
- uint32_t lengthInBytes;
- nsCOMPtr<nsISupports> convertedData;
- if (handlingCustomFormats) {
- if (!ConvertFromVariant(variant, getter_AddRefs(convertedData),
- &lengthInBytes)) {
- continue;
- }
- // When handling custom types, add the data to the stream if this is a
- // custom type. If totalCustomLength is 0, then a write error occurred
- // on a previous item, so ignore any others.
- if (isCustomFormat && totalCustomLength > 0) {
- // If it isn't a string, just ignore it. The dataTransfer is cached in
- // the drag sesion during drag-and-drop, so non-strings will be
- // available when dragging locally.
- nsCOMPtr<nsISupportsString> str(do_QueryInterface(convertedData));
- if (str) {
- nsAutoString data;
- str->GetData(data);
- if (!stream) {
- // Create a storage stream to write to.
- NS_NewStorageStream(1024, UINT32_MAX, getter_AddRefs(storageStream));
- nsCOMPtr<nsIOutputStream> outputStream;
- storageStream->GetOutputStream(0, getter_AddRefs(outputStream));
- stream = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
- stream->SetOutputStream(outputStream);
- }
- CheckedInt<uint32_t> formatLength =
- CheckedInt<uint32_t>(type.Length()) * sizeof(nsString::char_type);
- // The total size of the stream is the format length, the data
- // length, two integers to hold the lengths and one integer for
- // the string flag. Guard against large data by ignoring any that
- // don't fit.
- CheckedInt<uint32_t> newSize = formatLength + totalCustomLength +
- lengthInBytes + (sizeof(uint32_t) * 3);
- if (newSize.isValid()) {
- // If a write error occurs, set totalCustomLength to 0 so that
- // further processing gets ignored.
- nsresult rv = stream->Write32(eCustomClipboardTypeId_String);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- totalCustomLength = 0;
- continue;
- }
- rv = stream->Write32(formatLength.value());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- totalCustomLength = 0;
- continue;
- }
- rv = stream->WriteBytes((const char *)type.get(), formatLength.value());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- totalCustomLength = 0;
- continue;
- }
- rv = stream->Write32(lengthInBytes);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- totalCustomLength = 0;
- continue;
- }
- rv = stream->WriteBytes((const char *)data.get(), lengthInBytes);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- totalCustomLength = 0;
- continue;
- }
- totalCustomLength = newSize.value();
- }
- }
- }
- } else if (isCustomFormat && stream) {
- // This is the second pass of the loop (handlingCustomFormats is false).
- // When encountering the first custom format, append all of the stream
- // at this position. If totalCustomLength is 0 indicating a write error
- // occurred, or no data has been added to it, don't output anything,
- if (totalCustomLength > baseLength) {
- // Write out an end of data terminator.
- nsresult rv = stream->Write32(eCustomClipboardTypeId_None);
- if (NS_SUCCEEDED(rv)) {
- nsCOMPtr<nsIInputStream> inputStream;
- storageStream->NewInputStream(0, getter_AddRefs(inputStream));
- RefPtr<nsStringBuffer> stringBuffer =
- nsStringBuffer::Alloc(totalCustomLength);
- // Subtract off the null terminator when reading.
- totalCustomLength--;
- // Read the data from the stream and add a null-terminator as
- // ToString needs it.
- uint32_t amountRead;
- rv = inputStream->Read(static_cast<char*>(stringBuffer->Data()),
- totalCustomLength, &amountRead);
- if (NS_SUCCEEDED(rv)) {
- static_cast<char*>(stringBuffer->Data())[amountRead] = 0;
- nsCString str;
- stringBuffer->ToString(totalCustomLength, str);
- nsCOMPtr<nsISupportsCString>
- strSupports(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
- strSupports->SetData(str);
- nsresult rv = transferable->SetTransferData(kCustomTypesMime,
- strSupports,
- totalCustomLength);
- if (NS_FAILED(rv)) {
- return nullptr;
- }
- added = true;
- }
- }
- }
- // Clear the stream so it doesn't get used again.
- stream = nullptr;
- } else {
- // This is the second pass of the loop and a known type is encountered.
- // Add it as is.
- if (!ConvertFromVariant(variant, getter_AddRefs(convertedData),
- &lengthInBytes)) {
- continue;
- }
- // The underlying drag code uses text/unicode, so use that instead of
- // text/plain
- const char* format;
- NS_ConvertUTF16toUTF8 utf8format(type);
- if (utf8format.EqualsLiteral(kTextMime)) {
- format = kUnicodeMime;
- } else {
- format = utf8format.get();
- }
- // If a converter is set for a format, set the converter for the
- // transferable and don't add the item
- nsCOMPtr<nsIFormatConverter> converter =
- do_QueryInterface(convertedData);
- if (converter) {
- transferable->AddDataFlavor(format);
- transferable->SetConverter(converter);
- continue;
- }
- nsresult rv = transferable->SetTransferData(format, convertedData,
- lengthInBytes);
- if (NS_FAILED(rv)) {
- return nullptr;
- }
- added = true;
- }
- }
- handlingCustomFormats = !handlingCustomFormats;
- } while (!handlingCustomFormats);
- // only return the transferable if data was successfully added to it
- if (added) {
- return transferable.forget();
- }
- return nullptr;
- }
- bool
- DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
- nsISupports** aSupports,
- uint32_t* aLength) const
- {
- *aSupports = nullptr;
- *aLength = 0;
- uint16_t type;
- aVariant->GetDataType(&type);
- if (type == nsIDataType::VTYPE_INTERFACE ||
- type == nsIDataType::VTYPE_INTERFACE_IS) {
- nsCOMPtr<nsISupports> data;
- if (NS_FAILED(aVariant->GetAsISupports(getter_AddRefs(data)))) {
- return false;
- }
- nsCOMPtr<nsIFlavorDataProvider> fdp = do_QueryInterface(data);
- if (fdp) {
- // for flavour data providers, use kFlavorHasDataProvider (which has the
- // value 0) as the length.
- fdp.forget(aSupports);
- *aLength = nsITransferable::kFlavorHasDataProvider;
- }
- else {
- // wrap the item in an nsISupportsInterfacePointer
- nsCOMPtr<nsISupportsInterfacePointer> ptrSupports =
- do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID);
- if (!ptrSupports) {
- return false;
- }
- ptrSupports->SetData(data);
- ptrSupports.forget(aSupports);
- *aLength = sizeof(nsISupportsInterfacePointer *);
- }
- return true;
- }
- char16_t* chrs;
- uint32_t len = 0;
- nsresult rv = aVariant->GetAsWStringWithSize(&len, &chrs);
- if (NS_FAILED(rv)) {
- return false;
- }
- nsAutoString str;
- str.Adopt(chrs, len);
- nsCOMPtr<nsISupportsString>
- strSupports(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
- if (!strSupports) {
- return false;
- }
- strSupports->SetData(str);
- strSupports.forget(aSupports);
- // each character is two bytes
- *aLength = str.Length() << 1;
- return true;
- }
- void
- DataTransfer::ClearAll()
- {
- mItems->ClearAllItems();
- }
- uint32_t
- DataTransfer::MozItemCount() const
- {
- return mItems->MozItemCount();
- }
- nsresult
- DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
- nsIVariant* aData,
- uint32_t aIndex,
- nsIPrincipal* aPrincipal)
- {
- nsAutoString format;
- GetRealFormat(aFormat, format);
- ErrorResult rv;
- RefPtr<DataTransferItem> item =
- mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal,
- /* aInsertOnly = */ false,
- /* aHidden= */ false,
- rv);
- return rv.StealNSResult();
- }
- void
- DataTransfer::SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat,
- nsIVariant* aData,
- uint32_t aIndex,
- nsIPrincipal* aPrincipal,
- bool aHidden)
- {
- if (aFormat.EqualsLiteral(kCustomTypesMime)) {
- FillInExternalCustomTypes(aData, aIndex, aPrincipal);
- } else {
- nsAutoString format;
- GetRealFormat(aFormat, format);
- ErrorResult rv;
- RefPtr<DataTransferItem> item =
- mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal,
- /* aInsertOnly = */ false, aHidden, rv);
- if (NS_WARN_IF(rv.Failed())) {
- rv.SuppressException();
- }
- }
- }
- void
- DataTransfer::GetRealFormat(const nsAString& aInFormat,
- nsAString& aOutFormat) const
- {
- // treat text/unicode as equivalent to text/plain
- nsAutoString lowercaseFormat;
- nsContentUtils::ASCIIToLower(aInFormat, lowercaseFormat);
- if (lowercaseFormat.EqualsLiteral("text") ||
- lowercaseFormat.EqualsLiteral("text/unicode")) {
- aOutFormat.AssignLiteral("text/plain");
- return;
- }
- if (lowercaseFormat.EqualsLiteral("url")) {
- aOutFormat.AssignLiteral("text/uri-list");
- return;
- }
- aOutFormat.Assign(lowercaseFormat);
- }
- nsresult
- DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex,
- nsIPrincipal* aPrincipal, bool aHidden)
- {
- 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;
- }
- 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;
- }
- 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;
- }
- void
- DataTransfer::CacheExternalDragFormats()
- {
- // Called during the constructor to cache the formats available from an
- // external drag. The data associated with each format will be set to null.
- // This data will instead only be retrieved in FillInExternalDragData when
- // asked for, as it may be time consuming for the source application to
- // generate it.
- nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
- if (!dragSession) {
- return;
- }
- // make sure that the system principal is used for external drags
- nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
- nsCOMPtr<nsIPrincipal> sysPrincipal;
- ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
- // 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.
- // NOTE: kFileMime must have index 0
- const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime,
- kUnicodeMime, kPNGImageMime };
- 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);
- if (supported) {
- FillInExternalCustomTypes(c, sysPrincipal);
- }
- for (uint32_t f = 0; f < ArrayLength(formats); f++) {
- // IsDataFlavorSupported doesn't take an index as an argument and just
- // checks if any of the items support a particular flavor, even though
- // the GetData method does take an index. Here, we just assume that
- // every item being dragged has the same set of flavors.
- bool supported;
- dragSession->IsDataFlavorSupported(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(formats[f], c, sysPrincipal, /* hidden = */ f && hasFileData);
- }
- }
- }
- }
- void
- DataTransfer::CacheExternalClipboardFormats()
- {
- NS_ASSERTION(mEventMessage == ePaste,
- "caching clipboard data for invalid event");
- // Called during the constructor for paste events to cache the formats
- // available on the clipboard. As with CacheExternalDragFormats, the
- // data will only be retrieved when needed.
- nsCOMPtr<nsIClipboard> clipboard =
- do_GetService("@mozilla.org/widget/clipboard;1");
- if (!clipboard || mClipboardType < 0) {
- return;
- }
- nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
- 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);
- // We will be ignoring any application/x-moz-file files found in the paste
- // datatransfer within e10s, as they will fail to be sent over IPC. Because of
- // that, we will unset hasFileData, whether or not it would have been set.
- // (bug 1308007)
- if (XRE_IsContentProcess()) {
- hasFileData = false;
- }
- // 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: kCustomTypesMime must have index 0, kFileMime index 1
- const char* formats[] = { kCustomTypesMime, kFileMime, kHTMLMime, kRTFMime,
- kURLMime, kURLDataMime, kUnicodeMime, kPNGImageMime };
- for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) {
- // check each format one at a time
- bool supported;
- clipboard->HasDataMatchingFlavors(&(formats[f]), 1, mClipboardType,
- &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) {
- if (f == 0) {
- FillInExternalCustomTypes(0, sysPrincipal);
- } else {
- // In non-e10s we support pasting files from explorer.exe.
- // Unfortunately, we fail to send that data over IPC in e10s, so we
- // don't want to add the item to the DataTransfer and end up producing a
- // null `application/x-moz-file`. (bug 1308007)
- if (XRE_IsContentProcess() && f == 1) {
- continue;
- }
- // 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);
- }
- }
- }
- }
- 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();
- }
- }
- }
- }
- void
- DataTransfer::FillInExternalCustomTypes(uint32_t aIndex,
- nsIPrincipal* aPrincipal)
- {
- RefPtr<DataTransferItem> item = new DataTransferItem(this,
- NS_LITERAL_STRING(kCustomTypesMime),
- DataTransferItem::KIND_STRING);
- item->SetIndex(aIndex);
- nsCOMPtr<nsIVariant> variant = item->DataNoSecurityCheck();
- if (!variant) {
- return;
- }
- FillInExternalCustomTypes(variant, aIndex, aPrincipal);
- }
- void
- DataTransfer::FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex,
- nsIPrincipal* aPrincipal)
- {
- char* chrs;
- uint32_t len = 0;
- nsresult rv = aData->GetAsStringWithSize(&len, &chrs);
- if (NS_FAILED(rv)) {
- return;
- }
- nsAutoCString str;
- str.Adopt(chrs, len);
- nsCOMPtr<nsIInputStream> stringStream;
- NS_NewCStringInputStream(getter_AddRefs(stringStream), str);
- nsCOMPtr<nsIBinaryInputStream> stream =
- do_CreateInstance("@mozilla.org/binaryinputstream;1");
- if (!stream) {
- return;
- }
- rv = stream->SetInputStream(stringStream);
- NS_ENSURE_SUCCESS_VOID(rv);
- uint32_t type;
- do {
- rv = stream->Read32(&type);
- NS_ENSURE_SUCCESS_VOID(rv);
- if (type == eCustomClipboardTypeId_String) {
- uint32_t formatLength;
- rv = stream->Read32(&formatLength);
- NS_ENSURE_SUCCESS_VOID(rv);
- char* formatBytes;
- rv = stream->ReadBytes(formatLength, &formatBytes);
- NS_ENSURE_SUCCESS_VOID(rv);
- nsAutoString format;
- format.Adopt(reinterpret_cast<char16_t*>(formatBytes),
- formatLength / sizeof(char16_t));
- uint32_t dataLength;
- rv = stream->Read32(&dataLength);
- NS_ENSURE_SUCCESS_VOID(rv);
- char* dataBytes;
- rv = stream->ReadBytes(dataLength, &dataBytes);
- NS_ENSURE_SUCCESS_VOID(rv);
- nsAutoString data;
- data.Adopt(reinterpret_cast<char16_t*>(dataBytes),
- dataLength / sizeof(char16_t));
- RefPtr<nsVariantCC> variant = new nsVariantCC();
- rv = variant->SetAsAString(data);
- NS_ENSURE_SUCCESS_VOID(rv);
- SetDataWithPrincipal(format, variant, aIndex, aPrincipal);
- }
- } while (type != eCustomClipboardTypeId_None);
- }
- } // namespace dom
- } // namespace mozilla
|