widget/windows/nsClipboard.cpp

changeset 0
6474c204b198
     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 +}

mercurial