1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/events/DataTransfer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1287 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "mozilla/ArrayUtils.h" 1.11 +#include "mozilla/BasicEvents.h" 1.12 + 1.13 +#include "DataTransfer.h" 1.14 + 1.15 +#include "nsIDOMDocument.h" 1.16 +#include "nsIVariant.h" 1.17 +#include "nsISupportsPrimitives.h" 1.18 +#include "nsIScriptSecurityManager.h" 1.19 +#include "mozilla/dom/DOMStringList.h" 1.20 +#include "nsError.h" 1.21 +#include "nsIDragService.h" 1.22 +#include "nsIClipboard.h" 1.23 +#include "nsContentUtils.h" 1.24 +#include "nsIContent.h" 1.25 +#include "nsCRT.h" 1.26 +#include "nsIScriptObjectPrincipal.h" 1.27 +#include "nsIScriptContext.h" 1.28 +#include "nsIDocument.h" 1.29 +#include "nsIScriptGlobalObject.h" 1.30 +#include "mozilla/dom/DataTransferBinding.h" 1.31 +#include "mozilla/dom/Element.h" 1.32 +#include "mozilla/dom/BindingUtils.h" 1.33 + 1.34 +namespace mozilla { 1.35 +namespace dom { 1.36 + 1.37 +NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer) 1.38 + 1.39 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer) 1.40 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) 1.41 + if (tmp->mFiles) { 1.42 + tmp->mFiles->Disconnect(); 1.43 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles) 1.44 + } 1.45 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget) 1.46 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage) 1.47 + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 1.48 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.49 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer) 1.50 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) 1.51 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles) 1.52 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget) 1.53 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage) 1.54 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.55 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.56 +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DataTransfer) 1.57 + 1.58 +NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransfer) 1.59 +NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransfer) 1.60 + 1.61 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransfer) 1.62 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.63 + NS_INTERFACE_MAP_ENTRY(mozilla::dom::DataTransfer) 1.64 + NS_INTERFACE_MAP_ENTRY(nsIDOMDataTransfer) 1.65 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDataTransfer) 1.66 +NS_INTERFACE_MAP_END 1.67 + 1.68 +// the size of the array 1.69 +const char DataTransfer::sEffects[8][9] = { 1.70 + "none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all" 1.71 +}; 1.72 + 1.73 +DataTransfer::DataTransfer(nsISupports* aParent, uint32_t aEventType, 1.74 + bool aIsExternal, int32_t aClipboardType) 1.75 + : mParent(aParent), 1.76 + mEventType(aEventType), 1.77 + mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE), 1.78 + mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED), 1.79 + mCursorState(false), 1.80 + mReadOnly(true), 1.81 + mIsExternal(aIsExternal), 1.82 + mUserCancelled(false), 1.83 + mIsCrossDomainSubFrameDrop(false), 1.84 + mClipboardType(aClipboardType), 1.85 + mDragImageX(0), 1.86 + mDragImageY(0) 1.87 +{ 1.88 + MOZ_ASSERT(mParent); 1.89 + SetIsDOMBinding(); 1.90 + // For these events, we want to be able to add data to the data transfer, so 1.91 + // clear the readonly state. Otherwise, the data is already present. For 1.92 + // external usage, cache the data from the native clipboard or drag. 1.93 + if (aEventType == NS_CUT || 1.94 + aEventType == NS_COPY || 1.95 + aEventType == NS_DRAGDROP_START || 1.96 + aEventType == NS_DRAGDROP_GESTURE) { 1.97 + mReadOnly = false; 1.98 + } else if (mIsExternal) { 1.99 + if (aEventType == NS_PASTE) { 1.100 + CacheExternalClipboardFormats(); 1.101 + } else if (aEventType >= NS_DRAGDROP_EVENT_START && aEventType <= NS_DRAGDROP_LEAVE_SYNTH) { 1.102 + CacheExternalDragFormats(); 1.103 + } 1.104 + } 1.105 +} 1.106 + 1.107 +DataTransfer::DataTransfer(nsISupports* aParent, 1.108 + uint32_t aEventType, 1.109 + const uint32_t aEffectAllowed, 1.110 + bool aCursorState, 1.111 + bool aIsExternal, 1.112 + bool aUserCancelled, 1.113 + bool aIsCrossDomainSubFrameDrop, 1.114 + int32_t aClipboardType, 1.115 + nsTArray<nsTArray<TransferItem> >& aItems, 1.116 + Element* aDragImage, 1.117 + uint32_t aDragImageX, 1.118 + uint32_t aDragImageY) 1.119 + : mParent(aParent), 1.120 + mEventType(aEventType), 1.121 + mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE), 1.122 + mEffectAllowed(aEffectAllowed), 1.123 + mCursorState(aCursorState), 1.124 + mReadOnly(true), 1.125 + mIsExternal(aIsExternal), 1.126 + mUserCancelled(aUserCancelled), 1.127 + mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop), 1.128 + mClipboardType(aClipboardType), 1.129 + mItems(aItems), 1.130 + mDragImage(aDragImage), 1.131 + mDragImageX(aDragImageX), 1.132 + mDragImageY(aDragImageY) 1.133 +{ 1.134 + MOZ_ASSERT(mParent); 1.135 + SetIsDOMBinding(); 1.136 + // The items are copied from aItems into mItems. There is no need to copy 1.137 + // the actual data in the items as the data transfer will be read only. The 1.138 + // draggesture and dragstart events are the only times when items are 1.139 + // modifiable, but those events should have been using the first constructor 1.140 + // above. 1.141 + NS_ASSERTION(aEventType != NS_DRAGDROP_GESTURE && 1.142 + aEventType != NS_DRAGDROP_START, 1.143 + "invalid event type for DataTransfer constructor"); 1.144 +} 1.145 + 1.146 +DataTransfer::~DataTransfer() 1.147 +{ 1.148 + if (mFiles) { 1.149 + mFiles->Disconnect(); 1.150 + } 1.151 +} 1.152 + 1.153 +// static 1.154 +already_AddRefed<DataTransfer> 1.155 +DataTransfer::Constructor(const GlobalObject& aGlobal, 1.156 + const nsAString& aEventType, bool aIsExternal, 1.157 + ErrorResult& aRv) 1.158 +{ 1.159 + nsAutoCString onEventType("on"); 1.160 + AppendUTF16toUTF8(aEventType, onEventType); 1.161 + nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(onEventType); 1.162 + if (!eventTypeAtom) { 1.163 + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.164 + return nullptr; 1.165 + } 1.166 + 1.167 + uint32_t eventType = nsContentUtils::GetEventId(eventTypeAtom); 1.168 + nsRefPtr<DataTransfer> transfer = new DataTransfer(aGlobal.GetAsSupports(), 1.169 + eventType, aIsExternal, 1.170 + -1); 1.171 + return transfer.forget(); 1.172 +} 1.173 + 1.174 +JSObject* 1.175 +DataTransfer::WrapObject(JSContext* aCx) 1.176 +{ 1.177 + return DataTransferBinding::Wrap(aCx, this); 1.178 +} 1.179 + 1.180 +NS_IMETHODIMP 1.181 +DataTransfer::GetDropEffect(nsAString& aDropEffect) 1.182 +{ 1.183 + nsString dropEffect; 1.184 + GetDropEffect(dropEffect); 1.185 + aDropEffect = dropEffect; 1.186 + return NS_OK; 1.187 +} 1.188 + 1.189 +NS_IMETHODIMP 1.190 +DataTransfer::SetDropEffect(const nsAString& aDropEffect) 1.191 +{ 1.192 + // the drop effect can only be 'none', 'copy', 'move' or 'link'. 1.193 + for (uint32_t e = 0; e <= nsIDragService::DRAGDROP_ACTION_LINK; e++) { 1.194 + if (aDropEffect.EqualsASCII(sEffects[e])) { 1.195 + // don't allow copyMove 1.196 + if (e != (nsIDragService::DRAGDROP_ACTION_COPY | 1.197 + nsIDragService::DRAGDROP_ACTION_MOVE)) 1.198 + mDropEffect = e; 1.199 + break; 1.200 + } 1.201 + } 1.202 + 1.203 + return NS_OK; 1.204 +} 1.205 + 1.206 +NS_IMETHODIMP 1.207 +DataTransfer::GetEffectAllowed(nsAString& aEffectAllowed) 1.208 +{ 1.209 + nsString effectAllowed; 1.210 + GetEffectAllowed(effectAllowed); 1.211 + aEffectAllowed = effectAllowed; 1.212 + return NS_OK; 1.213 +} 1.214 + 1.215 +NS_IMETHODIMP 1.216 +DataTransfer::SetEffectAllowed(const nsAString& aEffectAllowed) 1.217 +{ 1.218 + if (aEffectAllowed.EqualsLiteral("uninitialized")) { 1.219 + mEffectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED; 1.220 + return NS_OK; 1.221 + } 1.222 + 1.223 + static_assert(nsIDragService::DRAGDROP_ACTION_NONE == 0, 1.224 + "DRAGDROP_ACTION_NONE constant is wrong"); 1.225 + static_assert(nsIDragService::DRAGDROP_ACTION_COPY == 1, 1.226 + "DRAGDROP_ACTION_COPY constant is wrong"); 1.227 + static_assert(nsIDragService::DRAGDROP_ACTION_MOVE == 2, 1.228 + "DRAGDROP_ACTION_MOVE constant is wrong"); 1.229 + static_assert(nsIDragService::DRAGDROP_ACTION_LINK == 4, 1.230 + "DRAGDROP_ACTION_LINK constant is wrong"); 1.231 + 1.232 + for (uint32_t e = 0; e < ArrayLength(sEffects); e++) { 1.233 + if (aEffectAllowed.EqualsASCII(sEffects[e])) { 1.234 + mEffectAllowed = e; 1.235 + break; 1.236 + } 1.237 + } 1.238 + 1.239 + return NS_OK; 1.240 +} 1.241 + 1.242 +NS_IMETHODIMP 1.243 +DataTransfer::GetDropEffectInt(uint32_t* aDropEffect) 1.244 +{ 1.245 + *aDropEffect = mDropEffect; 1.246 + return NS_OK; 1.247 +} 1.248 + 1.249 +NS_IMETHODIMP 1.250 +DataTransfer::SetDropEffectInt(uint32_t aDropEffect) 1.251 +{ 1.252 + mDropEffect = aDropEffect; 1.253 + return NS_OK; 1.254 +} 1.255 + 1.256 +NS_IMETHODIMP 1.257 +DataTransfer::GetEffectAllowedInt(uint32_t* aEffectAllowed) 1.258 +{ 1.259 + *aEffectAllowed = mEffectAllowed; 1.260 + return NS_OK; 1.261 +} 1.262 + 1.263 +NS_IMETHODIMP 1.264 +DataTransfer::SetEffectAllowedInt(uint32_t aEffectAllowed) 1.265 +{ 1.266 + mEffectAllowed = aEffectAllowed; 1.267 + return NS_OK; 1.268 +} 1.269 + 1.270 +NS_IMETHODIMP 1.271 +DataTransfer::GetMozUserCancelled(bool* aUserCancelled) 1.272 +{ 1.273 + *aUserCancelled = MozUserCancelled(); 1.274 + return NS_OK; 1.275 +} 1.276 + 1.277 +nsDOMFileList* 1.278 +DataTransfer::GetFiles(ErrorResult& aRv) 1.279 +{ 1.280 + if (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP && 1.281 + mEventType != NS_PASTE) { 1.282 + return nullptr; 1.283 + } 1.284 + 1.285 + if (!mFiles) { 1.286 + mFiles = new nsDOMFileList(static_cast<nsIDOMDataTransfer*>(this)); 1.287 + 1.288 + uint32_t count = mItems.Length(); 1.289 + 1.290 + for (uint32_t i = 0; i < count; i++) { 1.291 + nsCOMPtr<nsIVariant> variant; 1.292 + aRv = MozGetDataAt(NS_ConvertUTF8toUTF16(kFileMime), i, getter_AddRefs(variant)); 1.293 + if (aRv.Failed()) { 1.294 + return nullptr; 1.295 + } 1.296 + 1.297 + if (!variant) 1.298 + continue; 1.299 + 1.300 + nsCOMPtr<nsISupports> supports; 1.301 + nsresult rv = variant->GetAsISupports(getter_AddRefs(supports)); 1.302 + 1.303 + if (NS_FAILED(rv)) 1.304 + continue; 1.305 + 1.306 + nsCOMPtr<nsIFile> file = do_QueryInterface(supports); 1.307 + 1.308 + if (!file) 1.309 + continue; 1.310 + 1.311 + nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(file); 1.312 + 1.313 + if (!mFiles->Append(domFile)) { 1.314 + aRv.Throw(NS_ERROR_FAILURE); 1.315 + return nullptr; 1.316 + } 1.317 + } 1.318 + } 1.319 + 1.320 + return mFiles; 1.321 +} 1.322 + 1.323 +NS_IMETHODIMP 1.324 +DataTransfer::GetFiles(nsIDOMFileList** aFileList) 1.325 +{ 1.326 + ErrorResult rv; 1.327 + NS_IF_ADDREF(*aFileList = GetFiles(rv)); 1.328 + return rv.ErrorCode(); 1.329 +} 1.330 + 1.331 +already_AddRefed<DOMStringList> 1.332 +DataTransfer::Types() 1.333 +{ 1.334 + nsRefPtr<DOMStringList> types = new DOMStringList(); 1.335 + if (mItems.Length()) { 1.336 + bool addFile = false; 1.337 + const nsTArray<TransferItem>& item = mItems[0]; 1.338 + for (uint32_t i = 0; i < item.Length(); i++) { 1.339 + const nsString& format = item[i].mFormat; 1.340 + types->Add(format); 1.341 + if (!addFile) { 1.342 + addFile = format.EqualsASCII(kFileMime) || 1.343 + format.EqualsASCII("application/x-moz-file-promise"); 1.344 + } 1.345 + } 1.346 + 1.347 + if (addFile) { 1.348 + types->Add(NS_LITERAL_STRING("Files")); 1.349 + } 1.350 + } 1.351 + 1.352 + return types.forget(); 1.353 +} 1.354 + 1.355 +NS_IMETHODIMP 1.356 +DataTransfer::GetTypes(nsISupports** aTypes) 1.357 +{ 1.358 + nsRefPtr<DOMStringList> types = Types(); 1.359 + types.forget(aTypes); 1.360 + 1.361 + return NS_OK; 1.362 +} 1.363 + 1.364 +void 1.365 +DataTransfer::GetData(const nsAString& aFormat, nsAString& aData, 1.366 + ErrorResult& aRv) 1.367 +{ 1.368 + // return an empty string if data for the format was not found 1.369 + aData.Truncate(); 1.370 + 1.371 + nsCOMPtr<nsIVariant> data; 1.372 + nsresult rv = MozGetDataAt(aFormat, 0, getter_AddRefs(data)); 1.373 + if (NS_FAILED(rv)) { 1.374 + if (rv != NS_ERROR_DOM_INDEX_SIZE_ERR) { 1.375 + aRv.Throw(rv); 1.376 + } 1.377 + return; 1.378 + } 1.379 + 1.380 + if (data) { 1.381 + nsAutoString stringdata; 1.382 + data->GetAsAString(stringdata); 1.383 + 1.384 + // for the URL type, parse out the first URI from the list. The URIs are 1.385 + // separated by newlines 1.386 + nsAutoString lowercaseFormat; 1.387 + aRv = nsContentUtils::ASCIIToLower(aFormat, lowercaseFormat); 1.388 + if (aRv.Failed()) { 1.389 + return; 1.390 + } 1.391 + 1.392 + if (lowercaseFormat.EqualsLiteral("url")) { 1.393 + int32_t lastidx = 0, idx; 1.394 + int32_t length = stringdata.Length(); 1.395 + while (lastidx < length) { 1.396 + idx = stringdata.FindChar('\n', lastidx); 1.397 + // lines beginning with # are comments 1.398 + if (stringdata[lastidx] == '#') { 1.399 + if (idx == -1) 1.400 + break; 1.401 + } 1.402 + else { 1.403 + if (idx == -1) 1.404 + aData.Assign(Substring(stringdata, lastidx)); 1.405 + else 1.406 + aData.Assign(Substring(stringdata, lastidx, idx - lastidx)); 1.407 + aData = nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(aData, true); 1.408 + return; 1.409 + } 1.410 + lastidx = idx + 1; 1.411 + } 1.412 + } 1.413 + else { 1.414 + aData = stringdata; 1.415 + } 1.416 + } 1.417 +} 1.418 + 1.419 +NS_IMETHODIMP 1.420 +DataTransfer::GetData(const nsAString& aFormat, nsAString& aData) 1.421 +{ 1.422 + ErrorResult rv; 1.423 + GetData(aFormat, aData, rv); 1.424 + return rv.ErrorCode(); 1.425 +} 1.426 + 1.427 +void 1.428 +DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData, 1.429 + ErrorResult& aRv) 1.430 +{ 1.431 + nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID); 1.432 + if (!variant) { 1.433 + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.434 + return; 1.435 + } 1.436 + 1.437 + variant->SetAsAString(aData); 1.438 + 1.439 + aRv = MozSetDataAt(aFormat, variant, 0); 1.440 +} 1.441 + 1.442 +NS_IMETHODIMP 1.443 +DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData) 1.444 +{ 1.445 + ErrorResult rv; 1.446 + SetData(aFormat, aData, rv); 1.447 + return rv.ErrorCode(); 1.448 +} 1.449 + 1.450 +void 1.451 +DataTransfer::ClearData(const Optional<nsAString>& aFormat, ErrorResult& aRv) 1.452 +{ 1.453 + if (mReadOnly) { 1.454 + aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); 1.455 + return; 1.456 + } 1.457 + 1.458 + if (mItems.Length() == 0) { 1.459 + return; 1.460 + } 1.461 + 1.462 + if (aFormat.WasPassed()) { 1.463 + MozClearDataAtHelper(aFormat.Value(), 0, aRv); 1.464 + } else { 1.465 + MozClearDataAtHelper(EmptyString(), 0, aRv); 1.466 + } 1.467 +} 1.468 + 1.469 +NS_IMETHODIMP 1.470 +DataTransfer::ClearData(const nsAString& aFormat) 1.471 +{ 1.472 + Optional<nsAString> format; 1.473 + format = &aFormat; 1.474 + ErrorResult rv; 1.475 + ClearData(format, rv); 1.476 + return rv.ErrorCode(); 1.477 +} 1.478 + 1.479 +NS_IMETHODIMP 1.480 +DataTransfer::GetMozItemCount(uint32_t* aCount) 1.481 +{ 1.482 + *aCount = MozItemCount(); 1.483 + return NS_OK; 1.484 +} 1.485 + 1.486 +NS_IMETHODIMP 1.487 +DataTransfer::GetMozCursor(nsAString& aCursorState) 1.488 +{ 1.489 + nsString cursor; 1.490 + GetMozCursor(cursor); 1.491 + aCursorState = cursor; 1.492 + return NS_OK; 1.493 +} 1.494 + 1.495 +NS_IMETHODIMP 1.496 +DataTransfer::SetMozCursor(const nsAString& aCursorState) 1.497 +{ 1.498 + // Lock the cursor to an arrow during the drag. 1.499 + mCursorState = aCursorState.EqualsLiteral("default"); 1.500 + 1.501 + return NS_OK; 1.502 +} 1.503 + 1.504 +already_AddRefed<nsINode> 1.505 +DataTransfer::GetMozSourceNode() 1.506 +{ 1.507 + nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); 1.508 + if (!dragSession) { 1.509 + return nullptr; 1.510 + } 1.511 + 1.512 + nsCOMPtr<nsIDOMNode> sourceNode; 1.513 + dragSession->GetSourceNode(getter_AddRefs(sourceNode)); 1.514 + nsCOMPtr<nsINode> node = do_QueryInterface(sourceNode); 1.515 + if (node && !nsContentUtils::CanCallerAccess(node)) { 1.516 + return nullptr; 1.517 + } 1.518 + 1.519 + return node.forget(); 1.520 +} 1.521 + 1.522 +NS_IMETHODIMP 1.523 +DataTransfer::GetMozSourceNode(nsIDOMNode** aSourceNode) 1.524 +{ 1.525 + nsCOMPtr<nsINode> sourceNode = GetMozSourceNode(); 1.526 + if (!sourceNode) { 1.527 + *aSourceNode = nullptr; 1.528 + return NS_OK; 1.529 + } 1.530 + 1.531 + return CallQueryInterface(sourceNode, aSourceNode); 1.532 +} 1.533 + 1.534 +already_AddRefed<DOMStringList> 1.535 +DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv) 1.536 +{ 1.537 + // Only the first item is valid for clipboard events 1.538 + if (aIndex > 0 && 1.539 + (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) { 1.540 + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); 1.541 + return nullptr; 1.542 + } 1.543 + 1.544 + nsRefPtr<DOMStringList> types = new DOMStringList(); 1.545 + if (aIndex < mItems.Length()) { 1.546 + // note that you can retrieve the types regardless of their principal 1.547 + nsTArray<TransferItem>& item = mItems[aIndex]; 1.548 + for (uint32_t i = 0; i < item.Length(); i++) 1.549 + types->Add(item[i].mFormat); 1.550 + } 1.551 + 1.552 + return types.forget(); 1.553 +} 1.554 + 1.555 +NS_IMETHODIMP 1.556 +DataTransfer::MozTypesAt(uint32_t aIndex, nsISupports** aTypes) 1.557 +{ 1.558 + ErrorResult rv; 1.559 + nsRefPtr<DOMStringList> types = MozTypesAt(aIndex, rv); 1.560 + types.forget(aTypes); 1.561 + return rv.ErrorCode(); 1.562 +} 1.563 + 1.564 +NS_IMETHODIMP 1.565 +DataTransfer::MozGetDataAt(const nsAString& aFormat, uint32_t aIndex, 1.566 + nsIVariant** aData) 1.567 +{ 1.568 + *aData = nullptr; 1.569 + 1.570 + if (aFormat.IsEmpty()) 1.571 + return NS_OK; 1.572 + 1.573 + if (aIndex >= mItems.Length()) { 1.574 + return NS_ERROR_DOM_INDEX_SIZE_ERR; 1.575 + } 1.576 + 1.577 + // Only the first item is valid for clipboard events 1.578 + if (aIndex > 0 && 1.579 + (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) { 1.580 + return NS_ERROR_DOM_INDEX_SIZE_ERR; 1.581 + } 1.582 + 1.583 + 1.584 + nsAutoString format; 1.585 + GetRealFormat(aFormat, format); 1.586 + 1.587 + nsTArray<TransferItem>& item = mItems[aIndex]; 1.588 + 1.589 + // Check if the caller is allowed to access the drag data. Callers with 1.590 + // chrome privileges can always read the data. During the 1.591 + // drop event, allow retrieving the data except in the case where the 1.592 + // source of the drag is in a child frame of the caller. In that case, 1.593 + // we only allow access to data of the same principal. During other events, 1.594 + // only allow access to the data with the same principal. 1.595 + nsIPrincipal* principal = nullptr; 1.596 + if (mIsCrossDomainSubFrameDrop || 1.597 + (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP && 1.598 + mEventType != NS_PASTE && 1.599 + !nsContentUtils::IsCallerChrome())) { 1.600 + nsresult rv = NS_OK; 1.601 + principal = GetCurrentPrincipal(&rv); 1.602 + NS_ENSURE_SUCCESS(rv, rv); 1.603 + } 1.604 + 1.605 + uint32_t count = item.Length(); 1.606 + for (uint32_t i = 0; i < count; i++) { 1.607 + TransferItem& formatitem = item[i]; 1.608 + if (formatitem.mFormat.Equals(format)) { 1.609 + bool subsumes; 1.610 + if (formatitem.mPrincipal && principal && 1.611 + (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes)) 1.612 + return NS_ERROR_DOM_SECURITY_ERR; 1.613 + 1.614 + if (!formatitem.mData) { 1.615 + FillInExternalData(formatitem, aIndex); 1.616 + } else { 1.617 + nsCOMPtr<nsISupports> data; 1.618 + formatitem.mData->GetAsISupports(getter_AddRefs(data)); 1.619 + // Make sure the code that is calling us is same-origin with the data. 1.620 + nsCOMPtr<EventTarget> pt = do_QueryInterface(data); 1.621 + if (pt) { 1.622 + nsresult rv = NS_OK; 1.623 + nsIScriptContext* c = pt->GetContextForEventHandlers(&rv); 1.624 + NS_ENSURE_TRUE(c && NS_SUCCEEDED(rv), NS_ERROR_DOM_SECURITY_ERR); 1.625 + nsIGlobalObject* go = c->GetGlobalObject(); 1.626 + NS_ENSURE_TRUE(go, NS_ERROR_DOM_SECURITY_ERR); 1.627 + nsCOMPtr<nsIScriptObjectPrincipal> sp = do_QueryInterface(go); 1.628 + MOZ_ASSERT(sp, "This cannot fail on the main thread."); 1.629 + nsIPrincipal* dataPrincipal = sp->GetPrincipal(); 1.630 + NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR); 1.631 + NS_ENSURE_TRUE(principal || (principal = GetCurrentPrincipal(&rv)), 1.632 + NS_ERROR_DOM_SECURITY_ERR); 1.633 + NS_ENSURE_SUCCESS(rv, rv); 1.634 + bool equals = false; 1.635 + NS_ENSURE_TRUE(NS_SUCCEEDED(principal->Equals(dataPrincipal, &equals)) && equals, 1.636 + NS_ERROR_DOM_SECURITY_ERR); 1.637 + } 1.638 + } 1.639 + *aData = formatitem.mData; 1.640 + NS_IF_ADDREF(*aData); 1.641 + return NS_OK; 1.642 + } 1.643 + } 1.644 + 1.645 + return NS_OK; 1.646 +} 1.647 + 1.648 +void 1.649 +DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat, 1.650 + uint32_t aIndex, 1.651 + JS::MutableHandle<JS::Value> aRetval, 1.652 + mozilla::ErrorResult& aRv) 1.653 +{ 1.654 + nsCOMPtr<nsIVariant> data; 1.655 + aRv = MozGetDataAt(aFormat, aIndex, getter_AddRefs(data)); 1.656 + if (aRv.Failed()) { 1.657 + return; 1.658 + } 1.659 + 1.660 + if (!data) { 1.661 + return; 1.662 + } 1.663 + 1.664 + JS::Rooted<JS::Value> result(aCx); 1.665 + if (!VariantToJsval(aCx, data, aRetval)) { 1.666 + aRv = NS_ERROR_FAILURE; 1.667 + return; 1.668 + } 1.669 +} 1.670 + 1.671 +NS_IMETHODIMP 1.672 +DataTransfer::MozSetDataAt(const nsAString& aFormat, nsIVariant* aData, 1.673 + uint32_t aIndex) 1.674 +{ 1.675 + if (aFormat.IsEmpty()) { 1.676 + return NS_OK; 1.677 + } 1.678 + 1.679 + if (mReadOnly) { 1.680 + return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; 1.681 + } 1.682 + 1.683 + // Specifying an index less than the current length will replace an existing 1.684 + // item. Specifying an index equal to the current length will add a new item. 1.685 + if (aIndex > mItems.Length()) { 1.686 + return NS_ERROR_DOM_INDEX_SIZE_ERR; 1.687 + } 1.688 + 1.689 + // Only the first item is valid for clipboard events 1.690 + if (aIndex > 0 && 1.691 + (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) { 1.692 + return NS_ERROR_DOM_INDEX_SIZE_ERR; 1.693 + } 1.694 + 1.695 + // don't allow non-chrome to add file data 1.696 + // XXX perhaps this should also limit any non-string type as well 1.697 + if ((aFormat.EqualsLiteral("application/x-moz-file-promise") || 1.698 + aFormat.EqualsLiteral("application/x-moz-file")) && 1.699 + !nsContentUtils::IsCallerChrome()) { 1.700 + return NS_ERROR_DOM_SECURITY_ERR; 1.701 + } 1.702 + 1.703 + nsresult rv = NS_OK; 1.704 + nsIPrincipal* principal = GetCurrentPrincipal(&rv); 1.705 + NS_ENSURE_SUCCESS(rv, rv); 1.706 + 1.707 + return SetDataWithPrincipal(aFormat, aData, aIndex, principal); 1.708 +} 1.709 + 1.710 +void 1.711 +DataTransfer::MozSetDataAt(JSContext* aCx, const nsAString& aFormat, 1.712 + JS::Handle<JS::Value> aData, 1.713 + uint32_t aIndex, ErrorResult& aRv) 1.714 +{ 1.715 + nsCOMPtr<nsIVariant> data; 1.716 + aRv = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData, 1.717 + getter_AddRefs(data)); 1.718 + if (!aRv.Failed()) { 1.719 + aRv = MozSetDataAt(aFormat, data, aIndex); 1.720 + } 1.721 +} 1.722 + 1.723 +void 1.724 +DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex, 1.725 + ErrorResult& aRv) 1.726 +{ 1.727 + if (mReadOnly) { 1.728 + aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); 1.729 + return; 1.730 + } 1.731 + 1.732 + if (aIndex >= mItems.Length()) { 1.733 + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); 1.734 + return; 1.735 + } 1.736 + 1.737 + // Only the first item is valid for clipboard events 1.738 + if (aIndex > 0 && 1.739 + (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) { 1.740 + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); 1.741 + return; 1.742 + } 1.743 + 1.744 + MozClearDataAtHelper(aFormat, aIndex, aRv); 1.745 +} 1.746 + 1.747 +void 1.748 +DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex, 1.749 + ErrorResult& aRv) 1.750 +{ 1.751 + MOZ_ASSERT(!mReadOnly); 1.752 + MOZ_ASSERT(aIndex < mItems.Length()); 1.753 + MOZ_ASSERT(aIndex == 0 || 1.754 + (mEventType != NS_CUT && mEventType != NS_COPY && 1.755 + mEventType != NS_PASTE)); 1.756 + 1.757 + nsAutoString format; 1.758 + GetRealFormat(aFormat, format); 1.759 + 1.760 + nsresult rv = NS_OK; 1.761 + nsIPrincipal* principal = GetCurrentPrincipal(&rv); 1.762 + if (NS_FAILED(rv)) { 1.763 + aRv = rv; 1.764 + return; 1.765 + } 1.766 + 1.767 + // if the format is empty, clear all formats 1.768 + bool clearall = format.IsEmpty(); 1.769 + 1.770 + nsTArray<TransferItem>& item = mItems[aIndex]; 1.771 + // count backwards so that the count and index don't have to be adjusted 1.772 + // after removing an element 1.773 + for (int32_t i = item.Length() - 1; i >= 0; i--) { 1.774 + TransferItem& formatitem = item[i]; 1.775 + if (clearall || formatitem.mFormat.Equals(format)) { 1.776 + // don't allow removing data that has a stronger principal 1.777 + bool subsumes; 1.778 + if (formatitem.mPrincipal && principal && 1.779 + (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes)) { 1.780 + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); 1.781 + return; 1.782 + } 1.783 + 1.784 + item.RemoveElementAt(i); 1.785 + 1.786 + // if a format was specified, break out. Otherwise, loop around until 1.787 + // all formats have been removed 1.788 + if (!clearall) 1.789 + break; 1.790 + } 1.791 + } 1.792 + 1.793 + // if the last format for an item is removed, remove the entire item 1.794 + if (!item.Length()) 1.795 + mItems.RemoveElementAt(aIndex); 1.796 +} 1.797 + 1.798 +NS_IMETHODIMP 1.799 +DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex) 1.800 +{ 1.801 + ErrorResult rv; 1.802 + MozClearDataAt(aFormat, aIndex, rv); 1.803 + return rv.ErrorCode(); 1.804 +} 1.805 + 1.806 +void 1.807 +DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY, 1.808 + ErrorResult& aRv) 1.809 +{ 1.810 + if (mReadOnly) { 1.811 + aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); 1.812 + return; 1.813 + } 1.814 + 1.815 + mDragImage = &aImage; 1.816 + mDragImageX = aX; 1.817 + mDragImageY = aY; 1.818 +} 1.819 + 1.820 +NS_IMETHODIMP 1.821 +DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY) 1.822 +{ 1.823 + ErrorResult rv; 1.824 + nsCOMPtr<Element> image = do_QueryInterface(aImage); 1.825 + if (image) { 1.826 + SetDragImage(*image, aX, aY, rv); 1.827 + } 1.828 + return rv.ErrorCode(); 1.829 +} 1.830 + 1.831 +void 1.832 +DataTransfer::AddElement(Element& aElement, ErrorResult& aRv) 1.833 +{ 1.834 + if (mReadOnly) { 1.835 + aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); 1.836 + return; 1.837 + } 1.838 + 1.839 + mDragTarget = &aElement; 1.840 +} 1.841 + 1.842 +NS_IMETHODIMP 1.843 +DataTransfer::AddElement(nsIDOMElement* aElement) 1.844 +{ 1.845 + NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER); 1.846 + 1.847 + nsCOMPtr<Element> element = do_QueryInterface(aElement); 1.848 + NS_ENSURE_TRUE(element, NS_ERROR_INVALID_ARG); 1.849 + 1.850 + ErrorResult rv; 1.851 + AddElement(*element, rv); 1.852 + return rv.ErrorCode(); 1.853 +} 1.854 + 1.855 +nsresult 1.856 +DataTransfer::Clone(nsISupports* aParent, uint32_t aEventType, 1.857 + bool aUserCancelled, bool aIsCrossDomainSubFrameDrop, 1.858 + DataTransfer** aNewDataTransfer) 1.859 +{ 1.860 + DataTransfer* newDataTransfer = 1.861 + new DataTransfer(aParent, aEventType, mEffectAllowed, mCursorState, 1.862 + mIsExternal, aUserCancelled, aIsCrossDomainSubFrameDrop, 1.863 + mClipboardType, mItems, mDragImage, mDragImageX, 1.864 + mDragImageY); 1.865 + 1.866 + *aNewDataTransfer = newDataTransfer; 1.867 + NS_ADDREF(*aNewDataTransfer); 1.868 + return NS_OK; 1.869 +} 1.870 + 1.871 +already_AddRefed<nsISupportsArray> 1.872 +DataTransfer::GetTransferables(nsIDOMNode* aDragTarget) 1.873 +{ 1.874 + MOZ_ASSERT(aDragTarget); 1.875 + 1.876 + nsCOMPtr<nsISupportsArray> transArray = 1.877 + do_CreateInstance("@mozilla.org/supports-array;1"); 1.878 + if (!transArray) { 1.879 + return nullptr; 1.880 + } 1.881 + 1.882 + 1.883 + nsCOMPtr<nsINode> dragNode = do_QueryInterface(aDragTarget); 1.884 + if (!dragNode) { 1.885 + return nullptr; 1.886 + } 1.887 + 1.888 + nsIDocument* doc = dragNode->GetCurrentDoc(); 1.889 + if (!doc) { 1.890 + return nullptr; 1.891 + } 1.892 + 1.893 + nsILoadContext* loadContext = doc->GetLoadContext(); 1.894 + 1.895 + uint32_t count = mItems.Length(); 1.896 + for (uint32_t i = 0; i < count; i++) { 1.897 + nsCOMPtr<nsITransferable> transferable = GetTransferable(i, loadContext); 1.898 + if (transferable) { 1.899 + transArray->AppendElement(transferable); 1.900 + } 1.901 + } 1.902 + 1.903 + return transArray.forget(); 1.904 +} 1.905 + 1.906 +already_AddRefed<nsITransferable> 1.907 +DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext) 1.908 +{ 1.909 + if (aIndex >= mItems.Length()) { 1.910 + return nullptr; 1.911 + } 1.912 + 1.913 + nsTArray<TransferItem>& item = mItems[aIndex]; 1.914 + uint32_t count = item.Length(); 1.915 + if (!count) { 1.916 + return nullptr; 1.917 + } 1.918 + 1.919 + nsCOMPtr<nsITransferable> transferable = 1.920 + do_CreateInstance("@mozilla.org/widget/transferable;1"); 1.921 + if (!transferable) { 1.922 + return nullptr; 1.923 + } 1.924 + transferable->Init(aLoadContext); 1.925 + 1.926 + bool added = false; 1.927 + for (uint32_t f = 0; f < count; f++) { 1.928 + const TransferItem& formatitem = item[f]; 1.929 + if (!formatitem.mData) { // skip empty items 1.930 + continue; 1.931 + } 1.932 + 1.933 + uint32_t length; 1.934 + nsCOMPtr<nsISupports> convertedData; 1.935 + if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &length)) { 1.936 + continue; 1.937 + } 1.938 + 1.939 + // the underlying drag code uses text/unicode, so use that instead of text/plain 1.940 + const char* format; 1.941 + NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat); 1.942 + if (utf8format.EqualsLiteral("text/plain")) { 1.943 + format = kUnicodeMime; 1.944 + } else { 1.945 + format = utf8format.get(); 1.946 + } 1.947 + 1.948 + // if a converter is set for a format, set the converter for the 1.949 + // transferable and don't add the item 1.950 + nsCOMPtr<nsIFormatConverter> converter = do_QueryInterface(convertedData); 1.951 + if (converter) { 1.952 + transferable->AddDataFlavor(format); 1.953 + transferable->SetConverter(converter); 1.954 + continue; 1.955 + } 1.956 + 1.957 + nsresult rv = transferable->SetTransferData(format, convertedData, length); 1.958 + if (NS_FAILED(rv)) { 1.959 + return nullptr; 1.960 + } 1.961 + 1.962 + added = true; 1.963 + } 1.964 + 1.965 + // only return the transferable if data was successfully added to it 1.966 + if (added) { 1.967 + return transferable.forget(); 1.968 + } 1.969 + 1.970 + return nullptr; 1.971 +} 1.972 + 1.973 +bool 1.974 +DataTransfer::ConvertFromVariant(nsIVariant* aVariant, 1.975 + nsISupports** aSupports, 1.976 + uint32_t* aLength) 1.977 +{ 1.978 + *aSupports = nullptr; 1.979 + *aLength = 0; 1.980 + 1.981 + uint16_t type; 1.982 + aVariant->GetDataType(&type); 1.983 + if (type == nsIDataType::VTYPE_INTERFACE || 1.984 + type == nsIDataType::VTYPE_INTERFACE_IS) { 1.985 + nsCOMPtr<nsISupports> data; 1.986 + if (NS_FAILED(aVariant->GetAsISupports(getter_AddRefs(data)))) 1.987 + return false; 1.988 + 1.989 + nsCOMPtr<nsIFlavorDataProvider> fdp = do_QueryInterface(data); 1.990 + if (fdp) { 1.991 + // for flavour data providers, use kFlavorHasDataProvider (which has the 1.992 + // value 0) as the length. 1.993 + NS_ADDREF(*aSupports = fdp); 1.994 + *aLength = nsITransferable::kFlavorHasDataProvider; 1.995 + } 1.996 + else { 1.997 + // wrap the item in an nsISupportsInterfacePointer 1.998 + nsCOMPtr<nsISupportsInterfacePointer> ptrSupports = 1.999 + do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID); 1.1000 + if (!ptrSupports) 1.1001 + return false; 1.1002 + 1.1003 + ptrSupports->SetData(data); 1.1004 + NS_ADDREF(*aSupports = ptrSupports); 1.1005 + 1.1006 + *aLength = sizeof(nsISupportsInterfacePointer *); 1.1007 + } 1.1008 + 1.1009 + return true; 1.1010 + } 1.1011 + 1.1012 + char16_t* chrs; 1.1013 + uint32_t len = 0; 1.1014 + nsresult rv = aVariant->GetAsWStringWithSize(&len, &chrs); 1.1015 + if (NS_FAILED(rv)) 1.1016 + return false; 1.1017 + 1.1018 + nsAutoString str; 1.1019 + str.Adopt(chrs, len); 1.1020 + 1.1021 + nsCOMPtr<nsISupportsString> 1.1022 + strSupports(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); 1.1023 + if (!strSupports) 1.1024 + return false; 1.1025 + 1.1026 + strSupports->SetData(str); 1.1027 + 1.1028 + *aSupports = strSupports; 1.1029 + NS_ADDREF(*aSupports); 1.1030 + 1.1031 + // each character is two bytes 1.1032 + *aLength = str.Length() << 1; 1.1033 + 1.1034 + return true; 1.1035 +} 1.1036 + 1.1037 +void 1.1038 +DataTransfer::ClearAll() 1.1039 +{ 1.1040 + mItems.Clear(); 1.1041 +} 1.1042 + 1.1043 +nsresult 1.1044 +DataTransfer::SetDataWithPrincipal(const nsAString& aFormat, 1.1045 + nsIVariant* aData, 1.1046 + uint32_t aIndex, 1.1047 + nsIPrincipal* aPrincipal) 1.1048 +{ 1.1049 + nsAutoString format; 1.1050 + GetRealFormat(aFormat, format); 1.1051 + 1.1052 + // check if the item for the format already exists. In that case, 1.1053 + // just replace it. 1.1054 + TransferItem* formatitem; 1.1055 + if (aIndex < mItems.Length()) { 1.1056 + nsTArray<TransferItem>& item = mItems[aIndex]; 1.1057 + uint32_t count = item.Length(); 1.1058 + for (uint32_t i = 0; i < count; i++) { 1.1059 + TransferItem& itemformat = item[i]; 1.1060 + if (itemformat.mFormat.Equals(format)) { 1.1061 + // don't allow replacing data that has a stronger principal 1.1062 + bool subsumes; 1.1063 + if (itemformat.mPrincipal && aPrincipal && 1.1064 + (NS_FAILED(aPrincipal->Subsumes(itemformat.mPrincipal, &subsumes)) || !subsumes)) 1.1065 + return NS_ERROR_DOM_SECURITY_ERR; 1.1066 + 1.1067 + itemformat.mPrincipal = aPrincipal; 1.1068 + itemformat.mData = aData; 1.1069 + return NS_OK; 1.1070 + } 1.1071 + } 1.1072 + 1.1073 + // add a new format 1.1074 + formatitem = item.AppendElement(); 1.1075 + } 1.1076 + else { 1.1077 + NS_ASSERTION(aIndex == mItems.Length(), "Index out of range"); 1.1078 + 1.1079 + // add a new index 1.1080 + nsTArray<TransferItem>* item = mItems.AppendElement(); 1.1081 + NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY); 1.1082 + 1.1083 + formatitem = item->AppendElement(); 1.1084 + } 1.1085 + 1.1086 + NS_ENSURE_TRUE(formatitem, NS_ERROR_OUT_OF_MEMORY); 1.1087 + 1.1088 + formatitem->mFormat = format; 1.1089 + formatitem->mPrincipal = aPrincipal; 1.1090 + formatitem->mData = aData; 1.1091 + 1.1092 + return NS_OK; 1.1093 +} 1.1094 + 1.1095 +nsIPrincipal* 1.1096 +DataTransfer::GetCurrentPrincipal(nsresult* rv) 1.1097 +{ 1.1098 + nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); 1.1099 + 1.1100 + nsCOMPtr<nsIPrincipal> currentPrincipal; 1.1101 + *rv = ssm->GetSubjectPrincipal(getter_AddRefs(currentPrincipal)); 1.1102 + NS_ENSURE_SUCCESS(*rv, nullptr); 1.1103 + 1.1104 + if (!currentPrincipal) 1.1105 + ssm->GetSystemPrincipal(getter_AddRefs(currentPrincipal)); 1.1106 + 1.1107 + return currentPrincipal.get(); 1.1108 +} 1.1109 + 1.1110 +void 1.1111 +DataTransfer::GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat) 1.1112 +{ 1.1113 + // treat text/unicode as equivalent to text/plain 1.1114 + nsAutoString lowercaseFormat; 1.1115 + nsContentUtils::ASCIIToLower(aInFormat, lowercaseFormat); 1.1116 + if (lowercaseFormat.EqualsLiteral("text") || lowercaseFormat.EqualsLiteral("text/unicode")) 1.1117 + aOutFormat.AssignLiteral("text/plain"); 1.1118 + else if (lowercaseFormat.EqualsLiteral("url")) 1.1119 + aOutFormat.AssignLiteral("text/uri-list"); 1.1120 + else 1.1121 + aOutFormat.Assign(lowercaseFormat); 1.1122 +} 1.1123 + 1.1124 +void 1.1125 +DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex, nsIPrincipal* aPrincipal) 1.1126 +{ 1.1127 + if (strcmp(aFormat, kUnicodeMime) == 0) { 1.1128 + SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr, aIndex, aPrincipal); 1.1129 + } else { 1.1130 + if (strcmp(aFormat, kURLDataMime) == 0) { 1.1131 + SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr, aIndex, aPrincipal); 1.1132 + } 1.1133 + SetDataWithPrincipal(NS_ConvertUTF8toUTF16(aFormat), nullptr, aIndex, aPrincipal); 1.1134 + } 1.1135 +} 1.1136 + 1.1137 +void 1.1138 +DataTransfer::CacheExternalDragFormats() 1.1139 +{ 1.1140 + // Called during the constructor to cache the formats available from an 1.1141 + // external drag. The data associated with each format will be set to null. 1.1142 + // This data will instead only be retrieved in FillInExternalDragData when 1.1143 + // asked for, as it may be time consuming for the source application to 1.1144 + // generate it. 1.1145 + 1.1146 + nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); 1.1147 + if (!dragSession) 1.1148 + return; 1.1149 + 1.1150 + // make sure that the system principal is used for external drags 1.1151 + nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); 1.1152 + nsCOMPtr<nsIPrincipal> sysPrincipal; 1.1153 + ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal)); 1.1154 + 1.1155 + // there isn't a way to get a list of the formats that might be available on 1.1156 + // all platforms, so just check for the types that can actually be imported 1.1157 + // XXXndeakin there are some other formats but those are platform specific. 1.1158 + const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime, kUnicodeMime }; 1.1159 + 1.1160 + uint32_t count; 1.1161 + dragSession->GetNumDropItems(&count); 1.1162 + for (uint32_t c = 0; c < count; c++) { 1.1163 + for (uint32_t f = 0; f < ArrayLength(formats); f++) { 1.1164 + // IsDataFlavorSupported doesn't take an index as an argument and just 1.1165 + // checks if any of the items support a particular flavor, even though 1.1166 + // the GetData method does take an index. Here, we just assume that 1.1167 + // every item being dragged has the same set of flavors. 1.1168 + bool supported; 1.1169 + dragSession->IsDataFlavorSupported(formats[f], &supported); 1.1170 + // if the format is supported, add an item to the array with null as 1.1171 + // the data. When retrieved, GetRealData will read the data. 1.1172 + if (supported) { 1.1173 + CacheExternalData(formats[f], c, sysPrincipal); 1.1174 + } 1.1175 + } 1.1176 + } 1.1177 +} 1.1178 + 1.1179 +void 1.1180 +DataTransfer::CacheExternalClipboardFormats() 1.1181 +{ 1.1182 + NS_ASSERTION(mEventType == NS_PASTE, "caching clipboard data for invalid event"); 1.1183 + 1.1184 + // Called during the constructor for paste events to cache the formats 1.1185 + // available on the clipboard. As with CacheExternalDragFormats, the 1.1186 + // data will only be retrieved when needed. 1.1187 + 1.1188 + nsCOMPtr<nsIClipboard> clipboard = do_GetService("@mozilla.org/widget/clipboard;1"); 1.1189 + if (!clipboard || mClipboardType < 0) { 1.1190 + return; 1.1191 + } 1.1192 + 1.1193 + nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); 1.1194 + nsCOMPtr<nsIPrincipal> sysPrincipal; 1.1195 + ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal)); 1.1196 + 1.1197 + // there isn't a way to get a list of the formats that might be available on 1.1198 + // all platforms, so just check for the types that can actually be imported 1.1199 + const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime, kUnicodeMime }; 1.1200 + 1.1201 + for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) { 1.1202 + // check each format one at a time 1.1203 + bool supported; 1.1204 + clipboard->HasDataMatchingFlavors(&(formats[f]), 1, mClipboardType, &supported); 1.1205 + // if the format is supported, add an item to the array with null as 1.1206 + // the data. When retrieved, GetRealData will read the data. 1.1207 + if (supported) { 1.1208 + CacheExternalData(formats[f], 0, sysPrincipal); 1.1209 + } 1.1210 + } 1.1211 +} 1.1212 + 1.1213 +void 1.1214 +DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex) 1.1215 +{ 1.1216 + NS_PRECONDITION(mIsExternal, "Not an external data transfer"); 1.1217 + 1.1218 + if (aItem.mData) { 1.1219 + return; 1.1220 + } 1.1221 + 1.1222 + // only drag and paste events should be calling FillInExternalData 1.1223 + NS_ASSERTION(mEventType != NS_CUT && mEventType != NS_COPY, 1.1224 + "clipboard event with empty data"); 1.1225 + 1.1226 + NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat); 1.1227 + const char* format = utf8format.get(); 1.1228 + if (strcmp(format, "text/plain") == 0) 1.1229 + format = kUnicodeMime; 1.1230 + else if (strcmp(format, "text/uri-list") == 0) 1.1231 + format = kURLDataMime; 1.1232 + 1.1233 + nsCOMPtr<nsITransferable> trans = 1.1234 + do_CreateInstance("@mozilla.org/widget/transferable;1"); 1.1235 + if (!trans) 1.1236 + return; 1.1237 + 1.1238 + trans->Init(nullptr); 1.1239 + trans->AddDataFlavor(format); 1.1240 + 1.1241 + if (mEventType == NS_PASTE) { 1.1242 + MOZ_ASSERT(aIndex == 0, "index in clipboard must be 0"); 1.1243 + 1.1244 + nsCOMPtr<nsIClipboard> clipboard = do_GetService("@mozilla.org/widget/clipboard;1"); 1.1245 + if (!clipboard || mClipboardType < 0) { 1.1246 + return; 1.1247 + } 1.1248 + 1.1249 + clipboard->GetData(trans, mClipboardType); 1.1250 + } else { 1.1251 + nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); 1.1252 + if (!dragSession) { 1.1253 + return; 1.1254 + } 1.1255 + 1.1256 +#ifdef DEBUG 1.1257 + // Since this is an external drag, the source document will always be null. 1.1258 + nsCOMPtr<nsIDOMDocument> domDoc; 1.1259 + dragSession->GetSourceDocument(getter_AddRefs(domDoc)); 1.1260 + MOZ_ASSERT(!domDoc); 1.1261 +#endif 1.1262 + 1.1263 + dragSession->GetData(trans, aIndex); 1.1264 + } 1.1265 + 1.1266 + uint32_t length = 0; 1.1267 + nsCOMPtr<nsISupports> data; 1.1268 + trans->GetTransferData(format, getter_AddRefs(data), &length); 1.1269 + if (!data) 1.1270 + return; 1.1271 + 1.1272 + nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID); 1.1273 + if (!variant) 1.1274 + return; 1.1275 + 1.1276 + nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data); 1.1277 + if (supportsstr) { 1.1278 + nsAutoString str; 1.1279 + supportsstr->GetData(str); 1.1280 + variant->SetAsAString(str); 1.1281 + } 1.1282 + else { 1.1283 + variant->SetAsISupports(data); 1.1284 + } 1.1285 + 1.1286 + aItem.mData = variant; 1.1287 + } 1.1288 + 1.1289 +} // namespace dom 1.1290 +} // namespace mozilla