widget/windows/nsClipboard.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsClipboard.h"
michael@0 7 #include <ole2.h>
michael@0 8 #include <shlobj.h>
michael@0 9 #include <intshcut.h>
michael@0 10
michael@0 11 // shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
michael@0 12 #include <shellapi.h>
michael@0 13
michael@0 14 #include "nsCOMPtr.h"
michael@0 15 #include "nsDataObj.h"
michael@0 16 #include "nsIClipboardOwner.h"
michael@0 17 #include "nsString.h"
michael@0 18 #include "nsNativeCharsetUtils.h"
michael@0 19 #include "nsIFormatConverter.h"
michael@0 20 #include "nsITransferable.h"
michael@0 21 #include "nsCOMPtr.h"
michael@0 22 #include "nsXPCOM.h"
michael@0 23 #include "nsISupportsPrimitives.h"
michael@0 24 #include "nsXPIDLString.h"
michael@0 25 #include "nsReadableUtils.h"
michael@0 26 #include "nsUnicharUtils.h"
michael@0 27 #include "nsPrimitiveHelpers.h"
michael@0 28 #include "nsImageClipboard.h"
michael@0 29 #include "nsIWidget.h"
michael@0 30 #include "nsIComponentManager.h"
michael@0 31 #include "nsWidgetsCID.h"
michael@0 32 #include "nsCRT.h"
michael@0 33 #include "nsNetUtil.h"
michael@0 34 #include "nsEscape.h"
michael@0 35 #include "nsIObserverService.h"
michael@0 36
michael@0 37 #ifdef PR_LOGGING
michael@0 38 PRLogModuleInfo* gWin32ClipboardLog = nullptr;
michael@0 39 #endif
michael@0 40
michael@0 41 // oddly, this isn't in the MSVC headers anywhere.
michael@0 42 UINT nsClipboard::CF_HTML = ::RegisterClipboardFormatW(L"HTML Format");
michael@0 43
michael@0 44
michael@0 45 //-------------------------------------------------------------------------
michael@0 46 //
michael@0 47 // nsClipboard constructor
michael@0 48 //
michael@0 49 //-------------------------------------------------------------------------
michael@0 50 nsClipboard::nsClipboard() : nsBaseClipboard()
michael@0 51 {
michael@0 52 #ifdef PR_LOGGING
michael@0 53 if (!gWin32ClipboardLog) {
michael@0 54 gWin32ClipboardLog = PR_NewLogModule("nsClipboard");
michael@0 55 }
michael@0 56 #endif
michael@0 57
michael@0 58 mIgnoreEmptyNotification = false;
michael@0 59 mWindow = nullptr;
michael@0 60
michael@0 61 // Register for a shutdown notification so that we can flush data
michael@0 62 // to the OS clipboard.
michael@0 63 nsCOMPtr<nsIObserverService> observerService =
michael@0 64 do_GetService("@mozilla.org/observer-service;1");
michael@0 65 if (observerService)
michael@0 66 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
michael@0 67 }
michael@0 68
michael@0 69 //-------------------------------------------------------------------------
michael@0 70 // nsClipboard destructor
michael@0 71 //-------------------------------------------------------------------------
michael@0 72 nsClipboard::~nsClipboard()
michael@0 73 {
michael@0 74
michael@0 75 }
michael@0 76
michael@0 77 NS_IMPL_ISUPPORTS_INHERITED(nsClipboard, nsBaseClipboard, nsIObserver)
michael@0 78
michael@0 79 NS_IMETHODIMP
michael@0 80 nsClipboard::Observe(nsISupports *aSubject, const char *aTopic,
michael@0 81 const char16_t *aData)
michael@0 82 {
michael@0 83 // This will be called on shutdown.
michael@0 84 ::OleFlushClipboard();
michael@0 85 ::CloseClipboard();
michael@0 86
michael@0 87 return NS_OK;
michael@0 88 }
michael@0 89
michael@0 90 //-------------------------------------------------------------------------
michael@0 91 UINT nsClipboard::GetFormat(const char* aMimeStr)
michael@0 92 {
michael@0 93 UINT format;
michael@0 94
michael@0 95 if (strcmp(aMimeStr, kTextMime) == 0)
michael@0 96 format = CF_TEXT;
michael@0 97 else if (strcmp(aMimeStr, kUnicodeMime) == 0)
michael@0 98 format = CF_UNICODETEXT;
michael@0 99 else if (strcmp(aMimeStr, kJPEGImageMime) == 0 ||
michael@0 100 strcmp(aMimeStr, kJPGImageMime) == 0 ||
michael@0 101 strcmp(aMimeStr, kPNGImageMime) == 0)
michael@0 102 format = CF_DIBV5;
michael@0 103 else if (strcmp(aMimeStr, kFileMime) == 0 ||
michael@0 104 strcmp(aMimeStr, kFilePromiseMime) == 0)
michael@0 105 format = CF_HDROP;
michael@0 106 else if (strcmp(aMimeStr, kNativeHTMLMime) == 0)
michael@0 107 format = CF_HTML;
michael@0 108 else
michael@0 109 format = ::RegisterClipboardFormatW(NS_ConvertASCIItoUTF16(aMimeStr).get());
michael@0 110
michael@0 111 return format;
michael@0 112 }
michael@0 113
michael@0 114 //-------------------------------------------------------------------------
michael@0 115 nsresult nsClipboard::CreateNativeDataObject(nsITransferable * aTransferable, IDataObject ** aDataObj, nsIURI * uri)
michael@0 116 {
michael@0 117 if (nullptr == aTransferable) {
michael@0 118 return NS_ERROR_FAILURE;
michael@0 119 }
michael@0 120
michael@0 121 // Create our native DataObject that implements
michael@0 122 // the OLE IDataObject interface
michael@0 123 nsDataObj * dataObj = new nsDataObj(uri);
michael@0 124
michael@0 125 if (!dataObj)
michael@0 126 return NS_ERROR_OUT_OF_MEMORY;
michael@0 127
michael@0 128 dataObj->AddRef();
michael@0 129
michael@0 130 // Now set it up with all the right data flavors & enums
michael@0 131 nsresult res = SetupNativeDataObject(aTransferable, dataObj);
michael@0 132 if (NS_OK == res) {
michael@0 133 *aDataObj = dataObj;
michael@0 134 } else {
michael@0 135 delete dataObj;
michael@0 136 }
michael@0 137 return res;
michael@0 138 }
michael@0 139
michael@0 140 //-------------------------------------------------------------------------
michael@0 141 nsresult nsClipboard::SetupNativeDataObject(nsITransferable * aTransferable, IDataObject * aDataObj)
michael@0 142 {
michael@0 143 if (nullptr == aTransferable || nullptr == aDataObj) {
michael@0 144 return NS_ERROR_FAILURE;
michael@0 145 }
michael@0 146
michael@0 147 nsDataObj * dObj = static_cast<nsDataObj *>(aDataObj);
michael@0 148
michael@0 149 // Now give the Transferable to the DataObject
michael@0 150 // for getting the data out of it
michael@0 151 dObj->SetTransferable(aTransferable);
michael@0 152
michael@0 153 // Get the transferable list of data flavors
michael@0 154 nsCOMPtr<nsISupportsArray> dfList;
michael@0 155 aTransferable->FlavorsTransferableCanExport(getter_AddRefs(dfList));
michael@0 156
michael@0 157 // Walk through flavors that contain data and register them
michael@0 158 // into the DataObj as supported flavors
michael@0 159 uint32_t i;
michael@0 160 uint32_t cnt;
michael@0 161 dfList->Count(&cnt);
michael@0 162 for (i=0;i<cnt;i++) {
michael@0 163 nsCOMPtr<nsISupports> genericFlavor;
michael@0 164 dfList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
michael@0 165 nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
michael@0 166 if ( currentFlavor ) {
michael@0 167 nsXPIDLCString flavorStr;
michael@0 168 currentFlavor->ToString(getter_Copies(flavorStr));
michael@0 169 UINT format = GetFormat(flavorStr);
michael@0 170
michael@0 171 // Now tell the native IDataObject about both our mime type and
michael@0 172 // the native data format
michael@0 173 FORMATETC fe;
michael@0 174 SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
michael@0 175 dObj->AddDataFlavor(flavorStr, &fe);
michael@0 176
michael@0 177 // Do various things internal to the implementation, like map one
michael@0 178 // flavor to another or add additional flavors based on what's required
michael@0 179 // for the win32 impl.
michael@0 180 if ( strcmp(flavorStr, kUnicodeMime) == 0 ) {
michael@0 181 // if we find text/unicode, also advertise text/plain (which we will convert
michael@0 182 // on our own in nsDataObj::GetText().
michael@0 183 FORMATETC textFE;
michael@0 184 SET_FORMATETC(textFE, CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
michael@0 185 dObj->AddDataFlavor(kTextMime, &textFE);
michael@0 186 }
michael@0 187 else if ( strcmp(flavorStr, kHTMLMime) == 0 ) {
michael@0 188 // if we find text/html, also advertise win32's html flavor (which we will convert
michael@0 189 // on our own in nsDataObj::GetText().
michael@0 190 FORMATETC htmlFE;
michael@0 191 SET_FORMATETC(htmlFE, CF_HTML, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
michael@0 192 dObj->AddDataFlavor(kHTMLMime, &htmlFE);
michael@0 193 }
michael@0 194 else if ( strcmp(flavorStr, kURLMime) == 0 ) {
michael@0 195 // if we're a url, in addition to also being text, we need to register
michael@0 196 // the "file" flavors so that the win32 shell knows to create an internet
michael@0 197 // shortcut when it sees one of these beasts.
michael@0 198 FORMATETC shortcutFE;
michael@0 199 SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
michael@0 200 dObj->AddDataFlavor(kURLMime, &shortcutFE);
michael@0 201 SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
michael@0 202 dObj->AddDataFlavor(kURLMime, &shortcutFE);
michael@0 203 SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
michael@0 204 dObj->AddDataFlavor(kURLMime, &shortcutFE);
michael@0 205 SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
michael@0 206 dObj->AddDataFlavor(kURLMime, &shortcutFE);
michael@0 207 SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
michael@0 208 dObj->AddDataFlavor(kURLMime, &shortcutFE);
michael@0 209 }
michael@0 210 else if ( strcmp(flavorStr, kPNGImageMime) == 0 || strcmp(flavorStr, kJPEGImageMime) == 0 ||
michael@0 211 strcmp(flavorStr, kJPGImageMime) == 0 || strcmp(flavorStr, kGIFImageMime) == 0 ||
michael@0 212 strcmp(flavorStr, kNativeImageMime) == 0 ) {
michael@0 213 // if we're an image, register the native bitmap flavor
michael@0 214 FORMATETC imageFE;
michael@0 215 // Add DIBv5
michael@0 216 SET_FORMATETC(imageFE, CF_DIBV5, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
michael@0 217 dObj->AddDataFlavor(flavorStr, &imageFE);
michael@0 218 // Add DIBv3
michael@0 219 SET_FORMATETC(imageFE, CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
michael@0 220 dObj->AddDataFlavor(flavorStr, &imageFE);
michael@0 221 }
michael@0 222 else if ( strcmp(flavorStr, kFilePromiseMime) == 0 ) {
michael@0 223 // if we're a file promise flavor, also register the
michael@0 224 // CFSTR_PREFERREDDROPEFFECT format. The data object
michael@0 225 // returns a value of DROPEFFECTS_MOVE to the drop target
michael@0 226 // when it asks for the value of this format. This causes
michael@0 227 // the file to be moved from the temporary location instead
michael@0 228 // of being copied. The right thing to do here is to call
michael@0 229 // SetData() on the data object and set the value of this format
michael@0 230 // to DROPEFFECTS_MOVE on this particular data object. But,
michael@0 231 // since all the other clipboard formats follow the model of setting
michael@0 232 // data on the data object only when the drop object calls GetData(),
michael@0 233 // I am leaving this format's value hard coded in the data object.
michael@0 234 // We can change this if other consumers of this format get added to this
michael@0 235 // codebase and they need different values.
michael@0 236 FORMATETC shortcutFE;
michael@0 237 SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
michael@0 238 dObj->AddDataFlavor(kFilePromiseMime, &shortcutFE);
michael@0 239 }
michael@0 240 }
michael@0 241 }
michael@0 242
michael@0 243 return NS_OK;
michael@0 244 }
michael@0 245
michael@0 246 //-------------------------------------------------------------------------
michael@0 247 NS_IMETHODIMP nsClipboard::SetNativeClipboardData ( int32_t aWhichClipboard )
michael@0 248 {
michael@0 249 if ( aWhichClipboard != kGlobalClipboard )
michael@0 250 return NS_ERROR_FAILURE;
michael@0 251
michael@0 252 mIgnoreEmptyNotification = true;
michael@0 253
michael@0 254 // make sure we have a good transferable
michael@0 255 if (nullptr == mTransferable) {
michael@0 256 return NS_ERROR_FAILURE;
michael@0 257 }
michael@0 258
michael@0 259 IDataObject * dataObj;
michael@0 260 if ( NS_SUCCEEDED(CreateNativeDataObject(mTransferable, &dataObj, nullptr)) ) { // this add refs dataObj
michael@0 261 ::OleSetClipboard(dataObj);
michael@0 262 dataObj->Release();
michael@0 263 } else {
michael@0 264 // Clear the native clipboard
michael@0 265 ::OleSetClipboard(nullptr);
michael@0 266 }
michael@0 267
michael@0 268 mIgnoreEmptyNotification = false;
michael@0 269
michael@0 270 return NS_OK;
michael@0 271 }
michael@0 272
michael@0 273
michael@0 274 //-------------------------------------------------------------------------
michael@0 275 nsresult nsClipboard::GetGlobalData(HGLOBAL aHGBL, void ** aData, uint32_t * aLen)
michael@0 276 {
michael@0 277 // Allocate a new memory buffer and copy the data from global memory.
michael@0 278 // Recall that win98 allocates to nearest DWORD boundary. As a safety
michael@0 279 // precaution, allocate an extra 2 bytes (but don't report them!) and
michael@0 280 // null them out to ensure that all of our strlen calls will succeed.
michael@0 281 nsresult result = NS_ERROR_FAILURE;
michael@0 282 if (aHGBL != nullptr) {
michael@0 283 LPSTR lpStr = (LPSTR) GlobalLock(aHGBL);
michael@0 284 DWORD allocSize = GlobalSize(aHGBL);
michael@0 285 char* data = static_cast<char*>(nsMemory::Alloc(allocSize + sizeof(char16_t)));
michael@0 286 if ( data ) {
michael@0 287 memcpy ( data, lpStr, allocSize );
michael@0 288 data[allocSize] = data[allocSize + 1] = '\0'; // null terminate for safety
michael@0 289
michael@0 290 GlobalUnlock(aHGBL);
michael@0 291 *aData = data;
michael@0 292 *aLen = allocSize;
michael@0 293
michael@0 294 result = NS_OK;
michael@0 295 }
michael@0 296 } else {
michael@0 297 #ifdef MOZ_METRO
michael@0 298 return result;
michael@0 299 #endif
michael@0 300 // We really shouldn't ever get here
michael@0 301 // but just in case
michael@0 302 *aData = nullptr;
michael@0 303 *aLen = 0;
michael@0 304 LPVOID lpMsgBuf;
michael@0 305
michael@0 306 FormatMessageW(
michael@0 307 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
michael@0 308 nullptr,
michael@0 309 GetLastError(),
michael@0 310 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
michael@0 311 (LPWSTR) &lpMsgBuf,
michael@0 312 0,
michael@0 313 nullptr
michael@0 314 );
michael@0 315
michael@0 316 // Display the string.
michael@0 317 MessageBoxW( nullptr, (LPCWSTR) lpMsgBuf, L"GetLastError",
michael@0 318 MB_OK | MB_ICONINFORMATION );
michael@0 319
michael@0 320 // Free the buffer.
michael@0 321 LocalFree( lpMsgBuf );
michael@0 322 }
michael@0 323
michael@0 324 return result;
michael@0 325 }
michael@0 326
michael@0 327 //-------------------------------------------------------------------------
michael@0 328 nsresult nsClipboard::GetNativeDataOffClipboard(nsIWidget * aWidget, UINT /*aIndex*/, UINT aFormat, void ** aData, uint32_t * aLen)
michael@0 329 {
michael@0 330 HGLOBAL hglb;
michael@0 331 nsresult result = NS_ERROR_FAILURE;
michael@0 332
michael@0 333 HWND nativeWin = nullptr;
michael@0 334 if (::OpenClipboard(nativeWin)) {
michael@0 335 hglb = ::GetClipboardData(aFormat);
michael@0 336 result = GetGlobalData(hglb, aData, aLen);
michael@0 337 ::CloseClipboard();
michael@0 338 }
michael@0 339 return result;
michael@0 340 }
michael@0 341
michael@0 342 static void DisplayErrCode(HRESULT hres)
michael@0 343 {
michael@0 344 #if defined(DEBUG_rods) || defined(DEBUG_pinkerton)
michael@0 345 if (hres == E_INVALIDARG) {
michael@0 346 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("E_INVALIDARG\n"));
michael@0 347 } else
michael@0 348 if (hres == E_UNEXPECTED) {
michael@0 349 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("E_UNEXPECTED\n"));
michael@0 350 } else
michael@0 351 if (hres == E_OUTOFMEMORY) {
michael@0 352 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("E_OUTOFMEMORY\n"));
michael@0 353 } else
michael@0 354 if (hres == DV_E_LINDEX ) {
michael@0 355 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_LINDEX\n"));
michael@0 356 } else
michael@0 357 if (hres == DV_E_FORMATETC) {
michael@0 358 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_FORMATETC\n"));
michael@0 359 } else
michael@0 360 if (hres == DV_E_TYMED) {
michael@0 361 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_TYMED\n"));
michael@0 362 } else
michael@0 363 if (hres == DV_E_DVASPECT) {
michael@0 364 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_DVASPECT\n"));
michael@0 365 } else
michael@0 366 if (hres == OLE_E_NOTRUNNING) {
michael@0 367 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("OLE_E_NOTRUNNING\n"));
michael@0 368 } else
michael@0 369 if (hres == STG_E_MEDIUMFULL) {
michael@0 370 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("STG_E_MEDIUMFULL\n"));
michael@0 371 } else
michael@0 372 if (hres == DV_E_CLIPFORMAT) {
michael@0 373 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_CLIPFORMAT\n"));
michael@0 374 } else
michael@0 375 if (hres == S_OK) {
michael@0 376 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("S_OK\n"));
michael@0 377 } else {
michael@0 378 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS,
michael@0 379 ("****** DisplayErrCode 0x%X\n", hres));
michael@0 380 }
michael@0 381 #endif
michael@0 382 }
michael@0 383
michael@0 384 //-------------------------------------------------------------------------
michael@0 385 static HRESULT FillSTGMedium(IDataObject * aDataObject, UINT aFormat, LPFORMATETC pFE, LPSTGMEDIUM pSTM, DWORD aTymed)
michael@0 386 {
michael@0 387 SET_FORMATETC(*pFE, aFormat, 0, DVASPECT_CONTENT, -1, aTymed);
michael@0 388
michael@0 389 // Starting by querying for the data to see if we can get it as from global memory
michael@0 390 HRESULT hres = S_FALSE;
michael@0 391 hres = aDataObject->QueryGetData(pFE);
michael@0 392 DisplayErrCode(hres);
michael@0 393 if (S_OK == hres) {
michael@0 394 hres = aDataObject->GetData(pFE, pSTM);
michael@0 395 DisplayErrCode(hres);
michael@0 396 }
michael@0 397 return hres;
michael@0 398 }
michael@0 399
michael@0 400
michael@0 401 //-------------------------------------------------------------------------
michael@0 402 // If aFormat is CF_DIBV5, aMIMEImageFormat must be a type for which we have
michael@0 403 // an image encoder (e.g. image/png).
michael@0 404 // For other values of aFormat, it is OK to pass null for aMIMEImageFormat.
michael@0 405 nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject * aDataObject, UINT aIndex, UINT aFormat, const char * aMIMEImageFormat, void ** aData, uint32_t * aLen)
michael@0 406 {
michael@0 407 nsresult result = NS_ERROR_FAILURE;
michael@0 408 *aData = nullptr;
michael@0 409 *aLen = 0;
michael@0 410
michael@0 411 if ( !aDataObject )
michael@0 412 return result;
michael@0 413
michael@0 414 UINT format = aFormat;
michael@0 415 HRESULT hres = S_FALSE;
michael@0 416
michael@0 417 // XXX at the moment we only support global memory transfers
michael@0 418 // It is here where we will add support for native images
michael@0 419 // and IStream
michael@0 420 FORMATETC fe;
michael@0 421 STGMEDIUM stm;
michael@0 422 hres = FillSTGMedium(aDataObject, format, &fe, &stm, TYMED_HGLOBAL);
michael@0 423
michael@0 424 // Currently this is only handling TYMED_HGLOBAL data
michael@0 425 // For Text, Dibs, Files, and generic data (like HTML)
michael@0 426 if (S_OK == hres) {
michael@0 427 static CLIPFORMAT fileDescriptorFlavorA = ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORA );
michael@0 428 static CLIPFORMAT fileDescriptorFlavorW = ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORW );
michael@0 429 static CLIPFORMAT fileFlavor = ::RegisterClipboardFormat( CFSTR_FILECONTENTS );
michael@0 430 static CLIPFORMAT preferredDropEffect = ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
michael@0 431
michael@0 432 switch (stm.tymed) {
michael@0 433 case TYMED_HGLOBAL:
michael@0 434 {
michael@0 435 switch (fe.cfFormat) {
michael@0 436 case CF_TEXT:
michael@0 437 {
michael@0 438 // Get the data out of the global data handle. The size we return
michael@0 439 // should not include the null because the other platforms don't
michael@0 440 // use nulls, so just return the length we get back from strlen(),
michael@0 441 // since we know CF_TEXT is null terminated. Recall that GetGlobalData()
michael@0 442 // returns the size of the allocated buffer, not the size of the data
michael@0 443 // (on 98, these are not the same) so we can't use that.
michael@0 444 uint32_t allocLen = 0;
michael@0 445 if ( NS_SUCCEEDED(GetGlobalData(stm.hGlobal, aData, &allocLen)) ) {
michael@0 446 *aLen = strlen ( reinterpret_cast<char*>(*aData) );
michael@0 447 result = NS_OK;
michael@0 448 }
michael@0 449 } break;
michael@0 450
michael@0 451 case CF_UNICODETEXT:
michael@0 452 {
michael@0 453 // Get the data out of the global data handle. The size we return
michael@0 454 // should not include the null because the other platforms don't
michael@0 455 // use nulls, so just return the length we get back from strlen(),
michael@0 456 // since we know CF_UNICODETEXT is null terminated. Recall that GetGlobalData()
michael@0 457 // returns the size of the allocated buffer, not the size of the data
michael@0 458 // (on 98, these are not the same) so we can't use that.
michael@0 459 uint32_t allocLen = 0;
michael@0 460 if ( NS_SUCCEEDED(GetGlobalData(stm.hGlobal, aData, &allocLen)) ) {
michael@0 461 *aLen = NS_strlen(reinterpret_cast<char16_t*>(*aData)) * 2;
michael@0 462 result = NS_OK;
michael@0 463 }
michael@0 464 } break;
michael@0 465
michael@0 466 case CF_DIBV5:
michael@0 467 if (aMIMEImageFormat)
michael@0 468 {
michael@0 469 uint32_t allocLen = 0;
michael@0 470 unsigned char * clipboardData;
michael@0 471 if (NS_SUCCEEDED(GetGlobalData(stm.hGlobal, (void **)&clipboardData, &allocLen)))
michael@0 472 {
michael@0 473 nsImageFromClipboard converter;
michael@0 474 nsIInputStream * inputStream;
michael@0 475 converter.GetEncodedImageStream(clipboardData, aMIMEImageFormat, &inputStream); // addrefs for us, don't release
michael@0 476 if ( inputStream ) {
michael@0 477 *aData = inputStream;
michael@0 478 *aLen = sizeof(nsIInputStream*);
michael@0 479 result = NS_OK;
michael@0 480 }
michael@0 481 }
michael@0 482 } break;
michael@0 483
michael@0 484 case CF_HDROP :
michael@0 485 {
michael@0 486 // in the case of a file drop, multiple files are stashed within a
michael@0 487 // single data object. In order to match mozilla's D&D apis, we
michael@0 488 // just pull out the file at the requested index, pretending as
michael@0 489 // if there really are multiple drag items.
michael@0 490 HDROP dropFiles = (HDROP) GlobalLock(stm.hGlobal);
michael@0 491
michael@0 492 UINT numFiles = ::DragQueryFileW(dropFiles, 0xFFFFFFFF, nullptr, 0);
michael@0 493 NS_ASSERTION ( numFiles > 0, "File drop flavor, but no files...hmmmm" );
michael@0 494 NS_ASSERTION ( aIndex < numFiles, "Asked for a file index out of range of list" );
michael@0 495 if (numFiles > 0) {
michael@0 496 UINT fileNameLen = ::DragQueryFileW(dropFiles, aIndex, nullptr, 0);
michael@0 497 wchar_t* buffer = reinterpret_cast<wchar_t*>(nsMemory::Alloc((fileNameLen + 1) * sizeof(wchar_t)));
michael@0 498 if ( buffer ) {
michael@0 499 ::DragQueryFileW(dropFiles, aIndex, buffer, fileNameLen + 1);
michael@0 500 *aData = buffer;
michael@0 501 *aLen = fileNameLen * sizeof(char16_t);
michael@0 502 result = NS_OK;
michael@0 503 }
michael@0 504 else
michael@0 505 result = NS_ERROR_OUT_OF_MEMORY;
michael@0 506 }
michael@0 507 GlobalUnlock (stm.hGlobal) ;
michael@0 508
michael@0 509 } break;
michael@0 510
michael@0 511 default: {
michael@0 512 if ( fe.cfFormat == fileDescriptorFlavorA || fe.cfFormat == fileDescriptorFlavorW || fe.cfFormat == fileFlavor ) {
michael@0 513 NS_WARNING ( "Mozilla doesn't yet understand how to read this type of file flavor" );
michael@0 514 }
michael@0 515 else
michael@0 516 {
michael@0 517 // Get the data out of the global data handle. The size we return
michael@0 518 // should not include the null because the other platforms don't
michael@0 519 // use nulls, so just return the length we get back from strlen(),
michael@0 520 // since we know CF_UNICODETEXT is null terminated. Recall that GetGlobalData()
michael@0 521 // returns the size of the allocated buffer, not the size of the data
michael@0 522 // (on 98, these are not the same) so we can't use that.
michael@0 523 //
michael@0 524 // NOTE: we are assuming that anything that falls into this default case
michael@0 525 // is unicode. As we start to get more kinds of binary data, this
michael@0 526 // may become an incorrect assumption. Stay tuned.
michael@0 527 uint32_t allocLen = 0;
michael@0 528 if ( NS_SUCCEEDED(GetGlobalData(stm.hGlobal, aData, &allocLen)) ) {
michael@0 529 if ( fe.cfFormat == CF_HTML ) {
michael@0 530 // CF_HTML is actually UTF8, not unicode, so disregard the assumption
michael@0 531 // above. We have to check the header for the actual length, and we'll
michael@0 532 // do that in FindPlatformHTML(). For now, return the allocLen. This
michael@0 533 // case is mostly to ensure we don't try to call strlen on the buffer.
michael@0 534 *aLen = allocLen;
michael@0 535 } else if (fe.cfFormat == preferredDropEffect) {
michael@0 536 // As per the MSDN doc entitled: "Shell Clipboard Formats"
michael@0 537 // CFSTR_PREFERREDDROPEFFECT should return a DWORD
michael@0 538 // Reference: http://msdn.microsoft.com/en-us/library/bb776902(v=vs.85).aspx
michael@0 539 NS_ASSERTION(allocLen == sizeof(DWORD),
michael@0 540 "CFSTR_PREFERREDDROPEFFECT should return a DWORD");
michael@0 541 *aLen = allocLen;
michael@0 542 } else {
michael@0 543 *aLen = NS_strlen(reinterpret_cast<char16_t*>(*aData)) *
michael@0 544 sizeof(char16_t);
michael@0 545 }
michael@0 546 result = NS_OK;
michael@0 547 }
michael@0 548 }
michael@0 549 } break;
michael@0 550 } // switch
michael@0 551 } break;
michael@0 552
michael@0 553 case TYMED_GDI:
michael@0 554 {
michael@0 555 #ifdef DEBUG
michael@0 556 PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS,
michael@0 557 ("*********************** TYMED_GDI\n"));
michael@0 558 #endif
michael@0 559 } break;
michael@0 560
michael@0 561 default:
michael@0 562 break;
michael@0 563 } //switch
michael@0 564
michael@0 565 ReleaseStgMedium(&stm);
michael@0 566 }
michael@0 567
michael@0 568 return result;
michael@0 569 }
michael@0 570
michael@0 571
michael@0 572 //-------------------------------------------------------------------------
michael@0 573 nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject,
michael@0 574 UINT anIndex,
michael@0 575 nsIWidget * aWindow,
michael@0 576 nsITransferable * aTransferable)
michael@0 577 {
michael@0 578 // make sure we have a good transferable
michael@0 579 if ( !aTransferable )
michael@0 580 return NS_ERROR_INVALID_ARG;
michael@0 581
michael@0 582 nsresult res = NS_ERROR_FAILURE;
michael@0 583
michael@0 584 // get flavor list that includes all flavors that can be written (including ones
michael@0 585 // obtained through conversion)
michael@0 586 nsCOMPtr<nsISupportsArray> flavorList;
michael@0 587 res = aTransferable->FlavorsTransferableCanImport ( getter_AddRefs(flavorList) );
michael@0 588 if ( NS_FAILED(res) )
michael@0 589 return NS_ERROR_FAILURE;
michael@0 590
michael@0 591 // Walk through flavors and see which flavor is on the clipboard them on the native clipboard,
michael@0 592 uint32_t i;
michael@0 593 uint32_t cnt;
michael@0 594 flavorList->Count(&cnt);
michael@0 595 for (i=0;i<cnt;i++) {
michael@0 596 nsCOMPtr<nsISupports> genericFlavor;
michael@0 597 flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
michael@0 598 nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
michael@0 599 if ( currentFlavor ) {
michael@0 600 nsXPIDLCString flavorStr;
michael@0 601 currentFlavor->ToString(getter_Copies(flavorStr));
michael@0 602 UINT format = GetFormat(flavorStr);
michael@0 603
michael@0 604 // Try to get the data using the desired flavor. This might fail, but all is
michael@0 605 // not lost.
michael@0 606 void* data = nullptr;
michael@0 607 uint32_t dataLen = 0;
michael@0 608 bool dataFound = false;
michael@0 609 if (nullptr != aDataObject) {
michael@0 610 if ( NS_SUCCEEDED(GetNativeDataOffClipboard(aDataObject, anIndex, format, flavorStr, &data, &dataLen)) )
michael@0 611 dataFound = true;
michael@0 612 }
michael@0 613 else if (nullptr != aWindow) {
michael@0 614 if ( NS_SUCCEEDED(GetNativeDataOffClipboard(aWindow, anIndex, format, &data, &dataLen)) )
michael@0 615 dataFound = true;
michael@0 616 }
michael@0 617
michael@0 618 // This is our second chance to try to find some data, having not found it
michael@0 619 // when directly asking for the flavor. Let's try digging around in other
michael@0 620 // flavors to help satisfy our craving for data.
michael@0 621 if ( !dataFound ) {
michael@0 622 if ( strcmp(flavorStr, kUnicodeMime) == 0 )
michael@0 623 dataFound = FindUnicodeFromPlainText ( aDataObject, anIndex, &data, &dataLen );
michael@0 624 else if ( strcmp(flavorStr, kURLMime) == 0 ) {
michael@0 625 // drags from other windows apps expose the native
michael@0 626 // CFSTR_INETURL{A,W} flavor
michael@0 627 dataFound = FindURLFromNativeURL ( aDataObject, anIndex, &data, &dataLen );
michael@0 628 if ( !dataFound )
michael@0 629 dataFound = FindURLFromLocalFile ( aDataObject, anIndex, &data, &dataLen );
michael@0 630 }
michael@0 631 } // if we try one last ditch effort to find our data
michael@0 632
michael@0 633 // Hopefully by this point we've found it and can go about our business
michael@0 634 if ( dataFound ) {
michael@0 635 nsCOMPtr<nsISupports> genericDataWrapper;
michael@0 636 if ( strcmp(flavorStr, kFileMime) == 0 ) {
michael@0 637 // we have a file path in |data|. Create an nsLocalFile object.
michael@0 638 nsDependentString filepath(reinterpret_cast<char16_t*>(data));
michael@0 639 nsCOMPtr<nsIFile> file;
michael@0 640 if ( NS_SUCCEEDED(NS_NewLocalFile(filepath, false, getter_AddRefs(file))) )
michael@0 641 genericDataWrapper = do_QueryInterface(file);
michael@0 642 nsMemory::Free(data);
michael@0 643 }
michael@0 644 else if ( strcmp(flavorStr, kNativeHTMLMime) == 0) {
michael@0 645 // the editor folks want CF_HTML exactly as it's on the clipboard, no conversions,
michael@0 646 // no fancy stuff. Pull it off the clipboard, stuff it into a wrapper and hand
michael@0 647 // it back to them.
michael@0 648 if ( FindPlatformHTML(aDataObject, anIndex, &data, &dataLen) )
michael@0 649 nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) );
michael@0 650 else
michael@0 651 {
michael@0 652 nsMemory::Free(data);
michael@0 653 continue; // something wrong with this flavor, keep looking for other data
michael@0 654 }
michael@0 655 nsMemory::Free(data);
michael@0 656 }
michael@0 657 else if ( strcmp(flavorStr, kJPEGImageMime) == 0 ||
michael@0 658 strcmp(flavorStr, kJPGImageMime) == 0 ||
michael@0 659 strcmp(flavorStr, kPNGImageMime) == 0) {
michael@0 660 nsIInputStream * imageStream = reinterpret_cast<nsIInputStream*>(data);
michael@0 661 genericDataWrapper = do_QueryInterface(imageStream);
michael@0 662 NS_IF_RELEASE(imageStream);
michael@0 663 }
michael@0 664 else {
michael@0 665 // we probably have some form of text. The DOM only wants LF, so convert from Win32 line
michael@0 666 // endings to DOM line endings.
michael@0 667 int32_t signedLen = static_cast<int32_t>(dataLen);
michael@0 668 nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( flavorStr, &data, &signedLen );
michael@0 669 dataLen = signedLen;
michael@0 670
michael@0 671 nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) );
michael@0 672 nsMemory::Free(data);
michael@0 673 }
michael@0 674
michael@0 675 NS_ASSERTION ( genericDataWrapper, "About to put null data into the transferable" );
michael@0 676 aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLen);
michael@0 677 res = NS_OK;
michael@0 678
michael@0 679 // we found one, get out of the loop
michael@0 680 break;
michael@0 681 }
michael@0 682
michael@0 683 }
michael@0 684 } // foreach flavor
michael@0 685
michael@0 686 return res;
michael@0 687
michael@0 688 }
michael@0 689
michael@0 690
michael@0 691
michael@0 692 //
michael@0 693 // FindPlatformHTML
michael@0 694 //
michael@0 695 // Someone asked for the OS CF_HTML flavor. We give it back to them exactly as-is.
michael@0 696 //
michael@0 697 bool
michael@0 698 nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen )
michael@0 699 {
michael@0 700 // Reference: MSDN doc entitled "HTML Clipboard Format"
michael@0 701 // http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx#unknown_854
michael@0 702 // CF_HTML is UTF8, not unicode. We also can't rely on it being null-terminated
michael@0 703 // so we have to check the CF_HTML header for the correct length.
michael@0 704 // The length we return is the bytecount from the beginning of the selected data to the end
michael@0 705 // of the selected data, without the null termination. Because it's UTF8, we're guaranteed
michael@0 706 // the header is ASCII.
michael@0 707
michael@0 708 if (!outData || !*outData) {
michael@0 709 return false;
michael@0 710 }
michael@0 711
michael@0 712 char version[8] = { 0 };
michael@0 713 int32_t startOfData = 0;
michael@0 714 int32_t endOfData = 0;
michael@0 715 int numFound = sscanf((char*)*outData, "Version:%7s\nStartHTML:%d\nEndHTML:%d",
michael@0 716 version, &startOfData, &endOfData);
michael@0 717
michael@0 718 if (numFound != 3 || startOfData < -1 || endOfData < -1) {
michael@0 719 return false;
michael@0 720 }
michael@0 721
michael@0 722 // Fixup the start and end markers if they have no context (set to -1)
michael@0 723 if (startOfData == -1) {
michael@0 724 startOfData = 0;
michael@0 725 }
michael@0 726 if (endOfData == -1) {
michael@0 727 endOfData = *outDataLen;
michael@0 728 }
michael@0 729
michael@0 730 // Make sure we were passed sane values within our buffer size.
michael@0 731 // (Note that we've handled all cases of negative endOfData above, so we can
michael@0 732 // safely cast it to be unsigned here.)
michael@0 733 if (!endOfData || startOfData >= endOfData ||
michael@0 734 static_cast<uint32_t>(endOfData) > *outDataLen) {
michael@0 735 return false;
michael@0 736 }
michael@0 737
michael@0 738 // We want to return the buffer not offset by startOfData because it will be
michael@0 739 // parsed out later (probably by nsHTMLEditor::ParseCFHTML) when it is still
michael@0 740 // in CF_HTML format.
michael@0 741 *outDataLen = endOfData;
michael@0 742 return true;
michael@0 743 }
michael@0 744
michael@0 745
michael@0 746 //
michael@0 747 // FindUnicodeFromPlainText
michael@0 748 //
michael@0 749 // we are looking for text/unicode and we failed to find it on the clipboard first,
michael@0 750 // try again with text/plain. If that is present, convert it to unicode.
michael@0 751 //
michael@0 752 bool
michael@0 753 nsClipboard :: FindUnicodeFromPlainText ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen )
michael@0 754 {
michael@0 755 bool dataFound = false;
michael@0 756
michael@0 757 // we are looking for text/unicode and we failed to find it on the clipboard first,
michael@0 758 // try again with text/plain. If that is present, convert it to unicode.
michael@0 759 nsresult loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, GetFormat(kTextMime), nullptr, outData, outDataLen);
michael@0 760 if ( NS_SUCCEEDED(loadResult) && *outData ) {
michael@0 761 const char* castedText = reinterpret_cast<char*>(*outData);
michael@0 762 char16_t* convertedText = nullptr;
michael@0 763 int32_t convertedTextLen = 0;
michael@0 764 nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode ( castedText, *outDataLen,
michael@0 765 &convertedText, &convertedTextLen );
michael@0 766 if ( convertedText ) {
michael@0 767 // out with the old, in with the new
michael@0 768 nsMemory::Free(*outData);
michael@0 769 *outData = convertedText;
michael@0 770 *outDataLen = convertedTextLen * sizeof(char16_t);
michael@0 771 dataFound = true;
michael@0 772 }
michael@0 773 } // if plain text data on clipboard
michael@0 774
michael@0 775 return dataFound;
michael@0 776
michael@0 777 } // FindUnicodeFromPlainText
michael@0 778
michael@0 779
michael@0 780 //
michael@0 781 // FindURLFromLocalFile
michael@0 782 //
michael@0 783 // we are looking for a URL and couldn't find it, try again with looking for
michael@0 784 // a local file. If we have one, it may either be a normal file or an internet shortcut.
michael@0 785 // In both cases, however, we can get a URL (it will be a file:// url in the
michael@0 786 // local file case).
michael@0 787 //
michael@0 788 bool
michael@0 789 nsClipboard :: FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen )
michael@0 790 {
michael@0 791 bool dataFound = false;
michael@0 792
michael@0 793 nsresult loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, GetFormat(kFileMime), nullptr, outData, outDataLen);
michael@0 794 if ( NS_SUCCEEDED(loadResult) && *outData ) {
michael@0 795 // we have a file path in |data|. Is it an internet shortcut or a normal file?
michael@0 796 const nsDependentString filepath(static_cast<char16_t*>(*outData));
michael@0 797 nsCOMPtr<nsIFile> file;
michael@0 798 nsresult rv = NS_NewLocalFile(filepath, true, getter_AddRefs(file));
michael@0 799 if (NS_FAILED(rv)) {
michael@0 800 nsMemory::Free(*outData);
michael@0 801 return dataFound;
michael@0 802 }
michael@0 803
michael@0 804 if ( IsInternetShortcut(filepath) ) {
michael@0 805 nsMemory::Free(*outData);
michael@0 806 nsAutoCString url;
michael@0 807 ResolveShortcut( file, url );
michael@0 808 if ( !url.IsEmpty() ) {
michael@0 809 // convert it to unicode and pass it out
michael@0 810 nsDependentString urlString(UTF8ToNewUnicode(url));
michael@0 811 // the internal mozilla URL format, text/x-moz-url, contains
michael@0 812 // URL\ntitle. We can guess the title from the file's name.
michael@0 813 nsAutoString title;
michael@0 814 file->GetLeafName(title);
michael@0 815 // We rely on IsInternetShortcut check that file has a .url extension.
michael@0 816 title.SetLength(title.Length() - 4);
michael@0 817 if (title.IsEmpty())
michael@0 818 title = urlString;
michael@0 819 *outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + title);
michael@0 820 *outDataLen = NS_strlen(static_cast<char16_t*>(*outData)) * sizeof(char16_t);
michael@0 821
michael@0 822 dataFound = true;
michael@0 823 }
michael@0 824 }
michael@0 825 else {
michael@0 826 // we have a normal file, use some Necko objects to get our file path
michael@0 827 nsAutoCString urlSpec;
michael@0 828 NS_GetURLSpecFromFile(file, urlSpec);
michael@0 829
michael@0 830 // convert it to unicode and pass it out
michael@0 831 nsMemory::Free(*outData);
michael@0 832 *outData = UTF8ToNewUnicode(urlSpec);
michael@0 833 *outDataLen = NS_strlen(static_cast<char16_t*>(*outData)) * sizeof(char16_t);
michael@0 834 dataFound = true;
michael@0 835 } // else regular file
michael@0 836 }
michael@0 837
michael@0 838 return dataFound;
michael@0 839 } // FindURLFromLocalFile
michael@0 840
michael@0 841 //
michael@0 842 // FindURLFromNativeURL
michael@0 843 //
michael@0 844 // we are looking for a URL and couldn't find it using our internal
michael@0 845 // URL flavor, so look for it using the native URL flavor,
michael@0 846 // CF_INETURLSTRW (We don't handle CF_INETURLSTRA currently)
michael@0 847 //
michael@0 848 bool
michael@0 849 nsClipboard :: FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen )
michael@0 850 {
michael@0 851 bool dataFound = false;
michael@0 852
michael@0 853 void* tempOutData = nullptr;
michael@0 854 uint32_t tempDataLen = 0;
michael@0 855
michael@0 856 nsresult loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, ::RegisterClipboardFormat(CFSTR_INETURLW), nullptr, &tempOutData, &tempDataLen);
michael@0 857 if ( NS_SUCCEEDED(loadResult) && tempOutData ) {
michael@0 858 nsDependentString urlString(static_cast<char16_t*>(tempOutData));
michael@0 859 // the internal mozilla URL format, text/x-moz-url, contains
michael@0 860 // URL\ntitle. Since we don't actually have a title here,
michael@0 861 // just repeat the URL to fake it.
michael@0 862 *outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + urlString);
michael@0 863 *outDataLen = NS_strlen(static_cast<char16_t*>(*outData)) * sizeof(char16_t);
michael@0 864 nsMemory::Free(tempOutData);
michael@0 865 dataFound = true;
michael@0 866 }
michael@0 867 else {
michael@0 868 loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, ::RegisterClipboardFormat(CFSTR_INETURLA), nullptr, &tempOutData, &tempDataLen);
michael@0 869 if ( NS_SUCCEEDED(loadResult) && tempOutData ) {
michael@0 870 // CFSTR_INETURLA is (currently) equal to CFSTR_SHELLURL which is equal to CF_TEXT
michael@0 871 // which is by definition ANSI encoded.
michael@0 872 nsCString urlUnescapedA;
michael@0 873 bool unescaped = NS_UnescapeURL(static_cast<char*>(tempOutData), tempDataLen, esc_OnlyNonASCII | esc_SkipControl, urlUnescapedA);
michael@0 874
michael@0 875 nsString urlString;
michael@0 876 if (unescaped)
michael@0 877 NS_CopyNativeToUnicode(urlUnescapedA, urlString);
michael@0 878 else
michael@0 879 NS_CopyNativeToUnicode(nsDependentCString(static_cast<char*>(tempOutData), tempDataLen), urlString);
michael@0 880
michael@0 881 // the internal mozilla URL format, text/x-moz-url, contains
michael@0 882 // URL\ntitle. Since we don't actually have a title here,
michael@0 883 // just repeat the URL to fake it.
michael@0 884 *outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + urlString);
michael@0 885 *outDataLen = NS_strlen(static_cast<char16_t*>(*outData)) * sizeof(char16_t);
michael@0 886 nsMemory::Free(tempOutData);
michael@0 887 dataFound = true;
michael@0 888 }
michael@0 889 }
michael@0 890
michael@0 891 return dataFound;
michael@0 892 } // FindURLFromNativeURL
michael@0 893
michael@0 894 //
michael@0 895 // ResolveShortcut
michael@0 896 //
michael@0 897 void
michael@0 898 nsClipboard :: ResolveShortcut ( nsIFile* aFile, nsACString& outURL )
michael@0 899 {
michael@0 900 nsCOMPtr<nsIFileProtocolHandler> fph;
michael@0 901 nsresult rv = NS_GetFileProtocolHandler(getter_AddRefs(fph));
michael@0 902 if (NS_FAILED(rv))
michael@0 903 return;
michael@0 904
michael@0 905 nsCOMPtr<nsIURI> uri;
michael@0 906 rv = fph->ReadURLFile(aFile, getter_AddRefs(uri));
michael@0 907 if (NS_FAILED(rv))
michael@0 908 return;
michael@0 909
michael@0 910 uri->GetSpec(outURL);
michael@0 911 } // ResolveShortcut
michael@0 912
michael@0 913
michael@0 914 //
michael@0 915 // IsInternetShortcut
michael@0 916 //
michael@0 917 // A file is an Internet Shortcut if it ends with .URL
michael@0 918 //
michael@0 919 bool
michael@0 920 nsClipboard :: IsInternetShortcut ( const nsAString& inFileName )
michael@0 921 {
michael@0 922 return StringEndsWith(inFileName, NS_LITERAL_STRING(".url"), nsCaseInsensitiveStringComparator());
michael@0 923 } // IsInternetShortcut
michael@0 924
michael@0 925
michael@0 926 //-------------------------------------------------------------------------
michael@0 927 NS_IMETHODIMP
michael@0 928 nsClipboard::GetNativeClipboardData ( nsITransferable * aTransferable, int32_t aWhichClipboard )
michael@0 929 {
michael@0 930 // make sure we have a good transferable
michael@0 931 if ( !aTransferable || aWhichClipboard != kGlobalClipboard )
michael@0 932 return NS_ERROR_FAILURE;
michael@0 933
michael@0 934 nsresult res;
michael@0 935
michael@0 936 // This makes sure we can use the OLE functionality for the clipboard
michael@0 937 IDataObject * dataObj;
michael@0 938 if (S_OK == ::OleGetClipboard(&dataObj)) {
michael@0 939 // Use OLE IDataObject for clipboard operations
michael@0 940 res = GetDataFromDataObject(dataObj, 0, nullptr, aTransferable);
michael@0 941 dataObj->Release();
michael@0 942 }
michael@0 943 else {
michael@0 944 // do it the old manual way
michael@0 945 res = GetDataFromDataObject(nullptr, 0, mWindow, aTransferable);
michael@0 946 }
michael@0 947 return res;
michael@0 948
michael@0 949 }
michael@0 950
michael@0 951 NS_IMETHODIMP
michael@0 952 nsClipboard::EmptyClipboard(int32_t aWhichClipboard)
michael@0 953 {
michael@0 954 // Some programs such as ZoneAlarm monitor clipboard usage and then open the
michael@0 955 // clipboard to scan it. If we i) empty and then ii) set data, then the
michael@0 956 // 'set data' can sometimes fail with access denied becacuse another program
michael@0 957 // has the clipboard open. So to avoid this race condition for OpenClipboard
michael@0 958 // we do not empty the clipboard when we're setting it.
michael@0 959 if (aWhichClipboard == kGlobalClipboard && !mEmptyingForSetData) {
michael@0 960 OleSetClipboard(nullptr);
michael@0 961 }
michael@0 962 return nsBaseClipboard::EmptyClipboard(aWhichClipboard);
michael@0 963 }
michael@0 964
michael@0 965 //-------------------------------------------------------------------------
michael@0 966 NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(const char** aFlavorList,
michael@0 967 uint32_t aLength,
michael@0 968 int32_t aWhichClipboard,
michael@0 969 bool *_retval)
michael@0 970 {
michael@0 971 *_retval = false;
michael@0 972 if (aWhichClipboard != kGlobalClipboard || !aFlavorList)
michael@0 973 return NS_OK;
michael@0 974
michael@0 975 for (uint32_t i = 0;i < aLength; ++i) {
michael@0 976 #ifdef DEBUG
michael@0 977 if (strcmp(aFlavorList[i], kTextMime) == 0)
michael@0 978 NS_WARNING ( "DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD" );
michael@0 979 #endif
michael@0 980
michael@0 981 UINT format = GetFormat(aFlavorList[i]);
michael@0 982 if (IsClipboardFormatAvailable(format)) {
michael@0 983 *_retval = true;
michael@0 984 break;
michael@0 985 }
michael@0 986 else {
michael@0 987 // We haven't found the exact flavor the client asked for, but maybe we can
michael@0 988 // still find it from something else that's on the clipboard...
michael@0 989 if (strcmp(aFlavorList[i], kUnicodeMime) == 0) {
michael@0 990 // client asked for unicode and it wasn't present, check if we have CF_TEXT.
michael@0 991 // We'll handle the actual data substitution in the data object.
michael@0 992 if (IsClipboardFormatAvailable(GetFormat(kTextMime)))
michael@0 993 *_retval = true;
michael@0 994 }
michael@0 995 }
michael@0 996 }
michael@0 997
michael@0 998 return NS_OK;
michael@0 999 }

mercurial