зеркало из https://github.com/mozilla/pjs.git
bug 440911: Add CF_HDROP support back into Windows drag and drop data object (dragging images to some applications, e.g. PhotoShop, fails); r=emaijala, approval1.9.1b2=beltzner
This commit is contained in:
Родитель
7494f0d268
Коммит
892d6df1f2
|
@ -62,6 +62,32 @@
|
|||
#include "nsXPCOMStrings.h"
|
||||
#include "nscore.h"
|
||||
#include "prtypes.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
|
||||
// XXX Duped from profile/src/nsProfile.cpp.
|
||||
#include <stdlib.h>
|
||||
#define TABLE_SIZE 36
|
||||
static const char table[] =
|
||||
{ 'a','b','c','d','e','f','g','h','i','j',
|
||||
'k','l','m','n','o','p','q','r','s','t',
|
||||
'u','v','w','x','y','z','0','1','2','3',
|
||||
'4','5','6','7','8','9' };
|
||||
static void
|
||||
MakeRandomString(char *buf, PRInt32 bufLen)
|
||||
{
|
||||
// turn PR_Now() into milliseconds since epoch
|
||||
// and salt rand with that.
|
||||
double fpTime;
|
||||
LL_L2D(fpTime, PR_Now());
|
||||
srand((uint)(fpTime * 1e-6 + 0.5)); // use 1e-6, granularity of PR_Now() on the mac is seconds
|
||||
|
||||
PRInt32 i;
|
||||
for (i=0;i<bufLen;i++) {
|
||||
*buf++ = table[rand()%TABLE_SIZE];
|
||||
}
|
||||
*buf = 0;
|
||||
}
|
||||
// XXX
|
||||
|
||||
// XXX for older version of PSDK where IAsyncOperation and related stuff is not available
|
||||
// but this should be removed when parocles config is updated
|
||||
|
@ -447,7 +473,7 @@ BOOL nsDataObj::FormatsMatch(const FORMATETC& source, const FORMATETC& target) c
|
|||
STDMETHODIMP nsDataObj::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||||
{
|
||||
PRNTDEBUG("nsDataObj::GetData\n");
|
||||
PRNTDEBUG3(" format: %d Text: %d\n", pFE->cfFormat, CF_TEXT);
|
||||
PRNTDEBUG3(" format: %d Text: %d\n", pFE->cfFormat, CF_HDROP);
|
||||
if ( !mTransferable )
|
||||
return ResultFromScode(DATA_E_FORMATETC);
|
||||
|
||||
|
@ -486,6 +512,11 @@ STDMETHODIMP nsDataObj::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
|||
case CF_UNICODETEXT:
|
||||
return GetText(*df, *pFE, *pSTM);
|
||||
|
||||
// Some 3rd party apps that receive drag and drop files from the browser
|
||||
// window require support for this.
|
||||
case CF_HDROP:
|
||||
return GetFile(*pFE, *pSTM);
|
||||
|
||||
// Someone is asking for an image
|
||||
case CF_DIB:
|
||||
return GetDib(*df, *pFE, *pSTM);
|
||||
|
@ -537,7 +568,7 @@ STDMETHODIMP nsDataObj::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
|||
STDMETHODIMP nsDataObj::QueryGetData(LPFORMATETC pFE)
|
||||
{
|
||||
PRNTDEBUG("nsDataObj::QueryGetData ");
|
||||
PRNTDEBUG3("format: %d Text: %d\n", pFE->cfFormat, CF_TEXT);
|
||||
PRNTDEBUG2("format: %d\n", pFE->cfFormat);
|
||||
|
||||
// Arbitrary system formats
|
||||
LPDATAENTRY pde;
|
||||
|
@ -553,7 +584,7 @@ STDMETHODIMP nsDataObj::QueryGetData(LPFORMATETC pFE)
|
|||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PRNTDEBUG2("***** nsDataObj::QueryGetData - Unknown format %d\n", pFE->cfFormat);
|
||||
return ResultFromScode(E_FAIL);
|
||||
}
|
||||
|
@ -1349,6 +1380,173 @@ HRESULT nsDataObj::GetText(const nsACString & aDataFlavor, FORMATETC& aFE, STGME
|
|||
return ResultFromScode(S_OK);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
HRESULT nsDataObj::GetFile(FORMATETC& aFE, STGMEDIUM& aSTG)
|
||||
{
|
||||
HRESULT res = S_OK;
|
||||
|
||||
// We do not support 'application/x-moz-file-promise' since CF_HDROP does not
|
||||
// allow for delayed rendering of content. We'll need to write the content out emmediately
|
||||
// and return the path to it. Confirm we have support for 'application/x-moz-nativeimage',
|
||||
// if not fail.
|
||||
PRUint32 dfInx = 0;
|
||||
ULONG count;
|
||||
FORMATETC fe;
|
||||
m_enumFE->Reset();
|
||||
PRBool found = PR_FALSE;
|
||||
while (NOERROR == m_enumFE->Next(1, &fe, &count)) {
|
||||
nsCString * df = reinterpret_cast<nsCString*>(mDataFlavors.SafeElementAt(dfInx));
|
||||
dfInx++;
|
||||
if (df && df->EqualsLiteral(kNativeImageMime)) {
|
||||
found = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return E_FAIL;
|
||||
|
||||
nsresult rv;
|
||||
PRUint32 len = 0;
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
|
||||
mTransferable->GetTransferData(kNativeImageMime, getter_AddRefs(genericDataWrapper), &len);
|
||||
nsCOMPtr<nsIImage> image ( do_QueryInterface(genericDataWrapper) );
|
||||
|
||||
if (!image) {
|
||||
// In the 0.9.4 timeframe, I had some embedding clients put the nsIImage directly into the
|
||||
// transferable. Newer code, however, wraps the nsIImage in a nsISupportsInterfacePointer.
|
||||
// We should be backwards compatibile with code already out in the field. If we can't find
|
||||
// the image directly out of the transferable, unwrap the image from its wrapper.
|
||||
nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(genericDataWrapper));
|
||||
if (ptr)
|
||||
ptr->GetData(getter_AddRefs(image));
|
||||
}
|
||||
|
||||
if (!image)
|
||||
return E_FAIL;
|
||||
|
||||
// Use the clipboard helper class to build up a memory bitmap.
|
||||
nsImageToClipboard converter(image);
|
||||
HANDLE bits = nsnull;
|
||||
rv = converter.GetPicture(&bits); // Clipboard routines return a global handle we own.
|
||||
|
||||
if (NS_FAILED(rv) || !bits)
|
||||
return E_FAIL;
|
||||
|
||||
// We now own these bits!
|
||||
PRUint32 bitmapSize = GlobalSize(bits);
|
||||
if (!bitmapSize) {
|
||||
GlobalFree(bits);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (mCachedTempFile) {
|
||||
mCachedTempFile->Remove(PR_FALSE);
|
||||
mCachedTempFile = NULL;
|
||||
}
|
||||
|
||||
// Save the bitmap to a temporary location.
|
||||
nsCOMPtr<nsIFile> dropFile;
|
||||
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dropFile));
|
||||
if (!dropFile)
|
||||
return E_FAIL;
|
||||
|
||||
// Filename must be random so as not to confuse apps like Photshop which handle
|
||||
// multiple drags into a single window.
|
||||
char buf[13];
|
||||
nsCString filename;
|
||||
MakeRandomString(buf, 8);
|
||||
memcpy(buf+8, ".bmp", 5);
|
||||
filename.Append(nsDependentCString(buf, 12));
|
||||
dropFile->AppendNative(filename);
|
||||
rv = dropFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0660);
|
||||
if (NS_FAILED(rv)) {
|
||||
GlobalFree(bits);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Cache the temp file so we can delete it later.
|
||||
dropFile->Clone(getter_AddRefs(mCachedTempFile));
|
||||
|
||||
// Write the data to disk.
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), dropFile);
|
||||
if (NS_FAILED(rv)) {
|
||||
GlobalFree(bits);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
char * bm = (char *)GlobalLock(bits);
|
||||
|
||||
BITMAPFILEHEADER fileHdr;
|
||||
BITMAPINFOHEADER *bmpHdr = (BITMAPINFOHEADER*)bm;
|
||||
|
||||
fileHdr.bfType = ((WORD) ('M' << 8) | 'B');
|
||||
fileHdr.bfSize = GlobalSize (bits) + sizeof(fileHdr);
|
||||
fileHdr.bfReserved1 = 0;
|
||||
fileHdr.bfReserved2 = 0;
|
||||
fileHdr.bfOffBits = (DWORD) (sizeof(fileHdr) + bmpHdr->biSize);
|
||||
|
||||
PRUint32 writeCount = 0;
|
||||
if (NS_FAILED(outStream->Write((const char *)&fileHdr, sizeof(fileHdr), &writeCount)) ||
|
||||
NS_FAILED(outStream->Write((const char *)bm, bitmapSize, &writeCount)))
|
||||
rv = NS_ERROR_FAILURE;
|
||||
|
||||
outStream->Close();
|
||||
|
||||
GlobalUnlock(bits);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
GlobalFree(bits);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
GlobalFree(bits);
|
||||
|
||||
// Pass the file name back to the drop target so that it can access the file.
|
||||
nsAutoString path;
|
||||
rv = mCachedTempFile->GetPath(path);
|
||||
if (NS_FAILED(rv))
|
||||
return E_FAIL;
|
||||
|
||||
// Two null characters are needed to terminate the file name list.
|
||||
HGLOBAL hGlobalMemory = NULL;
|
||||
|
||||
PRUint32 allocLen = path.Length() + 2;
|
||||
|
||||
aSTG.tymed = TYMED_HGLOBAL;
|
||||
aSTG.pUnkForRelease = NULL;
|
||||
|
||||
hGlobalMemory = GlobalAlloc(GMEM_MOVEABLE, sizeof(DROPFILES) + allocLen * sizeof(PRUnichar));
|
||||
if (!hGlobalMemory)
|
||||
return E_FAIL;
|
||||
|
||||
DROPFILES* pDropFile = (DROPFILES*)GlobalLock(hGlobalMemory);
|
||||
|
||||
// First, populate the drop file structure.
|
||||
pDropFile->pFiles = sizeof(DROPFILES); // Offset to start of file name char array.
|
||||
pDropFile->fNC = 0;
|
||||
pDropFile->pt.x = 0;
|
||||
pDropFile->pt.y = 0;
|
||||
pDropFile->fWide = TRUE;
|
||||
|
||||
// Copy the filename right after the DROPFILES structure.
|
||||
PRUnichar* dest = (PRUnichar*)(((char*)pDropFile) + pDropFile->pFiles);
|
||||
memcpy(dest, path.get(), (allocLen - 1) * sizeof(PRUnichar)); // Copies the null character in path as well.
|
||||
|
||||
// Two null characters are needed at the end of the file name.
|
||||
// Lookup the CF_HDROP shell clipboard format for more info.
|
||||
// Add the second null character right after the first one.
|
||||
dest[allocLen - 1] = L'\0';
|
||||
|
||||
GlobalUnlock(hGlobalMemory);
|
||||
|
||||
aSTG.hGlobal = hGlobalMemory;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
HRESULT nsDataObj::GetMetafilePict(FORMATETC&, STGMEDIUM&)
|
||||
{
|
||||
|
@ -1408,22 +1606,11 @@ CLSID nsDataObj::GetClassID() const
|
|||
void nsDataObj::AddDataFlavor(const char* aDataFlavor, LPFORMATETC aFE)
|
||||
{
|
||||
// These two lists are the mapping to and from data flavors and FEs.
|
||||
// Later, OLE will tell us it needs a certain type of FORMATETC (text,
|
||||
// Later, OLE will tell us it needs a certain type of FORMATETC (text, unicode, etc)
|
||||
// unicode, etc), so we will look up the data flavor that corresponds to
|
||||
// the FE and then ask the transferable for that type of data.
|
||||
|
||||
#ifndef WINCE
|
||||
// Just ignore the CF_HDROP here
|
||||
// all file drags are now handled by CFSTR_FileContents format
|
||||
if (aFE->cfFormat == CF_HDROP) {
|
||||
return;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
mDataFlavors.AppendElement(new nsCString(aDataFlavor));
|
||||
m_enumFE->AddFE(aFE);
|
||||
}
|
||||
mDataFlavors.AppendElement(new nsCString(aDataFlavor));
|
||||
m_enumFE->AddFE(aFE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
|
|
|
@ -224,6 +224,7 @@ class nsDataObj : public IDataObject,
|
|||
virtual HRESULT AddSetFormat(FORMATETC& FE);
|
||||
virtual HRESULT AddGetFormat(FORMATETC& FE);
|
||||
|
||||
virtual HRESULT GetFile ( FORMATETC& aFE, STGMEDIUM& aSTG );
|
||||
virtual HRESULT GetText ( const nsACString& aDF, FORMATETC& aFE, STGMEDIUM & aSTG );
|
||||
virtual HRESULT GetBitmap ( const nsACString& inFlavor, FORMATETC& FE, STGMEDIUM& STM);
|
||||
virtual HRESULT GetDib ( const nsACString& inFlavor, FORMATETC &, STGMEDIUM & aSTG );
|
||||
|
@ -272,7 +273,7 @@ class nsDataObj : public IDataObject,
|
|||
CEnumFormatEtc * m_enumFE; // Ownership Rules:
|
||||
// nsDataObj owns and ref counts CEnumFormatEtc,
|
||||
|
||||
nsCOMPtr<nsILocalFile> mCachedTempFile;
|
||||
nsCOMPtr<nsIFile> mCachedTempFile;
|
||||
|
||||
BOOL mIsAsyncMode;
|
||||
BOOL mIsInOperation;
|
||||
|
|
|
@ -308,7 +308,7 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
|
|||
// do async drag
|
||||
if (SUCCEEDED(aDataObj->QueryInterface(IID_IAsyncOperation,
|
||||
(void**)&pAsyncOp)))
|
||||
pAsyncOp->SetAsyncMode(TRUE);
|
||||
pAsyncOp->SetAsyncMode(VARIANT_TRUE);
|
||||
}
|
||||
|
||||
// Call the native D&D method
|
||||
|
|
Загрузка…
Ссылка в новой задаче