1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsClipboard.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,999 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsClipboard.h" 1.10 +#include <ole2.h> 1.11 +#include <shlobj.h> 1.12 +#include <intshcut.h> 1.13 + 1.14 +// shellapi.h is needed to build with WIN32_LEAN_AND_MEAN 1.15 +#include <shellapi.h> 1.16 + 1.17 +#include "nsCOMPtr.h" 1.18 +#include "nsDataObj.h" 1.19 +#include "nsIClipboardOwner.h" 1.20 +#include "nsString.h" 1.21 +#include "nsNativeCharsetUtils.h" 1.22 +#include "nsIFormatConverter.h" 1.23 +#include "nsITransferable.h" 1.24 +#include "nsCOMPtr.h" 1.25 +#include "nsXPCOM.h" 1.26 +#include "nsISupportsPrimitives.h" 1.27 +#include "nsXPIDLString.h" 1.28 +#include "nsReadableUtils.h" 1.29 +#include "nsUnicharUtils.h" 1.30 +#include "nsPrimitiveHelpers.h" 1.31 +#include "nsImageClipboard.h" 1.32 +#include "nsIWidget.h" 1.33 +#include "nsIComponentManager.h" 1.34 +#include "nsWidgetsCID.h" 1.35 +#include "nsCRT.h" 1.36 +#include "nsNetUtil.h" 1.37 +#include "nsEscape.h" 1.38 +#include "nsIObserverService.h" 1.39 + 1.40 +#ifdef PR_LOGGING 1.41 +PRLogModuleInfo* gWin32ClipboardLog = nullptr; 1.42 +#endif 1.43 + 1.44 +// oddly, this isn't in the MSVC headers anywhere. 1.45 +UINT nsClipboard::CF_HTML = ::RegisterClipboardFormatW(L"HTML Format"); 1.46 + 1.47 + 1.48 +//------------------------------------------------------------------------- 1.49 +// 1.50 +// nsClipboard constructor 1.51 +// 1.52 +//------------------------------------------------------------------------- 1.53 +nsClipboard::nsClipboard() : nsBaseClipboard() 1.54 +{ 1.55 +#ifdef PR_LOGGING 1.56 + if (!gWin32ClipboardLog) { 1.57 + gWin32ClipboardLog = PR_NewLogModule("nsClipboard"); 1.58 + } 1.59 +#endif 1.60 + 1.61 + mIgnoreEmptyNotification = false; 1.62 + mWindow = nullptr; 1.63 + 1.64 + // Register for a shutdown notification so that we can flush data 1.65 + // to the OS clipboard. 1.66 + nsCOMPtr<nsIObserverService> observerService = 1.67 + do_GetService("@mozilla.org/observer-service;1"); 1.68 + if (observerService) 1.69 + observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); 1.70 +} 1.71 + 1.72 +//------------------------------------------------------------------------- 1.73 +// nsClipboard destructor 1.74 +//------------------------------------------------------------------------- 1.75 +nsClipboard::~nsClipboard() 1.76 +{ 1.77 + 1.78 +} 1.79 + 1.80 +NS_IMPL_ISUPPORTS_INHERITED(nsClipboard, nsBaseClipboard, nsIObserver) 1.81 + 1.82 +NS_IMETHODIMP 1.83 +nsClipboard::Observe(nsISupports *aSubject, const char *aTopic, 1.84 + const char16_t *aData) 1.85 +{ 1.86 + // This will be called on shutdown. 1.87 + ::OleFlushClipboard(); 1.88 + ::CloseClipboard(); 1.89 + 1.90 + return NS_OK; 1.91 +} 1.92 + 1.93 +//------------------------------------------------------------------------- 1.94 +UINT nsClipboard::GetFormat(const char* aMimeStr) 1.95 +{ 1.96 + UINT format; 1.97 + 1.98 + if (strcmp(aMimeStr, kTextMime) == 0) 1.99 + format = CF_TEXT; 1.100 + else if (strcmp(aMimeStr, kUnicodeMime) == 0) 1.101 + format = CF_UNICODETEXT; 1.102 + else if (strcmp(aMimeStr, kJPEGImageMime) == 0 || 1.103 + strcmp(aMimeStr, kJPGImageMime) == 0 || 1.104 + strcmp(aMimeStr, kPNGImageMime) == 0) 1.105 + format = CF_DIBV5; 1.106 + else if (strcmp(aMimeStr, kFileMime) == 0 || 1.107 + strcmp(aMimeStr, kFilePromiseMime) == 0) 1.108 + format = CF_HDROP; 1.109 + else if (strcmp(aMimeStr, kNativeHTMLMime) == 0) 1.110 + format = CF_HTML; 1.111 + else 1.112 + format = ::RegisterClipboardFormatW(NS_ConvertASCIItoUTF16(aMimeStr).get()); 1.113 + 1.114 + return format; 1.115 +} 1.116 + 1.117 +//------------------------------------------------------------------------- 1.118 +nsresult nsClipboard::CreateNativeDataObject(nsITransferable * aTransferable, IDataObject ** aDataObj, nsIURI * uri) 1.119 +{ 1.120 + if (nullptr == aTransferable) { 1.121 + return NS_ERROR_FAILURE; 1.122 + } 1.123 + 1.124 + // Create our native DataObject that implements 1.125 + // the OLE IDataObject interface 1.126 + nsDataObj * dataObj = new nsDataObj(uri); 1.127 + 1.128 + if (!dataObj) 1.129 + return NS_ERROR_OUT_OF_MEMORY; 1.130 + 1.131 + dataObj->AddRef(); 1.132 + 1.133 + // Now set it up with all the right data flavors & enums 1.134 + nsresult res = SetupNativeDataObject(aTransferable, dataObj); 1.135 + if (NS_OK == res) { 1.136 + *aDataObj = dataObj; 1.137 + } else { 1.138 + delete dataObj; 1.139 + } 1.140 + return res; 1.141 +} 1.142 + 1.143 +//------------------------------------------------------------------------- 1.144 +nsresult nsClipboard::SetupNativeDataObject(nsITransferable * aTransferable, IDataObject * aDataObj) 1.145 +{ 1.146 + if (nullptr == aTransferable || nullptr == aDataObj) { 1.147 + return NS_ERROR_FAILURE; 1.148 + } 1.149 + 1.150 + nsDataObj * dObj = static_cast<nsDataObj *>(aDataObj); 1.151 + 1.152 + // Now give the Transferable to the DataObject 1.153 + // for getting the data out of it 1.154 + dObj->SetTransferable(aTransferable); 1.155 + 1.156 + // Get the transferable list of data flavors 1.157 + nsCOMPtr<nsISupportsArray> dfList; 1.158 + aTransferable->FlavorsTransferableCanExport(getter_AddRefs(dfList)); 1.159 + 1.160 + // Walk through flavors that contain data and register them 1.161 + // into the DataObj as supported flavors 1.162 + uint32_t i; 1.163 + uint32_t cnt; 1.164 + dfList->Count(&cnt); 1.165 + for (i=0;i<cnt;i++) { 1.166 + nsCOMPtr<nsISupports> genericFlavor; 1.167 + dfList->GetElementAt ( i, getter_AddRefs(genericFlavor) ); 1.168 + nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) ); 1.169 + if ( currentFlavor ) { 1.170 + nsXPIDLCString flavorStr; 1.171 + currentFlavor->ToString(getter_Copies(flavorStr)); 1.172 + UINT format = GetFormat(flavorStr); 1.173 + 1.174 + // Now tell the native IDataObject about both our mime type and 1.175 + // the native data format 1.176 + FORMATETC fe; 1.177 + SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); 1.178 + dObj->AddDataFlavor(flavorStr, &fe); 1.179 + 1.180 + // Do various things internal to the implementation, like map one 1.181 + // flavor to another or add additional flavors based on what's required 1.182 + // for the win32 impl. 1.183 + if ( strcmp(flavorStr, kUnicodeMime) == 0 ) { 1.184 + // if we find text/unicode, also advertise text/plain (which we will convert 1.185 + // on our own in nsDataObj::GetText(). 1.186 + FORMATETC textFE; 1.187 + SET_FORMATETC(textFE, CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); 1.188 + dObj->AddDataFlavor(kTextMime, &textFE); 1.189 + } 1.190 + else if ( strcmp(flavorStr, kHTMLMime) == 0 ) { 1.191 + // if we find text/html, also advertise win32's html flavor (which we will convert 1.192 + // on our own in nsDataObj::GetText(). 1.193 + FORMATETC htmlFE; 1.194 + SET_FORMATETC(htmlFE, CF_HTML, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); 1.195 + dObj->AddDataFlavor(kHTMLMime, &htmlFE); 1.196 + } 1.197 + else if ( strcmp(flavorStr, kURLMime) == 0 ) { 1.198 + // if we're a url, in addition to also being text, we need to register 1.199 + // the "file" flavors so that the win32 shell knows to create an internet 1.200 + // shortcut when it sees one of these beasts. 1.201 + FORMATETC shortcutFE; 1.202 + SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) 1.203 + dObj->AddDataFlavor(kURLMime, &shortcutFE); 1.204 + SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) 1.205 + dObj->AddDataFlavor(kURLMime, &shortcutFE); 1.206 + SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) 1.207 + dObj->AddDataFlavor(kURLMime, &shortcutFE); 1.208 + SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) 1.209 + dObj->AddDataFlavor(kURLMime, &shortcutFE); 1.210 + SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) 1.211 + dObj->AddDataFlavor(kURLMime, &shortcutFE); 1.212 + } 1.213 + else if ( strcmp(flavorStr, kPNGImageMime) == 0 || strcmp(flavorStr, kJPEGImageMime) == 0 || 1.214 + strcmp(flavorStr, kJPGImageMime) == 0 || strcmp(flavorStr, kGIFImageMime) == 0 || 1.215 + strcmp(flavorStr, kNativeImageMime) == 0 ) { 1.216 + // if we're an image, register the native bitmap flavor 1.217 + FORMATETC imageFE; 1.218 + // Add DIBv5 1.219 + SET_FORMATETC(imageFE, CF_DIBV5, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) 1.220 + dObj->AddDataFlavor(flavorStr, &imageFE); 1.221 + // Add DIBv3 1.222 + SET_FORMATETC(imageFE, CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) 1.223 + dObj->AddDataFlavor(flavorStr, &imageFE); 1.224 + } 1.225 + else if ( strcmp(flavorStr, kFilePromiseMime) == 0 ) { 1.226 + // if we're a file promise flavor, also register the 1.227 + // CFSTR_PREFERREDDROPEFFECT format. The data object 1.228 + // returns a value of DROPEFFECTS_MOVE to the drop target 1.229 + // when it asks for the value of this format. This causes 1.230 + // the file to be moved from the temporary location instead 1.231 + // of being copied. The right thing to do here is to call 1.232 + // SetData() on the data object and set the value of this format 1.233 + // to DROPEFFECTS_MOVE on this particular data object. But, 1.234 + // since all the other clipboard formats follow the model of setting 1.235 + // data on the data object only when the drop object calls GetData(), 1.236 + // I am leaving this format's value hard coded in the data object. 1.237 + // We can change this if other consumers of this format get added to this 1.238 + // codebase and they need different values. 1.239 + FORMATETC shortcutFE; 1.240 + SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) 1.241 + dObj->AddDataFlavor(kFilePromiseMime, &shortcutFE); 1.242 + } 1.243 + } 1.244 + } 1.245 + 1.246 + return NS_OK; 1.247 +} 1.248 + 1.249 +//------------------------------------------------------------------------- 1.250 +NS_IMETHODIMP nsClipboard::SetNativeClipboardData ( int32_t aWhichClipboard ) 1.251 +{ 1.252 + if ( aWhichClipboard != kGlobalClipboard ) 1.253 + return NS_ERROR_FAILURE; 1.254 + 1.255 + mIgnoreEmptyNotification = true; 1.256 + 1.257 + // make sure we have a good transferable 1.258 + if (nullptr == mTransferable) { 1.259 + return NS_ERROR_FAILURE; 1.260 + } 1.261 + 1.262 + IDataObject * dataObj; 1.263 + if ( NS_SUCCEEDED(CreateNativeDataObject(mTransferable, &dataObj, nullptr)) ) { // this add refs dataObj 1.264 + ::OleSetClipboard(dataObj); 1.265 + dataObj->Release(); 1.266 + } else { 1.267 + // Clear the native clipboard 1.268 + ::OleSetClipboard(nullptr); 1.269 + } 1.270 + 1.271 + mIgnoreEmptyNotification = false; 1.272 + 1.273 + return NS_OK; 1.274 +} 1.275 + 1.276 + 1.277 +//------------------------------------------------------------------------- 1.278 +nsresult nsClipboard::GetGlobalData(HGLOBAL aHGBL, void ** aData, uint32_t * aLen) 1.279 +{ 1.280 + // Allocate a new memory buffer and copy the data from global memory. 1.281 + // Recall that win98 allocates to nearest DWORD boundary. As a safety 1.282 + // precaution, allocate an extra 2 bytes (but don't report them!) and 1.283 + // null them out to ensure that all of our strlen calls will succeed. 1.284 + nsresult result = NS_ERROR_FAILURE; 1.285 + if (aHGBL != nullptr) { 1.286 + LPSTR lpStr = (LPSTR) GlobalLock(aHGBL); 1.287 + DWORD allocSize = GlobalSize(aHGBL); 1.288 + char* data = static_cast<char*>(nsMemory::Alloc(allocSize + sizeof(char16_t))); 1.289 + if ( data ) { 1.290 + memcpy ( data, lpStr, allocSize ); 1.291 + data[allocSize] = data[allocSize + 1] = '\0'; // null terminate for safety 1.292 + 1.293 + GlobalUnlock(aHGBL); 1.294 + *aData = data; 1.295 + *aLen = allocSize; 1.296 + 1.297 + result = NS_OK; 1.298 + } 1.299 + } else { 1.300 +#ifdef MOZ_METRO 1.301 + return result; 1.302 +#endif 1.303 + // We really shouldn't ever get here 1.304 + // but just in case 1.305 + *aData = nullptr; 1.306 + *aLen = 0; 1.307 + LPVOID lpMsgBuf; 1.308 + 1.309 + FormatMessageW( 1.310 + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 1.311 + nullptr, 1.312 + GetLastError(), 1.313 + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language 1.314 + (LPWSTR) &lpMsgBuf, 1.315 + 0, 1.316 + nullptr 1.317 + ); 1.318 + 1.319 + // Display the string. 1.320 + MessageBoxW( nullptr, (LPCWSTR) lpMsgBuf, L"GetLastError", 1.321 + MB_OK | MB_ICONINFORMATION ); 1.322 + 1.323 + // Free the buffer. 1.324 + LocalFree( lpMsgBuf ); 1.325 + } 1.326 + 1.327 + return result; 1.328 +} 1.329 + 1.330 +//------------------------------------------------------------------------- 1.331 +nsresult nsClipboard::GetNativeDataOffClipboard(nsIWidget * aWidget, UINT /*aIndex*/, UINT aFormat, void ** aData, uint32_t * aLen) 1.332 +{ 1.333 + HGLOBAL hglb; 1.334 + nsresult result = NS_ERROR_FAILURE; 1.335 + 1.336 + HWND nativeWin = nullptr; 1.337 + if (::OpenClipboard(nativeWin)) { 1.338 + hglb = ::GetClipboardData(aFormat); 1.339 + result = GetGlobalData(hglb, aData, aLen); 1.340 + ::CloseClipboard(); 1.341 + } 1.342 + return result; 1.343 +} 1.344 + 1.345 +static void DisplayErrCode(HRESULT hres) 1.346 +{ 1.347 +#if defined(DEBUG_rods) || defined(DEBUG_pinkerton) 1.348 + if (hres == E_INVALIDARG) { 1.349 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("E_INVALIDARG\n")); 1.350 + } else 1.351 + if (hres == E_UNEXPECTED) { 1.352 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("E_UNEXPECTED\n")); 1.353 + } else 1.354 + if (hres == E_OUTOFMEMORY) { 1.355 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("E_OUTOFMEMORY\n")); 1.356 + } else 1.357 + if (hres == DV_E_LINDEX ) { 1.358 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_LINDEX\n")); 1.359 + } else 1.360 + if (hres == DV_E_FORMATETC) { 1.361 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_FORMATETC\n")); 1.362 + } else 1.363 + if (hres == DV_E_TYMED) { 1.364 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_TYMED\n")); 1.365 + } else 1.366 + if (hres == DV_E_DVASPECT) { 1.367 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_DVASPECT\n")); 1.368 + } else 1.369 + if (hres == OLE_E_NOTRUNNING) { 1.370 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("OLE_E_NOTRUNNING\n")); 1.371 + } else 1.372 + if (hres == STG_E_MEDIUMFULL) { 1.373 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("STG_E_MEDIUMFULL\n")); 1.374 + } else 1.375 + if (hres == DV_E_CLIPFORMAT) { 1.376 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("DV_E_CLIPFORMAT\n")); 1.377 + } else 1.378 + if (hres == S_OK) { 1.379 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, ("S_OK\n")); 1.380 + } else { 1.381 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, 1.382 + ("****** DisplayErrCode 0x%X\n", hres)); 1.383 + } 1.384 +#endif 1.385 +} 1.386 + 1.387 +//------------------------------------------------------------------------- 1.388 +static HRESULT FillSTGMedium(IDataObject * aDataObject, UINT aFormat, LPFORMATETC pFE, LPSTGMEDIUM pSTM, DWORD aTymed) 1.389 +{ 1.390 + SET_FORMATETC(*pFE, aFormat, 0, DVASPECT_CONTENT, -1, aTymed); 1.391 + 1.392 + // Starting by querying for the data to see if we can get it as from global memory 1.393 + HRESULT hres = S_FALSE; 1.394 + hres = aDataObject->QueryGetData(pFE); 1.395 + DisplayErrCode(hres); 1.396 + if (S_OK == hres) { 1.397 + hres = aDataObject->GetData(pFE, pSTM); 1.398 + DisplayErrCode(hres); 1.399 + } 1.400 + return hres; 1.401 +} 1.402 + 1.403 + 1.404 +//------------------------------------------------------------------------- 1.405 +// If aFormat is CF_DIBV5, aMIMEImageFormat must be a type for which we have 1.406 +// an image encoder (e.g. image/png). 1.407 +// For other values of aFormat, it is OK to pass null for aMIMEImageFormat. 1.408 +nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject * aDataObject, UINT aIndex, UINT aFormat, const char * aMIMEImageFormat, void ** aData, uint32_t * aLen) 1.409 +{ 1.410 + nsresult result = NS_ERROR_FAILURE; 1.411 + *aData = nullptr; 1.412 + *aLen = 0; 1.413 + 1.414 + if ( !aDataObject ) 1.415 + return result; 1.416 + 1.417 + UINT format = aFormat; 1.418 + HRESULT hres = S_FALSE; 1.419 + 1.420 + // XXX at the moment we only support global memory transfers 1.421 + // It is here where we will add support for native images 1.422 + // and IStream 1.423 + FORMATETC fe; 1.424 + STGMEDIUM stm; 1.425 + hres = FillSTGMedium(aDataObject, format, &fe, &stm, TYMED_HGLOBAL); 1.426 + 1.427 + // Currently this is only handling TYMED_HGLOBAL data 1.428 + // For Text, Dibs, Files, and generic data (like HTML) 1.429 + if (S_OK == hres) { 1.430 + static CLIPFORMAT fileDescriptorFlavorA = ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORA ); 1.431 + static CLIPFORMAT fileDescriptorFlavorW = ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORW ); 1.432 + static CLIPFORMAT fileFlavor = ::RegisterClipboardFormat( CFSTR_FILECONTENTS ); 1.433 + static CLIPFORMAT preferredDropEffect = ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT); 1.434 + 1.435 + switch (stm.tymed) { 1.436 + case TYMED_HGLOBAL: 1.437 + { 1.438 + switch (fe.cfFormat) { 1.439 + case CF_TEXT: 1.440 + { 1.441 + // Get the data out of the global data handle. The size we return 1.442 + // should not include the null because the other platforms don't 1.443 + // use nulls, so just return the length we get back from strlen(), 1.444 + // since we know CF_TEXT is null terminated. Recall that GetGlobalData() 1.445 + // returns the size of the allocated buffer, not the size of the data 1.446 + // (on 98, these are not the same) so we can't use that. 1.447 + uint32_t allocLen = 0; 1.448 + if ( NS_SUCCEEDED(GetGlobalData(stm.hGlobal, aData, &allocLen)) ) { 1.449 + *aLen = strlen ( reinterpret_cast<char*>(*aData) ); 1.450 + result = NS_OK; 1.451 + } 1.452 + } break; 1.453 + 1.454 + case CF_UNICODETEXT: 1.455 + { 1.456 + // Get the data out of the global data handle. The size we return 1.457 + // should not include the null because the other platforms don't 1.458 + // use nulls, so just return the length we get back from strlen(), 1.459 + // since we know CF_UNICODETEXT is null terminated. Recall that GetGlobalData() 1.460 + // returns the size of the allocated buffer, not the size of the data 1.461 + // (on 98, these are not the same) so we can't use that. 1.462 + uint32_t allocLen = 0; 1.463 + if ( NS_SUCCEEDED(GetGlobalData(stm.hGlobal, aData, &allocLen)) ) { 1.464 + *aLen = NS_strlen(reinterpret_cast<char16_t*>(*aData)) * 2; 1.465 + result = NS_OK; 1.466 + } 1.467 + } break; 1.468 + 1.469 + case CF_DIBV5: 1.470 + if (aMIMEImageFormat) 1.471 + { 1.472 + uint32_t allocLen = 0; 1.473 + unsigned char * clipboardData; 1.474 + if (NS_SUCCEEDED(GetGlobalData(stm.hGlobal, (void **)&clipboardData, &allocLen))) 1.475 + { 1.476 + nsImageFromClipboard converter; 1.477 + nsIInputStream * inputStream; 1.478 + converter.GetEncodedImageStream(clipboardData, aMIMEImageFormat, &inputStream); // addrefs for us, don't release 1.479 + if ( inputStream ) { 1.480 + *aData = inputStream; 1.481 + *aLen = sizeof(nsIInputStream*); 1.482 + result = NS_OK; 1.483 + } 1.484 + } 1.485 + } break; 1.486 + 1.487 + case CF_HDROP : 1.488 + { 1.489 + // in the case of a file drop, multiple files are stashed within a 1.490 + // single data object. In order to match mozilla's D&D apis, we 1.491 + // just pull out the file at the requested index, pretending as 1.492 + // if there really are multiple drag items. 1.493 + HDROP dropFiles = (HDROP) GlobalLock(stm.hGlobal); 1.494 + 1.495 + UINT numFiles = ::DragQueryFileW(dropFiles, 0xFFFFFFFF, nullptr, 0); 1.496 + NS_ASSERTION ( numFiles > 0, "File drop flavor, but no files...hmmmm" ); 1.497 + NS_ASSERTION ( aIndex < numFiles, "Asked for a file index out of range of list" ); 1.498 + if (numFiles > 0) { 1.499 + UINT fileNameLen = ::DragQueryFileW(dropFiles, aIndex, nullptr, 0); 1.500 + wchar_t* buffer = reinterpret_cast<wchar_t*>(nsMemory::Alloc((fileNameLen + 1) * sizeof(wchar_t))); 1.501 + if ( buffer ) { 1.502 + ::DragQueryFileW(dropFiles, aIndex, buffer, fileNameLen + 1); 1.503 + *aData = buffer; 1.504 + *aLen = fileNameLen * sizeof(char16_t); 1.505 + result = NS_OK; 1.506 + } 1.507 + else 1.508 + result = NS_ERROR_OUT_OF_MEMORY; 1.509 + } 1.510 + GlobalUnlock (stm.hGlobal) ; 1.511 + 1.512 + } break; 1.513 + 1.514 + default: { 1.515 + if ( fe.cfFormat == fileDescriptorFlavorA || fe.cfFormat == fileDescriptorFlavorW || fe.cfFormat == fileFlavor ) { 1.516 + NS_WARNING ( "Mozilla doesn't yet understand how to read this type of file flavor" ); 1.517 + } 1.518 + else 1.519 + { 1.520 + // Get the data out of the global data handle. The size we return 1.521 + // should not include the null because the other platforms don't 1.522 + // use nulls, so just return the length we get back from strlen(), 1.523 + // since we know CF_UNICODETEXT is null terminated. Recall that GetGlobalData() 1.524 + // returns the size of the allocated buffer, not the size of the data 1.525 + // (on 98, these are not the same) so we can't use that. 1.526 + // 1.527 + // NOTE: we are assuming that anything that falls into this default case 1.528 + // is unicode. As we start to get more kinds of binary data, this 1.529 + // may become an incorrect assumption. Stay tuned. 1.530 + uint32_t allocLen = 0; 1.531 + if ( NS_SUCCEEDED(GetGlobalData(stm.hGlobal, aData, &allocLen)) ) { 1.532 + if ( fe.cfFormat == CF_HTML ) { 1.533 + // CF_HTML is actually UTF8, not unicode, so disregard the assumption 1.534 + // above. We have to check the header for the actual length, and we'll 1.535 + // do that in FindPlatformHTML(). For now, return the allocLen. This 1.536 + // case is mostly to ensure we don't try to call strlen on the buffer. 1.537 + *aLen = allocLen; 1.538 + } else if (fe.cfFormat == preferredDropEffect) { 1.539 + // As per the MSDN doc entitled: "Shell Clipboard Formats" 1.540 + // CFSTR_PREFERREDDROPEFFECT should return a DWORD 1.541 + // Reference: http://msdn.microsoft.com/en-us/library/bb776902(v=vs.85).aspx 1.542 + NS_ASSERTION(allocLen == sizeof(DWORD), 1.543 + "CFSTR_PREFERREDDROPEFFECT should return a DWORD"); 1.544 + *aLen = allocLen; 1.545 + } else { 1.546 + *aLen = NS_strlen(reinterpret_cast<char16_t*>(*aData)) * 1.547 + sizeof(char16_t); 1.548 + } 1.549 + result = NS_OK; 1.550 + } 1.551 + } 1.552 + } break; 1.553 + } // switch 1.554 + } break; 1.555 + 1.556 + case TYMED_GDI: 1.557 + { 1.558 +#ifdef DEBUG 1.559 + PR_LOG(gWin32ClipboardLog, PR_LOG_ALWAYS, 1.560 + ("*********************** TYMED_GDI\n")); 1.561 +#endif 1.562 + } break; 1.563 + 1.564 + default: 1.565 + break; 1.566 + } //switch 1.567 + 1.568 + ReleaseStgMedium(&stm); 1.569 + } 1.570 + 1.571 + return result; 1.572 +} 1.573 + 1.574 + 1.575 +//------------------------------------------------------------------------- 1.576 +nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject, 1.577 + UINT anIndex, 1.578 + nsIWidget * aWindow, 1.579 + nsITransferable * aTransferable) 1.580 +{ 1.581 + // make sure we have a good transferable 1.582 + if ( !aTransferable ) 1.583 + return NS_ERROR_INVALID_ARG; 1.584 + 1.585 + nsresult res = NS_ERROR_FAILURE; 1.586 + 1.587 + // get flavor list that includes all flavors that can be written (including ones 1.588 + // obtained through conversion) 1.589 + nsCOMPtr<nsISupportsArray> flavorList; 1.590 + res = aTransferable->FlavorsTransferableCanImport ( getter_AddRefs(flavorList) ); 1.591 + if ( NS_FAILED(res) ) 1.592 + return NS_ERROR_FAILURE; 1.593 + 1.594 + // Walk through flavors and see which flavor is on the clipboard them on the native clipboard, 1.595 + uint32_t i; 1.596 + uint32_t cnt; 1.597 + flavorList->Count(&cnt); 1.598 + for (i=0;i<cnt;i++) { 1.599 + nsCOMPtr<nsISupports> genericFlavor; 1.600 + flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) ); 1.601 + nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) ); 1.602 + if ( currentFlavor ) { 1.603 + nsXPIDLCString flavorStr; 1.604 + currentFlavor->ToString(getter_Copies(flavorStr)); 1.605 + UINT format = GetFormat(flavorStr); 1.606 + 1.607 + // Try to get the data using the desired flavor. This might fail, but all is 1.608 + // not lost. 1.609 + void* data = nullptr; 1.610 + uint32_t dataLen = 0; 1.611 + bool dataFound = false; 1.612 + if (nullptr != aDataObject) { 1.613 + if ( NS_SUCCEEDED(GetNativeDataOffClipboard(aDataObject, anIndex, format, flavorStr, &data, &dataLen)) ) 1.614 + dataFound = true; 1.615 + } 1.616 + else if (nullptr != aWindow) { 1.617 + if ( NS_SUCCEEDED(GetNativeDataOffClipboard(aWindow, anIndex, format, &data, &dataLen)) ) 1.618 + dataFound = true; 1.619 + } 1.620 + 1.621 + // This is our second chance to try to find some data, having not found it 1.622 + // when directly asking for the flavor. Let's try digging around in other 1.623 + // flavors to help satisfy our craving for data. 1.624 + if ( !dataFound ) { 1.625 + if ( strcmp(flavorStr, kUnicodeMime) == 0 ) 1.626 + dataFound = FindUnicodeFromPlainText ( aDataObject, anIndex, &data, &dataLen ); 1.627 + else if ( strcmp(flavorStr, kURLMime) == 0 ) { 1.628 + // drags from other windows apps expose the native 1.629 + // CFSTR_INETURL{A,W} flavor 1.630 + dataFound = FindURLFromNativeURL ( aDataObject, anIndex, &data, &dataLen ); 1.631 + if ( !dataFound ) 1.632 + dataFound = FindURLFromLocalFile ( aDataObject, anIndex, &data, &dataLen ); 1.633 + } 1.634 + } // if we try one last ditch effort to find our data 1.635 + 1.636 + // Hopefully by this point we've found it and can go about our business 1.637 + if ( dataFound ) { 1.638 + nsCOMPtr<nsISupports> genericDataWrapper; 1.639 + if ( strcmp(flavorStr, kFileMime) == 0 ) { 1.640 + // we have a file path in |data|. Create an nsLocalFile object. 1.641 + nsDependentString filepath(reinterpret_cast<char16_t*>(data)); 1.642 + nsCOMPtr<nsIFile> file; 1.643 + if ( NS_SUCCEEDED(NS_NewLocalFile(filepath, false, getter_AddRefs(file))) ) 1.644 + genericDataWrapper = do_QueryInterface(file); 1.645 + nsMemory::Free(data); 1.646 + } 1.647 + else if ( strcmp(flavorStr, kNativeHTMLMime) == 0) { 1.648 + // the editor folks want CF_HTML exactly as it's on the clipboard, no conversions, 1.649 + // no fancy stuff. Pull it off the clipboard, stuff it into a wrapper and hand 1.650 + // it back to them. 1.651 + if ( FindPlatformHTML(aDataObject, anIndex, &data, &dataLen) ) 1.652 + nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) ); 1.653 + else 1.654 + { 1.655 + nsMemory::Free(data); 1.656 + continue; // something wrong with this flavor, keep looking for other data 1.657 + } 1.658 + nsMemory::Free(data); 1.659 + } 1.660 + else if ( strcmp(flavorStr, kJPEGImageMime) == 0 || 1.661 + strcmp(flavorStr, kJPGImageMime) == 0 || 1.662 + strcmp(flavorStr, kPNGImageMime) == 0) { 1.663 + nsIInputStream * imageStream = reinterpret_cast<nsIInputStream*>(data); 1.664 + genericDataWrapper = do_QueryInterface(imageStream); 1.665 + NS_IF_RELEASE(imageStream); 1.666 + } 1.667 + else { 1.668 + // we probably have some form of text. The DOM only wants LF, so convert from Win32 line 1.669 + // endings to DOM line endings. 1.670 + int32_t signedLen = static_cast<int32_t>(dataLen); 1.671 + nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( flavorStr, &data, &signedLen ); 1.672 + dataLen = signedLen; 1.673 + 1.674 + nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) ); 1.675 + nsMemory::Free(data); 1.676 + } 1.677 + 1.678 + NS_ASSERTION ( genericDataWrapper, "About to put null data into the transferable" ); 1.679 + aTransferable->SetTransferData(flavorStr, genericDataWrapper, dataLen); 1.680 + res = NS_OK; 1.681 + 1.682 + // we found one, get out of the loop 1.683 + break; 1.684 + } 1.685 + 1.686 + } 1.687 + } // foreach flavor 1.688 + 1.689 + return res; 1.690 + 1.691 +} 1.692 + 1.693 + 1.694 + 1.695 +// 1.696 +// FindPlatformHTML 1.697 +// 1.698 +// Someone asked for the OS CF_HTML flavor. We give it back to them exactly as-is. 1.699 +// 1.700 +bool 1.701 +nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) 1.702 +{ 1.703 + // Reference: MSDN doc entitled "HTML Clipboard Format" 1.704 + // http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx#unknown_854 1.705 + // CF_HTML is UTF8, not unicode. We also can't rely on it being null-terminated 1.706 + // so we have to check the CF_HTML header for the correct length. 1.707 + // The length we return is the bytecount from the beginning of the selected data to the end 1.708 + // of the selected data, without the null termination. Because it's UTF8, we're guaranteed 1.709 + // the header is ASCII. 1.710 + 1.711 + if (!outData || !*outData) { 1.712 + return false; 1.713 + } 1.714 + 1.715 + char version[8] = { 0 }; 1.716 + int32_t startOfData = 0; 1.717 + int32_t endOfData = 0; 1.718 + int numFound = sscanf((char*)*outData, "Version:%7s\nStartHTML:%d\nEndHTML:%d", 1.719 + version, &startOfData, &endOfData); 1.720 + 1.721 + if (numFound != 3 || startOfData < -1 || endOfData < -1) { 1.722 + return false; 1.723 + } 1.724 + 1.725 + // Fixup the start and end markers if they have no context (set to -1) 1.726 + if (startOfData == -1) { 1.727 + startOfData = 0; 1.728 + } 1.729 + if (endOfData == -1) { 1.730 + endOfData = *outDataLen; 1.731 + } 1.732 + 1.733 + // Make sure we were passed sane values within our buffer size. 1.734 + // (Note that we've handled all cases of negative endOfData above, so we can 1.735 + // safely cast it to be unsigned here.) 1.736 + if (!endOfData || startOfData >= endOfData || 1.737 + static_cast<uint32_t>(endOfData) > *outDataLen) { 1.738 + return false; 1.739 + } 1.740 + 1.741 + // We want to return the buffer not offset by startOfData because it will be 1.742 + // parsed out later (probably by nsHTMLEditor::ParseCFHTML) when it is still 1.743 + // in CF_HTML format. 1.744 + *outDataLen = endOfData; 1.745 + return true; 1.746 +} 1.747 + 1.748 + 1.749 +// 1.750 +// FindUnicodeFromPlainText 1.751 +// 1.752 +// we are looking for text/unicode and we failed to find it on the clipboard first, 1.753 +// try again with text/plain. If that is present, convert it to unicode. 1.754 +// 1.755 +bool 1.756 +nsClipboard :: FindUnicodeFromPlainText ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) 1.757 +{ 1.758 + bool dataFound = false; 1.759 + 1.760 + // we are looking for text/unicode and we failed to find it on the clipboard first, 1.761 + // try again with text/plain. If that is present, convert it to unicode. 1.762 + nsresult loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, GetFormat(kTextMime), nullptr, outData, outDataLen); 1.763 + if ( NS_SUCCEEDED(loadResult) && *outData ) { 1.764 + const char* castedText = reinterpret_cast<char*>(*outData); 1.765 + char16_t* convertedText = nullptr; 1.766 + int32_t convertedTextLen = 0; 1.767 + nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode ( castedText, *outDataLen, 1.768 + &convertedText, &convertedTextLen ); 1.769 + if ( convertedText ) { 1.770 + // out with the old, in with the new 1.771 + nsMemory::Free(*outData); 1.772 + *outData = convertedText; 1.773 + *outDataLen = convertedTextLen * sizeof(char16_t); 1.774 + dataFound = true; 1.775 + } 1.776 + } // if plain text data on clipboard 1.777 + 1.778 + return dataFound; 1.779 + 1.780 +} // FindUnicodeFromPlainText 1.781 + 1.782 + 1.783 +// 1.784 +// FindURLFromLocalFile 1.785 +// 1.786 +// we are looking for a URL and couldn't find it, try again with looking for 1.787 +// a local file. If we have one, it may either be a normal file or an internet shortcut. 1.788 +// In both cases, however, we can get a URL (it will be a file:// url in the 1.789 +// local file case). 1.790 +// 1.791 +bool 1.792 +nsClipboard :: FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) 1.793 +{ 1.794 + bool dataFound = false; 1.795 + 1.796 + nsresult loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, GetFormat(kFileMime), nullptr, outData, outDataLen); 1.797 + if ( NS_SUCCEEDED(loadResult) && *outData ) { 1.798 + // we have a file path in |data|. Is it an internet shortcut or a normal file? 1.799 + const nsDependentString filepath(static_cast<char16_t*>(*outData)); 1.800 + nsCOMPtr<nsIFile> file; 1.801 + nsresult rv = NS_NewLocalFile(filepath, true, getter_AddRefs(file)); 1.802 + if (NS_FAILED(rv)) { 1.803 + nsMemory::Free(*outData); 1.804 + return dataFound; 1.805 + } 1.806 + 1.807 + if ( IsInternetShortcut(filepath) ) { 1.808 + nsMemory::Free(*outData); 1.809 + nsAutoCString url; 1.810 + ResolveShortcut( file, url ); 1.811 + if ( !url.IsEmpty() ) { 1.812 + // convert it to unicode and pass it out 1.813 + nsDependentString urlString(UTF8ToNewUnicode(url)); 1.814 + // the internal mozilla URL format, text/x-moz-url, contains 1.815 + // URL\ntitle. We can guess the title from the file's name. 1.816 + nsAutoString title; 1.817 + file->GetLeafName(title); 1.818 + // We rely on IsInternetShortcut check that file has a .url extension. 1.819 + title.SetLength(title.Length() - 4); 1.820 + if (title.IsEmpty()) 1.821 + title = urlString; 1.822 + *outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + title); 1.823 + *outDataLen = NS_strlen(static_cast<char16_t*>(*outData)) * sizeof(char16_t); 1.824 + 1.825 + dataFound = true; 1.826 + } 1.827 + } 1.828 + else { 1.829 + // we have a normal file, use some Necko objects to get our file path 1.830 + nsAutoCString urlSpec; 1.831 + NS_GetURLSpecFromFile(file, urlSpec); 1.832 + 1.833 + // convert it to unicode and pass it out 1.834 + nsMemory::Free(*outData); 1.835 + *outData = UTF8ToNewUnicode(urlSpec); 1.836 + *outDataLen = NS_strlen(static_cast<char16_t*>(*outData)) * sizeof(char16_t); 1.837 + dataFound = true; 1.838 + } // else regular file 1.839 + } 1.840 + 1.841 + return dataFound; 1.842 +} // FindURLFromLocalFile 1.843 + 1.844 +// 1.845 +// FindURLFromNativeURL 1.846 +// 1.847 +// we are looking for a URL and couldn't find it using our internal 1.848 +// URL flavor, so look for it using the native URL flavor, 1.849 +// CF_INETURLSTRW (We don't handle CF_INETURLSTRA currently) 1.850 +// 1.851 +bool 1.852 +nsClipboard :: FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) 1.853 +{ 1.854 + bool dataFound = false; 1.855 + 1.856 + void* tempOutData = nullptr; 1.857 + uint32_t tempDataLen = 0; 1.858 + 1.859 + nsresult loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, ::RegisterClipboardFormat(CFSTR_INETURLW), nullptr, &tempOutData, &tempDataLen); 1.860 + if ( NS_SUCCEEDED(loadResult) && tempOutData ) { 1.861 + nsDependentString urlString(static_cast<char16_t*>(tempOutData)); 1.862 + // the internal mozilla URL format, text/x-moz-url, contains 1.863 + // URL\ntitle. Since we don't actually have a title here, 1.864 + // just repeat the URL to fake it. 1.865 + *outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + urlString); 1.866 + *outDataLen = NS_strlen(static_cast<char16_t*>(*outData)) * sizeof(char16_t); 1.867 + nsMemory::Free(tempOutData); 1.868 + dataFound = true; 1.869 + } 1.870 + else { 1.871 + loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, ::RegisterClipboardFormat(CFSTR_INETURLA), nullptr, &tempOutData, &tempDataLen); 1.872 + if ( NS_SUCCEEDED(loadResult) && tempOutData ) { 1.873 + // CFSTR_INETURLA is (currently) equal to CFSTR_SHELLURL which is equal to CF_TEXT 1.874 + // which is by definition ANSI encoded. 1.875 + nsCString urlUnescapedA; 1.876 + bool unescaped = NS_UnescapeURL(static_cast<char*>(tempOutData), tempDataLen, esc_OnlyNonASCII | esc_SkipControl, urlUnescapedA); 1.877 + 1.878 + nsString urlString; 1.879 + if (unescaped) 1.880 + NS_CopyNativeToUnicode(urlUnescapedA, urlString); 1.881 + else 1.882 + NS_CopyNativeToUnicode(nsDependentCString(static_cast<char*>(tempOutData), tempDataLen), urlString); 1.883 + 1.884 + // the internal mozilla URL format, text/x-moz-url, contains 1.885 + // URL\ntitle. Since we don't actually have a title here, 1.886 + // just repeat the URL to fake it. 1.887 + *outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + urlString); 1.888 + *outDataLen = NS_strlen(static_cast<char16_t*>(*outData)) * sizeof(char16_t); 1.889 + nsMemory::Free(tempOutData); 1.890 + dataFound = true; 1.891 + } 1.892 + } 1.893 + 1.894 + return dataFound; 1.895 +} // FindURLFromNativeURL 1.896 + 1.897 +// 1.898 +// ResolveShortcut 1.899 +// 1.900 +void 1.901 +nsClipboard :: ResolveShortcut ( nsIFile* aFile, nsACString& outURL ) 1.902 +{ 1.903 + nsCOMPtr<nsIFileProtocolHandler> fph; 1.904 + nsresult rv = NS_GetFileProtocolHandler(getter_AddRefs(fph)); 1.905 + if (NS_FAILED(rv)) 1.906 + return; 1.907 + 1.908 + nsCOMPtr<nsIURI> uri; 1.909 + rv = fph->ReadURLFile(aFile, getter_AddRefs(uri)); 1.910 + if (NS_FAILED(rv)) 1.911 + return; 1.912 + 1.913 + uri->GetSpec(outURL); 1.914 +} // ResolveShortcut 1.915 + 1.916 + 1.917 +// 1.918 +// IsInternetShortcut 1.919 +// 1.920 +// A file is an Internet Shortcut if it ends with .URL 1.921 +// 1.922 +bool 1.923 +nsClipboard :: IsInternetShortcut ( const nsAString& inFileName ) 1.924 +{ 1.925 + return StringEndsWith(inFileName, NS_LITERAL_STRING(".url"), nsCaseInsensitiveStringComparator()); 1.926 +} // IsInternetShortcut 1.927 + 1.928 + 1.929 +//------------------------------------------------------------------------- 1.930 +NS_IMETHODIMP 1.931 +nsClipboard::GetNativeClipboardData ( nsITransferable * aTransferable, int32_t aWhichClipboard ) 1.932 +{ 1.933 + // make sure we have a good transferable 1.934 + if ( !aTransferable || aWhichClipboard != kGlobalClipboard ) 1.935 + return NS_ERROR_FAILURE; 1.936 + 1.937 + nsresult res; 1.938 + 1.939 + // This makes sure we can use the OLE functionality for the clipboard 1.940 + IDataObject * dataObj; 1.941 + if (S_OK == ::OleGetClipboard(&dataObj)) { 1.942 + // Use OLE IDataObject for clipboard operations 1.943 + res = GetDataFromDataObject(dataObj, 0, nullptr, aTransferable); 1.944 + dataObj->Release(); 1.945 + } 1.946 + else { 1.947 + // do it the old manual way 1.948 + res = GetDataFromDataObject(nullptr, 0, mWindow, aTransferable); 1.949 + } 1.950 + return res; 1.951 + 1.952 +} 1.953 + 1.954 +NS_IMETHODIMP 1.955 +nsClipboard::EmptyClipboard(int32_t aWhichClipboard) 1.956 +{ 1.957 + // Some programs such as ZoneAlarm monitor clipboard usage and then open the 1.958 + // clipboard to scan it. If we i) empty and then ii) set data, then the 1.959 + // 'set data' can sometimes fail with access denied becacuse another program 1.960 + // has the clipboard open. So to avoid this race condition for OpenClipboard 1.961 + // we do not empty the clipboard when we're setting it. 1.962 + if (aWhichClipboard == kGlobalClipboard && !mEmptyingForSetData) { 1.963 + OleSetClipboard(nullptr); 1.964 + } 1.965 + return nsBaseClipboard::EmptyClipboard(aWhichClipboard); 1.966 +} 1.967 + 1.968 +//------------------------------------------------------------------------- 1.969 +NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, 1.970 + uint32_t aLength, 1.971 + int32_t aWhichClipboard, 1.972 + bool *_retval) 1.973 +{ 1.974 + *_retval = false; 1.975 + if (aWhichClipboard != kGlobalClipboard || !aFlavorList) 1.976 + return NS_OK; 1.977 + 1.978 + for (uint32_t i = 0;i < aLength; ++i) { 1.979 +#ifdef DEBUG 1.980 + if (strcmp(aFlavorList[i], kTextMime) == 0) 1.981 + NS_WARNING ( "DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD" ); 1.982 +#endif 1.983 + 1.984 + UINT format = GetFormat(aFlavorList[i]); 1.985 + if (IsClipboardFormatAvailable(format)) { 1.986 + *_retval = true; 1.987 + break; 1.988 + } 1.989 + else { 1.990 + // We haven't found the exact flavor the client asked for, but maybe we can 1.991 + // still find it from something else that's on the clipboard... 1.992 + if (strcmp(aFlavorList[i], kUnicodeMime) == 0) { 1.993 + // client asked for unicode and it wasn't present, check if we have CF_TEXT. 1.994 + // We'll handle the actual data substitution in the data object. 1.995 + if (IsClipboardFormatAvailable(GetFormat(kTextMime))) 1.996 + *_retval = true; 1.997 + } 1.998 + } 1.999 + } 1.1000 + 1.1001 + return NS_OK; 1.1002 +}