From ba0fb4a0dc6250d6531cef5eee0b93cc8022bce4 Mon Sep 17 00:00:00 2001 From: "sfraser%netscape.com" Date: Fri, 18 Apr 2003 20:20:04 +0000 Subject: [PATCH] Bug 193053: drag and drop-related changes to allow for the dragging and copying of image bits, and to allow dragging into the file system. r=pinkerton/brade, sr=bryner/bz. git-svn-id: svn://10.0.0.236/trunk@141409 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/base/public/nsCopySupport.h | 20 + mozilla/content/base/src/Makefile.in | 1 + .../base/src/nsContentAreaDragDrop.cpp | 173 +++++- .../content/base/src/nsContentAreaDragDrop.h | 15 +- mozilla/content/base/src/nsCopySupport.cpp | 130 +++++ mozilla/layout/base/src/nsCopySupport.cpp | 130 +++++ mozilla/layout/base/src/nsCopySupport.h | 20 + mozilla/widget/public/nsITransferable.idl | 69 ++- mozilla/widget/src/mac/nsClipboard.cpp | 14 +- mozilla/widget/src/mac/nsDragService.cpp | 538 ++++++++++++------ mozilla/widget/src/mac/nsDragService.h | 13 +- mozilla/widget/src/mac/nsMimeMapper.cpp | 36 +- .../src/xpwidgets/nsHTMLFormatConverter.h | 8 +- .../widget/src/xpwidgets/nsTransferable.cpp | 110 ++-- mozilla/widget/src/xpwidgets/nsTransferable.h | 15 +- 15 files changed, 993 insertions(+), 299 deletions(-) diff --git a/mozilla/content/base/public/nsCopySupport.h b/mozilla/content/base/public/nsCopySupport.h index 72d213413f6..1945df880a8 100644 --- a/mozilla/content/base/public/nsCopySupport.h +++ b/mozilla/content/base/public/nsCopySupport.h @@ -40,6 +40,13 @@ class nsISelection; class nsIDocument; +class nsIDOMNode; +class nsIDOMHTMLImageElement; +class nsIContent; +class nsIPresContext; +class nsIPresShell; +class nsIImageFrame; +class nsIImage; class nsITransferable; class nsCopySupport @@ -50,4 +57,17 @@ class nsCopySupport static nsresult DoHooks(nsIDocument *aDoc, nsITransferable *aTrans, PRBool *aDoPutOnClipboard); static nsresult IsPlainTextContext(nsISelection *aSel, nsIDocument *aDoc, PRBool *aIsPlainTextContext); + + // Get the selection, or entire document, in the format specified by the mime type + // (text/html or text/plain). If aSel is non-null, use it, otherwise get the entire + // doc. + static nsresult GetContents(const nsACString& aMimeType, PRUint32 aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata); + + static nsresult ImageCopy(nsIDOMHTMLImageElement* imageElement, PRInt16 aClipboardID); + + protected: + + // these are ripped from nsContentAreaDragDrop. This so needs factoring. + static nsresult GetImageFromDOMNode(nsIDOMNode* inNode, nsIImage**outImage); + }; diff --git a/mozilla/content/base/src/Makefile.in b/mozilla/content/base/src/Makefile.in index dce59313641..3e9c698215b 100644 --- a/mozilla/content/base/src/Makefile.in +++ b/mozilla/content/base/src/Makefile.in @@ -52,6 +52,7 @@ REQUIRES = xpcom \ xuldoc \ intl \ windowwatcher \ + webbrowserpersist \ imglib2 \ uriloader \ webbrwsr \ diff --git a/mozilla/content/base/src/nsContentAreaDragDrop.cpp b/mozilla/content/base/src/nsContentAreaDragDrop.cpp index d3be82e3d25..bef761132fa 100644 --- a/mozilla/content/base/src/nsContentAreaDragDrop.cpp +++ b/mozilla/content/base/src/nsContentAreaDragDrop.cpp @@ -42,7 +42,6 @@ // Helper Classes #include "nsString.h" -#include "nsXPIDLString.h" // Interfaces needed to be included #include "nsIDOMNSUIEvent.h" @@ -86,7 +85,7 @@ #include "nsINameSpaceManager.h" #include "nsUnicharUtils.h" #include "nsHTMLAtoms.h" -#include "nsIURI.h" +#include "nsIURL.h" #include "nsIImage.h" #include "nsIDocument.h" #include "nsIPresShell.h" @@ -99,6 +98,8 @@ #include "nsIInterfaceRequestor.h" #include "nsIDocumentEncoder.h" #include "nsRange.h" +#include "nsIWebBrowserPersist.h" +#include "nsEscape.h" NS_IMPL_ADDREF(nsContentAreaDragDrop) @@ -108,6 +109,7 @@ NS_INTERFACE_MAP_BEGIN(nsContentAreaDragDrop) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDragListener) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMDragListener) NS_INTERFACE_MAP_ENTRY(nsIDOMDragListener) + NS_INTERFACE_MAP_ENTRY(nsIFlavorDataProvider) NS_INTERFACE_MAP_ENTRY(nsIDragDropHandler) NS_INTERFACE_MAP_END @@ -155,7 +157,7 @@ nsContentAreaDragDrop::Detach() // // Subscribe to the events that will allow us to track drags. // -NS_IMETHODIMP +nsresult nsContentAreaDragDrop::AddDragListener() { nsresult rv = NS_ERROR_FAILURE; @@ -176,7 +178,7 @@ nsContentAreaDragDrop::AddDragListener() // // Unsubscribe from all the various drag events that we were listening to. // -NS_IMETHODIMP +nsresult nsContentAreaDragDrop::RemoveDragListener() { nsresult rv = NS_ERROR_FAILURE; @@ -304,7 +306,7 @@ nsContentAreaDragDrop::ExtractURLFromData(const nsACString & inFlavor, nsISuppor return; outURL.Truncate(); - if ( inFlavor.Equals(kUnicodeMime) ) { + if ( inFlavor.Equals(kUnicodeMime) || inFlavor.Equals(kURLDataMime) ) { // the data is regular unicode, just go with what we get. It may be a url, it // may not be. *shrug* nsCOMPtr stringData(do_QueryInterface(inDataWrapper)); @@ -374,12 +376,13 @@ nsContentAreaDragDrop::DragDrop(nsIDOMEvent* inMouseEvent) nsCOMPtr trans(do_CreateInstance("@mozilla.org/widget/transferable;1")); if ( !trans ) return NS_ERROR_FAILURE; - + // add the relevant flavors. order is important (highest fidelity to lowest) + trans->AddDataFlavor(kURLDataMime); trans->AddDataFlavor(kURLMime); trans->AddDataFlavor(kFileMime); trans->AddDataFlavor(kUnicodeMime); - + nsresult rv = session->GetData(trans, 0); // again, we only care about the first object if ( NS_SUCCEEDED(rv) ) { // if the client has provided an override callback, call it. It may @@ -980,6 +983,18 @@ nsContentAreaDragDrop::CreateTransferable(const nsAString & inURLString, const n return NS_ERROR_FAILURE; urlPrimitive->SetData(dragData); trans->SetTransferData(kURLMime, urlPrimitive, dragData.Length() * sizeof(PRUnichar)); + + nsCOMPtr urlDataPrimitive(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + if (!urlDataPrimitive) + return NS_ERROR_FAILURE; + urlDataPrimitive->SetData(inURLString); + trans->SetTransferData(kURLDataMime, urlDataPrimitive, inURLString.Length() * sizeof(PRUnichar)); + + nsCOMPtr urlDescPrimitive(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + if (!urlDescPrimitive) + return NS_ERROR_FAILURE; + urlDescPrimitive->SetData(inTitleString); + trans->SetTransferData(kURLDescriptionMime, urlDescPrimitive, inTitleString.Length() * sizeof(PRUnichar)); } // add the full html @@ -1007,6 +1022,26 @@ nsContentAreaDragDrop::CreateTransferable(const nsAString & inURLString, const n return NS_ERROR_FAILURE; ptrPrimitive->SetData(inImage); trans->SetTransferData(kNativeImageMime, ptrPrimitive, sizeof(nsIImage*)); + // assume the image comes from a file, and add a file promise. We register ourselves + // as a nsIFlavorDataProvider, and will use the GetFlavorData callback to save the + // image to disk. + trans->SetTransferData(kFilePromiseMime, NS_STATIC_CAST(nsIFlavorDataProvider*, this), nsITransferable::kFlavorHasDataProvider); + + nsCOMPtr imageUrlPrimitive(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + if (!imageUrlPrimitive) + return NS_ERROR_FAILURE; + imageUrlPrimitive->SetData(inImageSourceString); + trans->SetTransferData(kFilePromiseURLMime, imageUrlPrimitive, inImageSourceString.Length() * sizeof(PRUnichar)); + + // if not an anchor, add the image url + if (!inIsAnchor) + { + nsCOMPtr urlDataPrimitive(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); + if (!urlDataPrimitive) + return NS_ERROR_FAILURE; + urlDataPrimitive->SetData(inURLString); + trans->SetTransferData(kURLDataMime, urlDataPrimitive, inURLString.Length() * sizeof(PRUnichar)); + } } *outTrans = trans; @@ -1318,3 +1353,127 @@ nsContentAreaDragDrop::GetImageFromDOMNode(nsIDOMNode* inNode, nsIImage**outImag return CallGetInterface(ir.get(), outImage); } + +#if 0 +#pragma mark - +#endif + +// SaveURIToFile +// used on platforms where it's possible to drag items (e.g. images) +// into the file system +nsresult +nsContentAreaDragDrop::SaveURIToFileInDirectory(nsAString& inSourceURIString, nsILocalFile* inDestDirectory, nsILocalFile** outFile) +{ + *outFile = nsnull; + + nsresult rv; + + // clone it because it belongs to the drag data, so we shouldn't mess with it + nsCOMPtr clonedFile; + rv = inDestDirectory->Clone(getter_AddRefs(clonedFile)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr destFile = do_QueryInterface(clonedFile); + if (!destFile) return NS_ERROR_NO_INTERFACE; + + nsCOMPtr sourceURI; + rv = NS_NewURI(getter_AddRefs(sourceURI), inSourceURIString); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + + nsCOMPtr sourceURL = do_QueryInterface(sourceURI); + if (!sourceURL) return NS_ERROR_NO_INTERFACE; + + nsCAutoString fileName; // escaped, UTF-8 + sourceURL->GetFileName(fileName); + + if (fileName.IsEmpty()) + return NS_ERROR_FAILURE; // this is an error; the URL must point to a file + + NS_UnescapeURL(fileName); + NS_ConvertUTF8toUCS2 wideFileName(fileName); + + // make the name safe for the filesystem + wideFileName.ReplaceChar(PRUnichar('/'), PRUnichar('_')); + wideFileName.ReplaceChar(PRUnichar('\\'), PRUnichar('_')); + wideFileName.ReplaceChar(PRUnichar(':'), PRUnichar('_')); + + rv = destFile->Append(wideFileName); + if (NS_FAILED(rv)) return rv; + + rv = destFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600); + if (NS_FAILED(rv)) return rv; + + // we rely on the fact that the WPB is refcounted by the channel etc, + // so we don't keep a ref to it. It will die when finished. + nsCOMPtr persist = do_CreateInstance("@mozilla.org/embedding/browser/nsWebBrowserPersist;1", &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr fileAsSupports = do_QueryInterface(destFile); + rv = persist->SaveURI(sourceURI, nsnull, nsnull, nsnull, nsnull, fileAsSupports); + if (NS_FAILED(rv)) return rv; + + *outFile = destFile; + NS_ADDREF(*outFile); + + return NS_OK; +} + +// This is our nsIFlavorDataProvider callback. There are several assumptions here that +// make this work: +// +// 1. Someone put a kFilePromiseURLMime flavor into the transferable with the source +// URI of the file to save (as a string). We did that above. +// +// 2. Someone put a kFilePromiseDirectoryMime flavor into the transferable with +// an nsILocalFile for the directory we are to save in. That has to be done +// by platform-specific code (in widget), which gets the destination directory +// from OS-specific drag information. +// +NS_IMETHODIMP +nsContentAreaDragDrop::GetFlavorData(nsITransferable *aTransferable, + const char *aFlavor, nsISupports **aData, PRUint32 *aDataLen) +{ + NS_ENSURE_ARG_POINTER(aData && aDataLen); + *aData = nsnull; + *aDataLen = 0; + + nsresult rv = NS_ERROR_NOT_IMPLEMENTED; + + if (strcmp(aFlavor, kFilePromiseMime) == 0) + { + // get the URI from the kFilePromiseURLMime flavor + NS_ENSURE_ARG(aTransferable); + nsCOMPtr urlPrimitive; + PRUint32 dataSize = 0; + aTransferable->GetTransferData(kFilePromiseURLMime, getter_AddRefs(urlPrimitive), &dataSize); + nsCOMPtr srcUrlPrimitive = do_QueryInterface(urlPrimitive); + if (!srcUrlPrimitive) return NS_ERROR_FAILURE; + + nsAutoString sourceURLString; + srcUrlPrimitive->GetData(sourceURLString); + if (sourceURLString.IsEmpty()) + return NS_ERROR_FAILURE; + + // get the target directory from the kFilePromiseDirectoryMime flavor + nsCOMPtr dirPrimitive; + dataSize = 0; + aTransferable->GetTransferData(kFilePromiseDirectoryMime, getter_AddRefs(dirPrimitive), &dataSize); + nsCOMPtr destDirectory = do_QueryInterface(dirPrimitive); + if (!destDirectory) return NS_ERROR_FAILURE; + + // now save the file + nsCOMPtr destFile; + rv = SaveURIToFileInDirectory(sourceURLString, destDirectory, getter_AddRefs(destFile)); + + // send back an nsILocalFile + if (NS_SUCCEEDED(rv)) + { + CallQueryInterface(destFile, aData); + *aDataLen = sizeof(nsILocalFile*); + } + } + + return rv; +} + + diff --git a/mozilla/content/base/src/nsContentAreaDragDrop.h b/mozilla/content/base/src/nsContentAreaDragDrop.h index 6b2afef1b67..f5c01ea046b 100644 --- a/mozilla/content/base/src/nsContentAreaDragDrop.h +++ b/mozilla/content/base/src/nsContentAreaDragDrop.h @@ -45,6 +45,7 @@ #include "nsIDragDropHandler.h" #include "nsIDOMDragListener.h" #include "nsIDOMEventReceiver.h" +#include "nsITransferable.h" class nsIDOMNode; class nsISelection; @@ -54,9 +55,10 @@ class nsIPresShell; class nsIPresContext; class nsIContent; class nsIDocument; +class nsIURI; +class nsILocalFile; class nsISimpleEnumerator; - // {1f34bc80-1bc7-11d6-a384-d705dd0746fc} #define NS_CONTENTAREADRAGDROP_CID \ { 0x1f34bc80, 0x1bc7, 0x11d6, { 0xa3, 0x84, 0xd7, 0x05, 0xdd, 0x07, 0x46, 0xfc } } @@ -71,11 +73,14 @@ class nsISimpleEnumerator; // to drag and drop. Registers itself with the DOM with AddChromeListeners() // and removes itself with RemoveChromeListeners(). // -class nsContentAreaDragDrop : public nsIDOMDragListener, public nsIDragDropHandler +class nsContentAreaDragDrop : public nsIDOMDragListener, + public nsIDragDropHandler, + public nsIFlavorDataProvider { public: NS_DECL_ISUPPORTS NS_DECL_NSIDRAGDROPHANDLER + NS_DECL_NSIFLAVORDATAPROVIDER nsContentAreaDragDrop ( ) ; virtual ~nsContentAreaDragDrop ( ) ; @@ -91,8 +96,8 @@ public: private: // Add/remove the relevant listeners - NS_IMETHOD AddDragListener(); - NS_IMETHOD RemoveDragListener(); + nsresult AddDragListener(); + nsresult RemoveDragListener(); // utility routines static void FindFirstAnchor(nsIDOMNode* inNode, nsIDOMNode** outAnchor); @@ -110,6 +115,8 @@ private: // if inNode is null, use the selection from the window static nsresult SerializeNodeOrSelection(const char* inMimeType, PRUint32 inFlags, nsIDOMWindow* inWindow, nsIDOMNode* inNode, nsAString& outResultString); + + static nsresult SaveURIToFileInDirectory(nsAString& inSourceURIString, nsILocalFile* inDestDirectory, nsILocalFile** outFile); PRBool BuildDragData(nsIDOMEvent* inMouseEvent, nsAString & outURLString, nsAString & outTitleString, nsAString & outHTMLString, nsAString & outImageSourceString, nsIImage** outImage, PRBool* outIsAnchor); diff --git a/mozilla/content/base/src/nsCopySupport.cpp b/mozilla/content/base/src/nsCopySupport.cpp index 5f238a3c0d7..b9a9022cc0c 100644 --- a/mozilla/content/base/src/nsCopySupport.cpp +++ b/mozilla/content/base/src/nsCopySupport.cpp @@ -52,6 +52,7 @@ #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsIDOMRange.h" +#include "nsIFrame.h" #include "nsIDocShell.h" #include "nsIClipboardDragDropHooks.h" @@ -70,6 +71,17 @@ //static NS_DEFINE_CID(kUBidiUtilCID, NS_UNICHARBIDIUTIL_CID); #endif +// image copy stuff +#include "nsIDOMHTMLImageElement.h" +#include "nsLayoutAtoms.h" +#include "nsIImageLoadingContent.h" +#include "imgIContainer.h" +#include "imgIRequest.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "gfxIImageFrame.h" +#include "nsIImage.h" + static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID); static NS_DEFINE_CID(kHTMLConverterCID, NS_HTMLFORMATCONVERTER_CID); @@ -379,3 +391,121 @@ nsresult nsCopySupport::IsPlainTextContext(nsISelection *aSel, nsIDocument *aDoc return NS_OK; } + +nsresult +nsCopySupport::GetContents(const nsACString& aMimeType, PRUint32 aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata) +{ + nsresult rv = NS_OK; + + nsCOMPtr docEncoder; + + nsCAutoString encoderContractID(NS_DOC_ENCODER_CONTRACTID_BASE); + encoderContractID.Append(aMimeType); + + docEncoder = do_CreateInstance(encoderContractID.get()); + NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE); + + PRUint32 flags = aFlags; + + if (aMimeType.Equals("text/plain")) + flags |= nsIDocumentEncoder::OutputPreformatted; + + NS_ConvertASCIItoUCS2 unicodeMimeType(aMimeType); + rv = docEncoder->Init(aDoc, unicodeMimeType, flags); + if (NS_FAILED(rv)) return rv; + + if (aSel) + { + rv = docEncoder->SetSelection(aSel); + if (NS_FAILED(rv)) return rv; + } + + // encode the selection + return docEncoder->EncodeToString(outdata); +} + + +nsresult +nsCopySupport::ImageCopy(nsIDOMHTMLImageElement* imageElement, PRInt16 aClipboardID) +{ + nsresult rv; + + nsCOMPtr imageNode = do_QueryInterface(imageElement, &rv); + if (NS_FAILED(rv)) return rv; + if (!imageNode) return NS_ERROR_FAILURE; + + nsCOMPtr image; + rv = GetImageFromDOMNode(imageNode, getter_AddRefs(image)); + if (NS_FAILED(rv)) return rv; + if (!image) return NS_ERROR_FAILURE; + + // Get the Clipboard + nsCOMPtr clipboard(do_GetService(kCClipboardCID, &rv)); + if (NS_FAILED(rv)) return rv; + if (!clipboard) return NS_ERROR_FAILURE; + + // Create a transferable for putting data on the Clipboard + nsCOMPtr trans = do_CreateInstance(kCTransferableCID, &rv); + if (NS_FAILED(rv)) return rv; + if (!trans) return NS_ERROR_FAILURE; + + nsCOMPtr ptrPrimitive(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv)); + if (NS_FAILED(rv)) return rv; + if (!ptrPrimitive) return NS_ERROR_FAILURE; + ptrPrimitive->SetData(image); + + trans->SetTransferData(kNativeImageMime, ptrPrimitive, sizeof(nsISupports*)); + + // put the transferable on the clipboard + return clipboard->SetData(trans, nsnull, aClipboardID); +} + +// +// GetImage +// +// Given a dom node that's an image, finds the nsIImage associated with it. +// +// XXX see also nsContentAreaDragDrop, and factor! +nsresult +nsCopySupport::GetImageFromDOMNode(nsIDOMNode* inNode, nsIImage**outImage) +{ + NS_ENSURE_ARG_POINTER(outImage); + *outImage = nsnull; + + nsCOMPtr content(do_QueryInterface(inNode)); + if (!content) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr imgRequest; + content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, + getter_AddRefs(imgRequest)); + if (!imgRequest) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr imgContainer; + imgRequest->GetImage(getter_AddRefs(imgContainer)); + + if (!imgContainer) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr imgFrame; + imgContainer->GetFrameAt(0, getter_AddRefs(imgFrame)); + + if (!imgFrame) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr ir = do_QueryInterface(imgFrame); + + if (!ir) { + return NS_ERROR_NOT_AVAILABLE; + } + + return CallGetInterface(ir.get(), outImage); +} + + + diff --git a/mozilla/layout/base/src/nsCopySupport.cpp b/mozilla/layout/base/src/nsCopySupport.cpp index 5f238a3c0d7..b9a9022cc0c 100644 --- a/mozilla/layout/base/src/nsCopySupport.cpp +++ b/mozilla/layout/base/src/nsCopySupport.cpp @@ -52,6 +52,7 @@ #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsIDOMRange.h" +#include "nsIFrame.h" #include "nsIDocShell.h" #include "nsIClipboardDragDropHooks.h" @@ -70,6 +71,17 @@ //static NS_DEFINE_CID(kUBidiUtilCID, NS_UNICHARBIDIUTIL_CID); #endif +// image copy stuff +#include "nsIDOMHTMLImageElement.h" +#include "nsLayoutAtoms.h" +#include "nsIImageLoadingContent.h" +#include "imgIContainer.h" +#include "imgIRequest.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "gfxIImageFrame.h" +#include "nsIImage.h" + static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID); static NS_DEFINE_CID(kHTMLConverterCID, NS_HTMLFORMATCONVERTER_CID); @@ -379,3 +391,121 @@ nsresult nsCopySupport::IsPlainTextContext(nsISelection *aSel, nsIDocument *aDoc return NS_OK; } + +nsresult +nsCopySupport::GetContents(const nsACString& aMimeType, PRUint32 aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata) +{ + nsresult rv = NS_OK; + + nsCOMPtr docEncoder; + + nsCAutoString encoderContractID(NS_DOC_ENCODER_CONTRACTID_BASE); + encoderContractID.Append(aMimeType); + + docEncoder = do_CreateInstance(encoderContractID.get()); + NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE); + + PRUint32 flags = aFlags; + + if (aMimeType.Equals("text/plain")) + flags |= nsIDocumentEncoder::OutputPreformatted; + + NS_ConvertASCIItoUCS2 unicodeMimeType(aMimeType); + rv = docEncoder->Init(aDoc, unicodeMimeType, flags); + if (NS_FAILED(rv)) return rv; + + if (aSel) + { + rv = docEncoder->SetSelection(aSel); + if (NS_FAILED(rv)) return rv; + } + + // encode the selection + return docEncoder->EncodeToString(outdata); +} + + +nsresult +nsCopySupport::ImageCopy(nsIDOMHTMLImageElement* imageElement, PRInt16 aClipboardID) +{ + nsresult rv; + + nsCOMPtr imageNode = do_QueryInterface(imageElement, &rv); + if (NS_FAILED(rv)) return rv; + if (!imageNode) return NS_ERROR_FAILURE; + + nsCOMPtr image; + rv = GetImageFromDOMNode(imageNode, getter_AddRefs(image)); + if (NS_FAILED(rv)) return rv; + if (!image) return NS_ERROR_FAILURE; + + // Get the Clipboard + nsCOMPtr clipboard(do_GetService(kCClipboardCID, &rv)); + if (NS_FAILED(rv)) return rv; + if (!clipboard) return NS_ERROR_FAILURE; + + // Create a transferable for putting data on the Clipboard + nsCOMPtr trans = do_CreateInstance(kCTransferableCID, &rv); + if (NS_FAILED(rv)) return rv; + if (!trans) return NS_ERROR_FAILURE; + + nsCOMPtr ptrPrimitive(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv)); + if (NS_FAILED(rv)) return rv; + if (!ptrPrimitive) return NS_ERROR_FAILURE; + ptrPrimitive->SetData(image); + + trans->SetTransferData(kNativeImageMime, ptrPrimitive, sizeof(nsISupports*)); + + // put the transferable on the clipboard + return clipboard->SetData(trans, nsnull, aClipboardID); +} + +// +// GetImage +// +// Given a dom node that's an image, finds the nsIImage associated with it. +// +// XXX see also nsContentAreaDragDrop, and factor! +nsresult +nsCopySupport::GetImageFromDOMNode(nsIDOMNode* inNode, nsIImage**outImage) +{ + NS_ENSURE_ARG_POINTER(outImage); + *outImage = nsnull; + + nsCOMPtr content(do_QueryInterface(inNode)); + if (!content) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr imgRequest; + content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, + getter_AddRefs(imgRequest)); + if (!imgRequest) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr imgContainer; + imgRequest->GetImage(getter_AddRefs(imgContainer)); + + if (!imgContainer) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr imgFrame; + imgContainer->GetFrameAt(0, getter_AddRefs(imgFrame)); + + if (!imgFrame) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr ir = do_QueryInterface(imgFrame); + + if (!ir) { + return NS_ERROR_NOT_AVAILABLE; + } + + return CallGetInterface(ir.get(), outImage); +} + + + diff --git a/mozilla/layout/base/src/nsCopySupport.h b/mozilla/layout/base/src/nsCopySupport.h index 72d213413f6..1945df880a8 100644 --- a/mozilla/layout/base/src/nsCopySupport.h +++ b/mozilla/layout/base/src/nsCopySupport.h @@ -40,6 +40,13 @@ class nsISelection; class nsIDocument; +class nsIDOMNode; +class nsIDOMHTMLImageElement; +class nsIContent; +class nsIPresContext; +class nsIPresShell; +class nsIImageFrame; +class nsIImage; class nsITransferable; class nsCopySupport @@ -50,4 +57,17 @@ class nsCopySupport static nsresult DoHooks(nsIDocument *aDoc, nsITransferable *aTrans, PRBool *aDoPutOnClipboard); static nsresult IsPlainTextContext(nsISelection *aSel, nsIDocument *aDoc, PRBool *aIsPlainTextContext); + + // Get the selection, or entire document, in the format specified by the mime type + // (text/html or text/plain). If aSel is non-null, use it, otherwise get the entire + // doc. + static nsresult GetContents(const nsACString& aMimeType, PRUint32 aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata); + + static nsresult ImageCopy(nsIDOMHTMLImageElement* imageElement, PRInt16 aClipboardID); + + protected: + + // these are ripped from nsContentAreaDragDrop. This so needs factoring. + static nsresult GetImageFromDOMNode(nsIDOMNode* inNode, nsIImage**outImage); + }; diff --git a/mozilla/widget/public/nsITransferable.idl b/mozilla/widget/public/nsITransferable.idl index 79a77846adc..a0946026484 100644 --- a/mozilla/widget/public/nsITransferable.idl +++ b/mozilla/widget/public/nsITransferable.idl @@ -29,24 +29,66 @@ // these probably shouldn't live here, but in some central repository shared // by the entire app. -#define kTextMime "text/plain" -#define kUnicodeMime "text/unicode" -#define kHTMLMime "text/html" -#define kAOLMailMime "AOLMAIL" -#define kPNGImageMime "image/png" -#define kJPEGImageMime "image/jpg" -#define kGIFImageMime "image/gif" -#define kFileMime "application/x-moz-file" -#define kURLMime "text/x-moz-url" -#define kNativeImageMime "application/x-moz-nativeimage" -#define kNativeHTMLMime "application/x-moz-nativehtml" +#define kTextMime "text/plain" +#define kUnicodeMime "text/unicode" +#define kHTMLMime "text/html" +#define kAOLMailMime "AOLMAIL" +#define kPNGImageMime "image/png" +#define kJPEGImageMime "image/jpg" +#define kGIFImageMime "image/gif" +#define kFileMime "application/x-moz-file" + +#define kURLMime "text/x-moz-url" // data contains url\ntitle +#define kURLDataMime "text/x-moz-url-data" // data contains url only +#define kURLDescriptionMime "text/x-moz-url-desc" // data contains description +#define kNativeImageMime "application/x-moz-nativeimage" +#define kNativeHTMLMime "application/x-moz-nativehtml" + +// the source URL for a file promise +#define kFilePromiseURLMime "application/x-moz-file-promise-url" +// a dataless flavor used to interact with the OS during file drags +#define kFilePromiseMime "application/x-moz-file-promise" +// a synthetic flavor, put into the transferable once we know the destination directory of a file drag +#define kFilePromiseDirectoryMime "application/x-moz-file-promise-dir" %} +/** + * nsIFlavorDataProvider allows a flavor to 'promise' data later, + * supplying the data lazily. + * + * To use it, call setTransferData, passing the flavor string, + * a nsIFlavorDataProvider QI'd to nsISupports, and a data size of 0. + * + * When someone calls getTransferData later, if the data size is + * stored as 0, the nsISupports will be QI'd to nsIFlavorDataProvider, + * and its getFlavorData called. + * + */ +interface nsITransferable; + +[scriptable, uuid(7E225E5F-711C-11D7-9FAE-000393636592)] +interface nsIFlavorDataProvider : nsISupports +{ + + /** + * Retrieve the data from this data provider. + * + * @param aTransferable (in parameter) the transferable we're being called for. + * @param aFlavor (in parameter) the flavor of data to retrieve + * @param aData the data. Some variant of class in nsISupportsPrimitives.idl + * @param aDataLen the length of the data + */ + void getFlavorData(in nsITransferable aTransferable, in string aFlavor, out nsISupports aData, out unsigned long aDataLen); +}; + + [scriptable, uuid(8B5314BC-DB01-11d2-96CE-0060B0FB9956)] interface nsITransferable : nsISupports { + const long kFlavorHasDataProvider = 0; + /** * Computes a list of flavors (mime types as nsISupportsCString) that the transferable * can export, either through intrinsic knowledge or output data converters. @@ -99,8 +141,9 @@ interface nsITransferable : nsISupports * will maintain its own copy the data, so it is not necessary to do that beforehand. * * @param aFlavor the flavor of data that is being set - * @param aData the data, some variant of class in nsISupportsPrimitives.idl - * @param aDataLen the length of the data + * @param aData the data, some variant of class in nsISupportsPrimitives.idl, + * or an nsIFlavorDataProvider (see above) + * @param aDataLen the length of the data, or 0 if passing a nsIFlavorDataProvider */ void setTransferData ( in string aFlavor, in nsISupports aData, in unsigned long aDataLen ) ; diff --git a/mozilla/widget/src/mac/nsClipboard.cpp b/mozilla/widget/src/mac/nsClipboard.cpp index 04e868ab4a9..99866cfc7e1 100644 --- a/mozilla/widget/src/mac/nsClipboard.cpp +++ b/mozilla/widget/src/mac/nsClipboard.cpp @@ -211,13 +211,19 @@ nsClipboard :: SetNativeClipboardData ( PRInt32 aWhichClipboard ) } } // if unicode else if ( strcmp(flavorStr, kPNGImageMime) == 0 || strcmp(flavorStr, kJPEGImageMime) == 0 || - strcmp(flavorStr, kGIFImageMime) == 0 ) { + strcmp(flavorStr, kGIFImageMime) == 0 || strcmp(flavorStr, kNativeImageMime) == 0 ) { // we have an image, which is in the transferable as an nsIImage. Convert it // to PICT (PicHandle) and put those bits on the clipboard. The actual size // of the picture is the size of the handle, not sizeof(Picture). - nsCOMPtr imageSupports; - errCode = mTransferable->GetTransferData ( flavorStr, getter_AddRefs(imageSupports), &dataSize ); - nsCOMPtr image ( do_QueryInterface(imageSupports) ); + nsCOMPtr transferSupports; + errCode = mTransferable->GetTransferData ( flavorStr, getter_AddRefs(transferSupports), &dataSize ); + nsCOMPtr ptrPrimitive(do_QueryInterface(transferSupports)); + nsCOMPtr image; + if (ptrPrimitive) { + nsCOMPtr primitiveData; + ptrPrimitive->GetData(getter_AddRefs(primitiveData)); + image = do_QueryInterface(primitiveData); + } if ( image ) { PicHandle picture = nsnull; image->ConvertToPICT ( &picture ); diff --git a/mozilla/widget/src/mac/nsDragService.cpp b/mozilla/widget/src/mac/nsDragService.cpp index eb20f8866dc..2f324da44ec 100644 --- a/mozilla/widget/src/mac/nsDragService.cpp +++ b/mozilla/widget/src/mac/nsDragService.cpp @@ -55,11 +55,10 @@ #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsCOMPtr.h" -#include "nsXPIDLString.h" #include "nsCRT.h" #include "nsPrimitiveHelpers.h" -#include "nsILocalFileMac.h" #include "nsWatchTask.h" +#include "nsLinebreakConverter.h" // rjc #include @@ -74,10 +73,16 @@ #include "nsPoint.h" #include "nsIWidget.h" #include "nsCarbonHelpers.h" +#include "nsGfxUtils.h" + +// file save stuff +#include "nsNetUtil.h" +#include "nsILocalFileMac.h" #ifdef MOZ_XUL #include "nsIXULContent.h" #endif + #include "nsIDOMElement.h" #include "nsIImageMac.h" #include "nsIImage.h" @@ -96,7 +101,10 @@ NS_IMPL_QUERY_INTERFACE3(nsDragService, nsIDragService, nsIDragSession, nsIDragS // DragService constructor // nsDragService::nsDragService() - : mDragRef(0), mDataItems(nsnull), mImageDraggingSupported(PR_FALSE), mDragSendDataUPP(nsnull) + : mDragSendDataUPP(nsnull) + , mDragRef(0) + , mDataItems(nsnull) + , mImageDraggingSupported(PR_FALSE) { #if USE_TRANSLUCENT_DRAGS // check if the Drag Manager supports image dragging @@ -123,7 +131,7 @@ nsDragService::~nsDragService() PRBool -nsDragService :: ComputeGlobalRectFromFrame ( nsIDOMNode* aDOMNode, Rect & outScreenRect ) +nsDragService::ComputeGlobalRectFromFrame ( nsIDOMNode* aDOMNode, Rect & outScreenRect ) { NS_ASSERTION ( aDOMNode, "Oopps, no DOM node" ); @@ -165,7 +173,6 @@ nsDragService :: ComputeGlobalRectFromFrame ( nsIDOMNode* aDOMNode, Rect & outSc // nsRect aRect(0,0,0,0); - nsIView *parentView = nsnull; aFrame->GetRect(aRect); // Find offset from our view @@ -218,7 +225,7 @@ nsDragService :: ComputeGlobalRectFromFrame ( nsIDOMNode* aDOMNode, Rect & outSc // Do all the work to kick it off. // NS_IMETHODIMP -nsDragService :: InvokeDragSession (nsIDOMNode *aDOMNode, nsISupportsArray * aTransferableArray, nsIScriptableRegion * aDragRgn, PRUint32 aActionType) +nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode, nsISupportsArray * aTransferableArray, nsIScriptableRegion * aDragRgn, PRUint32 aActionType) { ::InitCursor(); nsBaseDragService::InvokeDragSession ( aDOMNode, aTransferableArray, aDragRgn, aActionType ); @@ -232,10 +239,6 @@ nsDragService :: InvokeDragSession (nsIDOMNode *aDOMNode, nsISupportsArray * aTr printf("**** created drag ref %ld\n", theDragRef); #endif - // add the flavors from the transferables. Cache this array for the send data proc - mDataItems = aTransferableArray; - RegisterDragItemsAndFlavors ( aTransferableArray ) ; - Rect frameRect = { 0, 0, 0, 0 }; RgnHandle theDragRgn = ::NewRgn(); ::RectRgn(theDragRgn, &frameRect); @@ -253,6 +256,10 @@ printf("**** created drag ref %ld\n", theDragRef); else BuildDragRegion ( aDragRgn, aDOMNode, theDragRgn ); + // add the flavors from the transferables. Cache this array for the send data proc + mDataItems = aTransferableArray; + RegisterDragItemsAndFlavors(aTransferableArray, theDragRgn); + // we have to synthesize the native event because we may be called from JavaScript // through XPConnect. In that case, we only have a DOM event and no way to // get to the native event. As a consequence, we just always fake it. @@ -307,7 +314,7 @@ printf("**** disposing drag ref %ld\n", theDragRef); // Returns PR_TRUE if the region is something that can be used with SetDragImage() // PRBool -nsDragService :: BuildDragRegion ( nsIScriptableRegion* inRegion, nsIDOMNode* inNode, RgnHandle ioDragRgn ) +nsDragService::BuildDragRegion ( nsIScriptableRegion* inRegion, nsIDOMNode* inNode, RgnHandle ioDragRgn ) { PRBool retVal = PR_TRUE; nsCOMPtr geckoRegion; @@ -377,13 +384,17 @@ nsDragService :: BuildDragRegion ( nsIScriptableRegion* inRegion, nsIDOMNode* in // requested. // void -nsDragService :: RegisterDragItemsAndFlavors ( nsISupportsArray * inArray ) +nsDragService::RegisterDragItemsAndFlavors(nsISupportsArray* inArray, RgnHandle inDragRgn) { const FlavorFlags flags = 0; - unsigned int numDragItems = 0; + Rect dragRgnBounds = {0, 0, 0, 0}; + if (inDragRgn) + GetRegionBounds(inDragRgn, &dragRgnBounds); + + PRUint32 numDragItems = 0; inArray->Count ( &numDragItems ) ; - for ( int itemIndex = 0; itemIndex < numDragItems; ++itemIndex ) { + for ( PRUint32 itemIndex = 0; itemIndex < numDragItems; ++itemIndex ) { nsMimeMapperMac theMapper; nsCOMPtr genericItem; @@ -394,25 +405,39 @@ nsDragService :: RegisterDragItemsAndFlavors ( nsISupportsArray * inArray ) if ( NS_SUCCEEDED(currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList))) ) { PRUint32 numFlavors; flavorList->Count ( &numFlavors ); - for ( int flavorIndex = 0; flavorIndex < numFlavors; ++flavorIndex ) { + for ( PRUint32 flavorIndex = 0; flavorIndex < numFlavors; ++flavorIndex ) { nsCOMPtr genericWrapper; flavorList->GetElementAt ( flavorIndex, getter_AddRefs(genericWrapper) ); nsCOMPtr currentFlavor ( do_QueryInterface(genericWrapper) ); - if ( currentFlavor ) { - nsXPIDLCString flavorStr; - currentFlavor->ToString ( getter_Copies(flavorStr) ); - FlavorType macOSFlavor = theMapper.MapMimeTypeToMacOSType(flavorStr); - ::AddDragItemFlavor ( mDragRef, itemIndex, macOSFlavor, NULL, 0, flags ); - - // If we advertise text/unicode, then make sure we add 'TEXT' to the list - // of flavors supported since we will do the conversion ourselves in GetDataForFlavor() - if ( strcmp(flavorStr, kUnicodeMime) == 0 ) { - theMapper.MapMimeTypeToMacOSType(kTextMime); - ::AddDragItemFlavor ( mDragRef, itemIndex, 'TEXT', NULL, 0, flags ); - ::AddDragItemFlavor ( mDragRef, itemIndex, 'styl', NULL, 0, flags ); - } - } + if ( currentFlavor ) { + nsCAutoString flavorStr; + currentFlavor->GetData(flavorStr); + FlavorType macOSFlavor = theMapper.MapMimeTypeToMacOSType(flavorStr.get()); + + if (macOSFlavor == kDragFlavorTypePromiseHFS) { + // we got kFilePromiseMime + // kDragFlavorTypePromiseHFS is special. See http://developer.apple.com/technotes/tn/tn1085.html + PromiseHFSFlavor promiseData; + promiseData.fileType = 0; // let the file extension prevail! + promiseData.fileCreator = 0; + promiseData.fdFlags = 0; + promiseData.promisedFlavor = kDragPromisedFlavor; + + ::AddDragItemFlavor(mDragRef, itemIndex, kDragFlavorTypePromiseHFS, &promiseData, sizeof(promiseData), flavorNotSaved); + ::AddDragItemFlavor(mDragRef, itemIndex, kDragPromisedFlavor, NULL, 0, flavorNotSaved); + } + else + ::AddDragItemFlavor(mDragRef, itemIndex, macOSFlavor, NULL, 0, flags); + + // If we advertise text/unicode, then make sure we add 'TEXT' to the list + // of flavors supported since we will do the conversion ourselves in GetDataForFlavor() + if ( strcmp(flavorStr.get(), kUnicodeMime) == 0 ) { + theMapper.MapMimeTypeToMacOSType(kTextMime); + ::AddDragItemFlavor ( mDragRef, itemIndex, 'TEXT', NULL, 0, flags ); + ::AddDragItemFlavor ( mDragRef, itemIndex, 'styl', NULL, 0, flags ); + } + } } // foreach flavor in item } // if valid flavor list @@ -428,6 +453,8 @@ nsDragService :: RegisterDragItemsAndFlavors ( nsISupportsArray * inArray ) ::AddDragItemFlavor ( mDragRef, itemIndex, nsMimeMapperMac::MappingFlavor(), mapping, mappingLen, flags ); nsCRT::free ( mapping ); + + ::SetDragItemBounds(mDragRef, itemIndex, &dragRgnBounds); } } // foreach drag item @@ -443,7 +470,7 @@ nsDragService :: RegisterDragItemsAndFlavors ( nsISupportsArray * inArray ) // stop as soon as we find a match. // NS_IMETHODIMP -nsDragService :: GetData ( nsITransferable * aTransferable, PRUint32 aItemIndex ) +nsDragService::GetData ( nsITransferable * aTransferable, PRUint32 aItemIndex ) { nsresult errCode = NS_ERROR_FAILURE; @@ -473,33 +500,33 @@ nsDragService :: GetData ( nsITransferable * aTransferable, PRUint32 aItemIndex // implicitly handles conversions. PRUint32 cnt; flavorList->Count ( &cnt ); - for ( int i = 0; i < cnt; ++i ) { + for (PRUint32 i = 0; i < cnt; ++i) { nsCOMPtr genericWrapper; flavorList->GetElementAt ( i, getter_AddRefs(genericWrapper) ); nsCOMPtr currentFlavor ( do_QueryInterface(genericWrapper) ); if ( currentFlavor ) { // find MacOS flavor (but don't add it if it's not there) - nsXPIDLCString flavorStr; - currentFlavor->ToString ( getter_Copies(flavorStr) ); - FlavorType macOSFlavor = theMapper.MapMimeTypeToMacOSType(flavorStr, PR_FALSE); + nsCAutoString flavorStr; + currentFlavor->GetData(flavorStr); + FlavorType macOSFlavor = theMapper.MapMimeTypeToMacOSType(flavorStr.get(), PR_FALSE); #if DEBUG_DD -printf("looking for data in type %s, mac flavor %ld\n", NS_STATIC_CAST(const char*,flavorStr), macOSFlavor); +printf("looking for data in type %s, mac flavor %ld\n", flavorStr.get(), macOSFlavor); #endif // check if it is present in the current drag item. FlavorFlags unused; PRBool dataFound = PR_FALSE; - void* dataBuff; + void* dataBuff = nsnull; PRInt32 dataSize = 0; if ( macOSFlavor && ::GetFlavorFlags(mDragRef, itemRef, macOSFlavor, &unused) == noErr ) { nsresult loadResult = ExtractDataFromOS(mDragRef, itemRef, macOSFlavor, &dataBuff, &dataSize); - if ( NS_SUCCEEDED(loadResult) && dataBuff ) - dataFound = PR_TRUE; + if ( NS_SUCCEEDED(loadResult) && dataBuff ) + dataFound = PR_TRUE; } else { - // if we are looking for text/unicode and we fail to find it on the clipboard first, + // if we are looking for text/unicode and we fail to find it on the clipboard first, // try again with text/plain. If that is present, convert it to unicode. - if ( strcmp(flavorStr, kUnicodeMime) == 0 ) { + if ( strcmp(flavorStr.get(), kUnicodeMime) == 0 ) { if ( ::GetFlavorFlags(mDragRef, itemRef, 'TEXT', &unused) == noErr ) { // if 'styl' is available, we can get a script of the first run @@ -554,19 +581,35 @@ printf("looking for data in type %s, mac flavor %ld\n", NS_STATIC_CAST(const cha } // else we try one last ditch effort to find our data if ( dataFound ) { - nsCOMPtr genericDataWrapper; - if ( strcmp(flavorStr, kFileMime) == 0 ) { + nsCOMPtr genericDataWrapper; + + if ( strcmp(flavorStr.get(), kFileMime) == 0 ) { // we have a HFSFlavor struct in |dataBuff|. Create an nsLocalFileMac object. HFSFlavor* fileData = NS_REINTERPRET_CAST(HFSFlavor*, dataBuff); - NS_ASSERTION ( sizeof(HFSFlavor) == dataSize, "Ooops, we realy don't have a HFSFlavor" ); + NS_ASSERTION ( sizeof(HFSFlavor) == dataSize, "Ooops, we really don't have a HFSFlavor" ); nsCOMPtr file; if ( NS_SUCCEEDED(NS_NewLocalFileWithFSSpec(&fileData->fileSpec, PR_TRUE, getter_AddRefs(file))) ) genericDataWrapper = do_QueryInterface(file); } + else if ((strcmp(flavorStr.get(), kURLDataMime) == 0) || (strcmp(flavorStr.get(), kURLDescriptionMime) == 0)) { + // need to convert platform data to unicode + const char* castedText = NS_REINTERPRET_CAST(char*, dataBuff); + PRUnichar* convertedText = nsnull; + PRInt32 convertedTextLen = 0; + nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode(castedText, dataSize, + &convertedText, &convertedTextLen); + if (convertedText) + { + nsMemory::Free(dataBuff); + dataBuff = convertedText; + dataSize = convertedTextLen * 2; + nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr.get(), (void *)dataBuff, dataSize, getter_AddRefs(genericDataWrapper)); + } + } else { // we probably have some form of text. The DOM only wants LF, so convert k // from MacOS line endings to DOM line endings. - nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( flavorStr, &dataBuff, NS_REINTERPRET_CAST(int*, &dataSize) ); + nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr.get(), &dataBuff, NS_REINTERPRET_CAST(int*, &dataSize)); unsigned char *dataPtr = (unsigned char *) dataBuff; #if TARGET_CARBON @@ -582,15 +625,14 @@ printf("looking for data in type %s, mac flavor %ld\n", NS_STATIC_CAST(const cha dataPtr += sizeof(PRUnichar); } #endif - nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, (void *) dataPtr, dataSize, getter_AddRefs(genericDataWrapper) ); + nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr.get(), (void *) dataPtr, dataSize, getter_AddRefs(genericDataWrapper)); } // put it into the transferable. - errCode = aTransferable->SetTransferData ( flavorStr, genericDataWrapper, dataSize ); - #ifdef NS_DEBUG + errCode = aTransferable->SetTransferData(flavorStr.get(), genericDataWrapper, dataSize); +#ifdef NS_DEBUG if ( errCode != NS_OK ) printf("nsDragService:: Error setting data into transferable\n"); - #endif - +#endif nsMemory::Free ( dataBuff ); errCode = NS_OK; @@ -618,7 +660,7 @@ printf("looking for data in type %s, mac flavor %ld\n", NS_STATIC_CAST(const cha // ¥¥¥Êand index to this API // NS_IMETHODIMP -nsDragService :: IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval) +nsDragService::IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval) { if ( !_retval ) return NS_ERROR_INVALID_ARG; @@ -670,7 +712,7 @@ nsDragService :: IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval) // Returns the number of drop items present in the current drag. // NS_IMETHODIMP -nsDragService :: GetNumDropItems ( PRUint32 * aNumItems ) +nsDragService::GetNumDropItems ( PRUint32 * aNumItems ) { // we have to put it into a short first because that's what the MacOS API's expect. // After it's in a short, getting it into a long is no problem. Oh well. @@ -690,7 +732,7 @@ nsDragService :: GetNumDropItems ( PRUint32 * aNumItems ) // current dragRef w/out resorting to knowing the internals of the implementation // NS_IMETHODIMP -nsDragService :: SetDragReference ( DragReference aDragRef ) +nsDragService::SetDragReference ( DragReference aDragRef ) { mDragRef = aDragRef; return NS_OK; @@ -712,16 +754,16 @@ nsDragService :: SetDragReference ( DragReference aDragRef ) // and pass that along. // pascal OSErr -nsDragService :: DragSendDataProc ( FlavorType inFlavor, void* inRefCon, ItemReference inItemRef, - DragReference inDragRef ) +nsDragService::DragSendDataProc(FlavorType inFlavor, void* inRefCon, ItemReference inItemRef, + DragReference inDragRef) { OSErr retVal = noErr; - nsDragService* self = NS_STATIC_CAST(nsDragService*, inRefCon); - NS_ASSERTION ( self, "Refcon not set correctly for DragSendDataProc" ); - if ( self ) { + nsDragService* dragService = NS_STATIC_CAST(nsDragService*, inRefCon); + NS_ASSERTION ( dragService, "Refcon not set correctly for DragSendDataProc" ); + if (dragService) { void* data = nsnull; PRUint32 dataSize = 0; - retVal = self->GetDataForFlavor ( self->mDataItems, inDragRef, inItemRef, inFlavor, &data, &dataSize ); + retVal = dragService->GetDataForFlavor(dragService->mDataItems, inDragRef, inItemRef, inFlavor, &data, &dataSize); if ( retVal == noErr ) { // make the data accessable to the DragManager retVal = ::SetDragItemFlavorData ( inDragRef, inItemRef, inFlavor, data, dataSize, 0 ); @@ -750,141 +792,210 @@ nsDragService :: DragSendDataProc ( FlavorType inFlavor, void* inRefCon, ItemRef // wouldn't have been allowed to look for unicode. // OSErr -nsDragService :: GetDataForFlavor ( nsISupportsArray* inDragItems, DragReference inDragRef, unsigned int inItemIndex, - FlavorType inFlavor, void** outData, unsigned int* outDataSize ) +nsDragService::GetDataForFlavor(nsISupportsArray* inDragItems, DragReference inDragRef, unsigned int inItemIndex, + FlavorType inFlavor, void** outData, unsigned int* outDataSize) { if ( !inDragItems || !inDragRef ) return paramErr; + *outData = nsnull; + *outDataSize = 0; + OSErr retVal = noErr; + nsresult rv; // (assumes that the items were placed into the transferable as nsITranferable*'s, not nsISupports*'s.) nsCOMPtr genericItem; - inDragItems->GetElementAt ( inItemIndex, getter_AddRefs(genericItem) ); - nsCOMPtr item ( do_QueryInterface(genericItem) ); - if ( item ) { - nsCAutoString mimeFlavor; + inDragItems->GetElementAt(inItemIndex, getter_AddRefs(genericItem)); + nsCOMPtr item(do_QueryInterface(genericItem)); + if (!item) return cantGetFlavorErr; // create a mime mapper to help us out based on data in a special flavor for this item. - char* mappings = LookupMimeMappingsForItem(inDragRef, inItemIndex) ; - nsMimeMapperMac theMapper ( mappings ); - theMapper.MapMacOSTypeToMimeType ( inFlavor, mimeFlavor ); - nsMemory::Free ( mappings ); + char* mappings = LookupMimeMappingsForItem(inDragRef, inItemIndex); + nsMimeMapperMac theMapper(mappings); + + nsCAutoString mimeFlavor; + theMapper.MapMacOSTypeToMimeType(inFlavor, mimeFlavor); + nsMemory::Free(mappings); + + // if someone was asking for text/plain, lookup unicode instead so we can convert it. + PRBool needToDoConversionToPlainText = PR_FALSE; + const char* actualFlavor = mimeFlavor.get(); + if ( strcmp(mimeFlavor.get(), kTextMime) == 0 || inFlavor == 'styl' ) + { + actualFlavor = kUnicodeMime; + needToDoConversionToPlainText = PR_TRUE; + } + else if (strcmp(actualFlavor, kURLDataMime) == 0) + { + needToDoConversionToPlainText = PR_TRUE; + } + else if (strcmp(actualFlavor, kURLDescriptionMime) == 0) + { + needToDoConversionToPlainText = PR_TRUE; + } + else if (strcmp(actualFlavor, kFilePromiseMime) == 0) + { + /* Here's how file dragging works: - // if someone was asking for text/plain, lookup unicode instead so we can convert it. - PRBool needToDoConversionToPlainText = PR_FALSE; - const char* actualFlavor = mimeFlavor.get(); - if ( strcmp(mimeFlavor.get(),kTextMime) == 0 || - inFlavor == 'styl' ) { - actualFlavor = kUnicodeMime; - needToDoConversionToPlainText = PR_TRUE; - } - else - actualFlavor = mimeFlavor.get(); + Drag code adds a kFilePromiseMime flavor to the transferable, with an + nsIFlavorDataProvider. + It also adds a kFilePromiseURLMime flavor, with a string containing the source + url. + + We map that to the OS drag flavor kDragFlavorTypePromiseHFS, which promises + the flavor kDragPromisedFlavor. The OS asks for kDragPromisedFlavor, and we + map that back to kFilePromiseMime. + + When asked for kFilePromiseMime data (here), we figure out the drop location from + the OS, and set that as an nsILocalFile on the kFilePromiseDirectoryMime flavor. We then + call GetTransferData() for the kFilePromiseMime flavor, which triggers + the nsIFlavorDataProvider to do the save. + */ + + nsCOMPtr dropDirectory; + OSErr err = GetHFSPromiseDropDirectory(inDragRef, inItemIndex, inFlavor, getter_AddRefs(dropDirectory)); + if (err != noErr) return err; + + // now add a flavor to the transferable + nsCOMPtr localFileISupports = do_QueryInterface(dropDirectory); + item->SetTransferData(kFilePromiseDirectoryMime, localFileISupports, sizeof(nsILocalFile*)); + + // now request the kFilePromiseMime data, which will invoke the data provider + // If successful, the returned data is a reference to the resulting file. + nsCOMPtr fileDataPrimitive; + PRUint32 dataSize = 0; + rv = item->GetTransferData(kFilePromiseMime, getter_AddRefs(fileDataPrimitive), &dataSize); + if (NS_FAILED(rv)) return cantGetFlavorErr; + + // if we successfully saved, tell the Drag Manager + nsCOMPtr resultFile = do_QueryInterface(fileDataPrimitive); + if (resultFile) + return SetDropFileInDrag(inDragRef, inItemIndex, inFlavor, resultFile); + + // something went wrong. + return cantGetFlavorErr; + } + else if (strcmp(actualFlavor, kNativeImageMime) == 0) + { + PRUint32 dataSize = 0; + nsCOMPtr transferSupports; + rv = item->GetTransferData(actualFlavor, getter_AddRefs(transferSupports), &dataSize); + if (NS_FAILED(rv)) return cantGetFlavorErr; + + nsCOMPtr ptrPrimitive(do_QueryInterface(transferSupports)); + if (!ptrPrimitive) return cantGetFlavorErr; + + nsCOMPtr primitiveData; + ptrPrimitive->GetData(getter_AddRefs(primitiveData)); + nsCOMPtr image = do_QueryInterface(primitiveData); + if (!image) return cantGetFlavorErr; - *outDataSize = 0; - nsCOMPtr data; - if ( NS_SUCCEEDED(item->GetTransferData(actualFlavor, getter_AddRefs(data), outDataSize)) ) { - if ( strcmp(actualFlavor, kNativeImageMime) == 0 ) { - // unwrap the image from its nsISupportsPrimitive wrapper - nsCOMPtr ptr(do_QueryInterface(data)); - nsCOMPtr image; - ptr->GetData(getter_AddRefs(image)); - - // we have an image, which is in the transferable as an nsIImage. Convert it - // to PICT (PicHandle) and put those bits on the clipboard. The actual size - // of the picture is the size of the handle, not sizeof(Picture). - nsCOMPtr imageMac ( do_QueryInterface(image) ); - if ( imageMac ) { - PicHandle picture = nsnull; - imageMac->ConvertToPICT ( &picture ); - *outDataSize = ::GetHandleSize((Handle)picture); - *outData = nsMemory::Alloc(*outDataSize); - ::HLock((Handle)picture); - ::BlockMoveData(*picture, *outData, *outDataSize); - ::HUnlock((Handle)picture); - ::KillPicture(picture); - } - else - NS_WARNING ( "Image isn't an nsIImageMac in transferable" ); - } - else { - nsPrimitiveHelpers::CreateDataFromPrimitive ( actualFlavor, data, outData, *outDataSize ); - - // if required, do the extra work to convert unicode to plain text and replace the output - // values with the plain text. - if ( needToDoConversionToPlainText ) { - char* plainTextData = nsnull; - PRUnichar* castedUnicode = NS_REINTERPRET_CAST(PRUnichar*, *outData); - PRInt32 plainTextLen = 0; - nsresult rv = - nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText ( castedUnicode, *outDataSize / 2, &plainTextData, &plainTextLen ); + PicHandle picture = nsnull; + image->ConvertToPICT(&picture); + if (!picture) return cantGetFlavorErr; - ScriptCodeRun *scriptCodeRuns = nsnull; - PRInt32 scriptRunOutLen; - - // if characters are not mapped from Unicode then try native API to convert to - // available script - if (rv == NS_ERROR_UENC_NOMAPPING) { - if (plainTextData) { - nsMemory::Free(plainTextData); - plainTextData = nsnull; - } - rv = nsMacNativeUnicodeConverter::ConvertUnicodetoScript(castedUnicode, - *outDataSize / sizeof(PRUnichar), - &plainTextData, - &plainTextLen, - &scriptCodeRuns, - &scriptRunOutLen); - } - else if (NS_SUCCEEDED(rv)) { - // create a single run with the default system script - scriptCodeRuns = NS_REINTERPRET_CAST(ScriptCodeRun*, - nsMemory::Alloc(sizeof(ScriptCodeRun))); - if (scriptCodeRuns) { - scriptCodeRuns[0].offset = 0; - scriptCodeRuns[0].script = (ScriptCode) ::GetScriptManagerVariable(smSysScript); - scriptRunOutLen = 1; - } - } - - if ( plainTextData && *outData ) { - nsMemory::Free(*outData); - *outData = nsnull; - *outDataSize = 0; - - if (inFlavor != 'styl') { - *outData = plainTextData; - *outDataSize = plainTextLen; - } - else { - nsMemory::Free(plainTextData); // discard 'TEXT' - - char *stylData; - PRInt32 stylLen; - // create 'styl' from the script runs - if (scriptCodeRuns) { - rv = CreateStylFromScriptRuns(scriptCodeRuns, - scriptRunOutLen, - &stylData, - &stylLen); - if (NS_SUCCEEDED(rv)) { - *outData = stylData; - *outDataSize = stylLen; - } - } - } - } - else - retVal = cantGetFlavorErr; - if (scriptCodeRuns) - nsMemory::Free(scriptCodeRuns); - } - } + PRInt32 pictSize = ::GetHandleSize((Handle)picture); + char* pictData = nsnull; + if (pictSize > 0) + pictData = (char*)nsMemory::Alloc(pictSize); + if (pictData) { + ::BlockMoveData(*picture, pictData, pictSize); // doesn't move memory + *outData = (void*)pictData; + *outDataSize = pictSize; + retVal = noErr; } else retVal = cantGetFlavorErr; - } // if valid item + + ::KillPicture(picture); + return retVal; + } + + nsCOMPtr data; + if (NS_SUCCEEDED(item->GetTransferData(actualFlavor, getter_AddRefs(data), outDataSize))) + { + nsPrimitiveHelpers::CreateDataFromPrimitive ( actualFlavor, data, outData, *outDataSize ); + + // Convert unix to mac linebreaks, since mac linebreaks are required for clipboard compatibility. + // I'm making the assumption here that the substitution will be entirely in-place, since both + // types of line breaks are 1-byte. + PRUnichar* castedUnicode = NS_REINTERPRET_CAST(PRUnichar*, *outData); + nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(&castedUnicode, + nsLinebreakConverter::eLinebreakUnix, + nsLinebreakConverter::eLinebreakMac, + *outDataSize / sizeof(PRUnichar), nsnull); + + // if required, do the extra work to convert unicode to plain text and replace the output + // values with the plain text. + if ( needToDoConversionToPlainText ) { + char* plainTextData = nsnull; + PRUnichar* castedUnicode = NS_REINTERPRET_CAST(PRUnichar*, *outData); + PRInt32 plainTextLen = 0; + nsresult rv = + nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText ( castedUnicode, *outDataSize / 2, &plainTextData, &plainTextLen ); + + ScriptCodeRun *scriptCodeRuns = nsnull; + PRInt32 scriptRunOutLen; + + // if characters are not mapped from Unicode then try native API to convert to + // available script + if (rv == NS_ERROR_UENC_NOMAPPING) { + if (plainTextData) { + nsMemory::Free(plainTextData); + plainTextData = nsnull; + } + rv = nsMacNativeUnicodeConverter::ConvertUnicodetoScript(castedUnicode, + *outDataSize / sizeof(PRUnichar), + &plainTextData, + &plainTextLen, + &scriptCodeRuns, + &scriptRunOutLen); + } + else if (NS_SUCCEEDED(rv)) { + // create a single run with the default system script + scriptCodeRuns = NS_REINTERPRET_CAST(ScriptCodeRun*, + nsMemory::Alloc(sizeof(ScriptCodeRun))); + if (scriptCodeRuns) { + scriptCodeRuns[0].offset = 0; + scriptCodeRuns[0].script = (ScriptCode) ::GetScriptManagerVariable(smSysScript); + scriptRunOutLen = 1; + } + } + + if ( plainTextData && *outData ) { + nsMemory::Free(*outData); + *outData = nsnull; + *outDataSize = 0; + + if (inFlavor != 'styl') { + *outData = plainTextData; + *outDataSize = plainTextLen; + } + else { + nsMemory::Free(plainTextData); // discard 'TEXT' + + char *stylData; + PRInt32 stylLen; + // create 'styl' from the script runs + if (scriptCodeRuns) { + rv = CreateStylFromScriptRuns(scriptCodeRuns, + scriptRunOutLen, + &stylData, + &stylLen); + if (NS_SUCCEEDED(rv)) { + *outData = stylData; + *outDataSize = stylLen; + } + } + } + } + else + retVal = cantGetFlavorErr; + if (scriptCodeRuns) + nsMemory::Free(scriptCodeRuns); + } + } return retVal; @@ -901,7 +1012,7 @@ nsDragService :: GetDataForFlavor ( nsISupportsArray* inDragItems, DragReference // Caller is responsible for deleting the memory. // char* -nsDragService :: LookupMimeMappingsForItem ( DragReference inDragRef, ItemReference inItemRef ) +nsDragService::LookupMimeMappingsForItem ( DragReference inDragRef, ItemReference inItemRef ) { char* mapperData = nsnull; PRInt32 mapperSize = 0; @@ -939,7 +1050,7 @@ nsDragService :: LookupMimeMappingsForItem ( DragReference inDragRef, ItemRefere // the data for whatever reason. // nsresult -nsDragService :: ExtractDataFromOS ( DragReference inDragRef, ItemReference inItemRef, ResType inFlavor, +nsDragService::ExtractDataFromOS ( DragReference inDragRef, ItemReference inItemRef, ResType inFlavor, void** outBuffer, PRInt32* outBuffSize ) { if ( !outBuffer || !outBuffSize || !inFlavor ) @@ -985,7 +1096,7 @@ nsDragService :: ExtractDataFromOS ( DragReference inDragRef, ItemReference inIt // nsresult -nsDragService :: StartDragSession ( ) +nsDragService::StartDragSession ( ) { nsWatchTask::GetTask().Suspend(); @@ -993,7 +1104,7 @@ nsDragService :: StartDragSession ( ) } nsresult -nsDragService :: EndDragSession ( ) +nsDragService::EndDragSession ( ) { nsWatchTask::GetTask().Resume(); @@ -1008,7 +1119,7 @@ nsDragService :: EndDragSession ( ) // drag action changes based on modifier keys // NS_IMETHODIMP -nsDragService :: SetDragAction ( PRUint32 anAction ) +nsDragService::SetDragAction ( PRUint32 anAction ) { const PRInt32 kCopyCursorID = 144; const PRInt32 kLinkCursorID = 145; @@ -1032,3 +1143,66 @@ nsDragService :: SetDragAction ( PRUint32 anAction ) return nsBaseDragService::SetDragAction(anAction); } + +#pragma mark - +// Utility routines for dragging files to the Finder + +static OSErr GetDropDirectory(DragReference dragRef, FSSpecPtr fssOut) +{ + OSErr err; + + AEDesc dropLocAlias = { typeNull, nil }; + err = ::GetDropLocation(dragRef, &dropLocAlias); + if (err != noErr) return err; + + if (dropLocAlias.descriptorType != typeAlias) + return paramErr; + + AEDesc dropLocFSS = { typeNull, nil }; + if ((err = ::AECoerceDesc(&dropLocAlias, typeFSS, &dropLocFSS)) == noErr) + { + err = ::AEGetDescData(&dropLocFSS, fssOut, sizeof(FSSpec)); + (void)::AEDisposeDesc(&dropLocFSS); + } + + if (dropLocAlias.dataHandle) + (void)::AEDisposeDesc(&dropLocAlias); + + return err; +} + +OSErr nsDragService::GetHFSPromiseDropDirectory(DragReference inDragRef, unsigned int inItemIndex, + FlavorType inFlavor, nsILocalFile** outDir) +{ + // get the promise data + PromiseHFSFlavor promiseData; + Size dataSize = sizeof(promiseData); + OSErr err = ::GetFlavorData(inDragRef, inItemIndex, kDragFlavorTypePromiseHFS, &promiseData, &dataSize, 0); + if (err != noErr) return err; + + FSSpec dropLocation; + err = GetDropDirectory(inDragRef, &dropLocation); + if (err != noErr) return err; + + nsCOMPtr dropFolderSpec; + nsresult rv = NS_NewLocalFileWithFSSpec(&dropLocation, PR_FALSE, getter_AddRefs(dropFolderSpec)); + if (NS_FAILED(rv)) return fnfErr; + + CallQueryInterface(dropFolderSpec, outDir); + return noErr; +} + +OSErr +nsDragService::SetDropFileInDrag(DragReference inDragRef, unsigned int inItemIndex, + FlavorType inFlavor, nsILocalFile* inFile) +{ + nsCOMPtr targetFileMac = do_QueryInterface(inFile); + if (!targetFileMac) return paramErr; + + FSSpec targetFileSpec; + nsresult rv = targetFileMac->GetFSSpec(&targetFileSpec); + if (NS_FAILED(rv)) return paramErr; + + return ::SetDragItemFlavorData(inDragRef, inItemIndex, inFlavor, &targetFileSpec, sizeof(FSSpec), 0); +} + diff --git a/mozilla/widget/src/mac/nsDragService.h b/mozilla/widget/src/mac/nsDragService.h index 600ffcd6371..44e6305a5a2 100644 --- a/mozilla/widget/src/mac/nsDragService.h +++ b/mozilla/widget/src/mac/nsDragService.h @@ -54,8 +54,7 @@ #include #include -class nsNativeDragTarget; - +class nsILocalFile; class nsDragService : public nsBaseDragService, public nsIDragSessionMac { @@ -85,7 +84,7 @@ private: char* LookupMimeMappingsForItem ( DragReference inDragRef, ItemReference itemRef ) ; - void RegisterDragItemsAndFlavors ( nsISupportsArray * inArray ) ; + void RegisterDragItemsAndFlavors ( nsISupportsArray * inArray, RgnHandle inDragRgn ) ; PRBool BuildDragRegion ( nsIScriptableRegion* inRegion, nsIDOMNode* inNode, RgnHandle ioDragRgn ) ; OSErr GetDataForFlavor ( nsISupportsArray* inDragItems, DragReference inDragRef, unsigned int inItemIndex, FlavorType inFlavor, void** outData, unsigned int * outSize ) ; @@ -95,16 +94,22 @@ private: // compute a screen rect from the frame associated with the given dom node PRBool ComputeGlobalRectFromFrame ( nsIDOMNode* aDOMNode, Rect & outScreenRect ) ; + OSErr GetHFSPromiseDropDirectory(DragReference inDragRef, unsigned int inItemIndex, + FlavorType inFlavor, nsILocalFile** outDir); + + OSErr SetDropFileInDrag(DragReference inDragRef, unsigned int inItemIndex, + FlavorType inFlavor, nsILocalFile* inFile); + // callback for the MacOS DragManager when a drop site asks for data static pascal OSErr DragSendDataProc ( FlavorType inFlavor, void* inRefCon, ItemReference theItemRef, DragReference inDragRef ) ; - PRBool mImageDraggingSupported; DragSendDataUPP mDragSendDataUPP; DragReference mDragRef; // reference to _the_ drag. There can be only one. nsISupportsArray* mDataItems; // cached here for when we start the drag so the // DragSendDataProc has access to them. // ONLY VALID DURING A DRAG STARTED WITHIN THIS APP. + PRBool mImageDraggingSupported; }; // class nsDragService diff --git a/mozilla/widget/src/mac/nsMimeMapper.cpp b/mozilla/widget/src/mac/nsMimeMapper.cpp index c41addac1fc..f368aacc538 100644 --- a/mozilla/widget/src/mac/nsMimeMapper.cpp +++ b/mozilla/widget/src/mac/nsMimeMapper.cpp @@ -51,7 +51,13 @@ #include #include -nsMimeMapperMac :: nsMimeMapperMac ( const char* inMappings ) + +enum { + kScrapFlavorTypeURL = FOUR_CHAR_CODE('url '), + kScrapFlavorTypeURLDesc = FOUR_CHAR_CODE('urld') +}; + +nsMimeMapperMac::nsMimeMapperMac ( const char* inMappings ) : mCounter(0) { if (inMappings && strlen(inMappings) ) @@ -59,7 +65,7 @@ nsMimeMapperMac :: nsMimeMapperMac ( const char* inMappings ) } -nsMimeMapperMac :: ~nsMimeMapperMac ( ) +nsMimeMapperMac::~nsMimeMapperMac ( ) { } @@ -76,7 +82,7 @@ nsMimeMapperMac :: ~nsMimeMapperMac ( ) // be exported along with the data. // ResType -nsMimeMapperMac :: MapMimeTypeToMacOSType ( const char* aMimeStr, PRBool inAddIfNotPresent ) +nsMimeMapperMac::MapMimeTypeToMacOSType ( const char* aMimeStr, PRBool inAddIfNotPresent ) { ResType format = 0; @@ -101,9 +107,15 @@ nsMimeMapperMac :: MapMimeTypeToMacOSType ( const char* aMimeStr, PRBool inAddIf else if ( PL_strcmp(aMimeStr, kTextMime) == 0 ) format = kScrapFlavorTypeText; else if ( PL_strcmp(aMimeStr, kFileMime) == 0 ) - format = flavorTypeHFS; + format = kDragFlavorTypeHFS; + else if ( PL_strcmp(aMimeStr, kFilePromiseMime) == 0 ) + format = kDragFlavorTypePromiseHFS; else if ( PL_strcmp(aMimeStr, kNativeImageMime) == 0 ) format = kScrapFlavorTypePicture; + else if ( PL_strcmp(aMimeStr, kURLDataMime) == 0 ) + format = kScrapFlavorTypeURL; + else if ( PL_strcmp(aMimeStr, kURLDescriptionMime) == 0 ) + format = kScrapFlavorTypeURLDesc; #if NOT_YET else if ( PL_strcmp(aMimeStr, kPNGImageMime) == 0 ) format = kScrapFlavorTypePicture; @@ -140,13 +152,17 @@ nsMimeMapperMac :: MapMimeTypeToMacOSType ( const char* aMimeStr, PRBool inAddIf // we probably won't get a match in that case. // void -nsMimeMapperMac :: MapMacOSTypeToMimeType ( ResType inMacType, nsCAutoString & outMimeStr ) +nsMimeMapperMac::MapMacOSTypeToMimeType ( ResType inMacType, nsCAutoString & outMimeStr ) { switch ( inMacType ) { - case kScrapFlavorTypeText: outMimeStr = kTextMime; break; - case kScrapFlavorTypeUnicode: outMimeStr = kUnicodeMime; break; - case flavorTypeHFS: outMimeStr = kFileMime; break; + case kScrapFlavorTypeText: outMimeStr = kTextMime; break; + case kScrapFlavorTypeUnicode: outMimeStr = kUnicodeMime; break; + case kDragFlavorTypeHFS: outMimeStr = kFileMime; break; + case kDragFlavorTypePromiseHFS: outMimeStr = kFilePromiseMime; break; + case kDragPromisedFlavor: outMimeStr = kFilePromiseMime; break; + case kScrapFlavorTypeURL: outMimeStr = kURLDataMime; break; + case kScrapFlavorTypeURLDesc: outMimeStr = kURLDescriptionMime; break; // if someone gives us PICT (or we could have put it there), use // the native image mime type. @@ -191,7 +207,7 @@ nsMimeMapperMac :: MapMacOSTypeToMimeType ( ResType inMacType, nsCAutoString & o // NOTE: we make the assumption that the data is NULL terminated. // void -nsMimeMapperMac :: ParseMappings ( const char* inMappings ) +nsMimeMapperMac::ParseMappings ( const char* inMappings ) { if ( !inMappings ) return; @@ -222,7 +238,7 @@ nsMimeMapperMac :: ParseMappings ( const char* inMappings ) // the null at the end of the string. // char* -nsMimeMapperMac :: ExportMapping ( short * outLength ) const +nsMimeMapperMac::ExportMapping ( short * outLength ) const { NS_WARN_IF_FALSE ( outLength, "No out param provided" ); if ( outLength ) diff --git a/mozilla/widget/src/xpwidgets/nsHTMLFormatConverter.h b/mozilla/widget/src/xpwidgets/nsHTMLFormatConverter.h index c63c78b1c80..e603f9fdff8 100644 --- a/mozilla/widget/src/xpwidgets/nsHTMLFormatConverter.h +++ b/mozilla/widget/src/xpwidgets/nsHTMLFormatConverter.h @@ -50,13 +50,7 @@ public: // nsISupports NS_DECL_ISUPPORTS - - // nsIHTMLConverter - NS_IMETHOD GetInputDataFlavors(nsISupportsArray **_retval) ; - NS_IMETHOD GetOutputDataFlavors(nsISupportsArray **_retval) ; - NS_IMETHOD CanConvert(const char *aFromDataFlavor, const char *aToDataFlavor, PRBool *_retval) ; - NS_IMETHOD Convert(const char *aFromDataFlavor, nsISupports *aFromData, PRUint32 aDataLen, - const char *aToDataFlavor, nsISupports **aToData, PRUint32 *aDataToLen) ; + NS_DECL_NSIFORMATCONVERTER protected: diff --git a/mozilla/widget/src/xpwidgets/nsTransferable.cpp b/mozilla/widget/src/xpwidgets/nsTransferable.cpp index 01ab617744c..e656752cdf0 100644 --- a/mozilla/widget/src/xpwidgets/nsTransferable.cpp +++ b/mozilla/widget/src/xpwidgets/nsTransferable.cpp @@ -318,32 +318,23 @@ nsTransferable::~nsTransferable() // account any converter that may be registered. This list consists of // nsISupportsCString objects so that the flavor list can be accessed from JS. // -NS_IMETHODIMP -nsTransferable :: GetTransferDataFlavors(nsISupportsArray ** aDataFlavorList) +nsresult +nsTransferable::GetTransferDataFlavors(nsISupportsArray ** aDataFlavorList) { - if (!aDataFlavorList) - return NS_ERROR_INVALID_ARG; + nsresult rv = NS_NewISupportsArray ( aDataFlavorList ); + if (NS_FAILED(rv)) return rv; - nsresult rv = NS_OK; - - NS_NewISupportsArray ( aDataFlavorList ); - if ( *aDataFlavorList ) { - for ( PRInt32 i=0; iCount(); ++i ) { - DataStruct * data = (DataStruct *)mDataArray->ElementAt(i); - nsCOMPtr flavorWrapper; - rv = nsComponentManager::CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull, - NS_GET_IID(nsISupportsCString), getter_AddRefs(flavorWrapper)); - if ( flavorWrapper ) { - flavorWrapper->SetData ( data->GetFlavor() ); - nsCOMPtr genericWrapper ( do_QueryInterface(flavorWrapper) ); - (*aDataFlavorList)->AppendElement( genericWrapper ); - } + for ( PRInt32 i=0; iCount(); ++i ) { + DataStruct * data = (DataStruct *)mDataArray->ElementAt(i); + nsCOMPtr flavorWrapper = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID); + if ( flavorWrapper ) { + flavorWrapper->SetData ( data->GetFlavor() ); + nsCOMPtr genericWrapper ( do_QueryInterface(flavorWrapper) ); + (*aDataFlavorList)->AppendElement( genericWrapper ); } } - else - rv = NS_ERROR_OUT_OF_MEMORY; - return rv; + return NS_OK; } @@ -355,27 +346,39 @@ nsTransferable :: GetTransferDataFlavors(nsISupportsArray ** aDataFlavorList) // accessable from JS. // NS_IMETHODIMP -nsTransferable :: GetTransferData(const char *aFlavor, nsISupports **aData, PRUint32 *aDataLen) +nsTransferable::GetTransferData(const char *aFlavor, nsISupports **aData, PRUint32 *aDataLen) { - if ( !aFlavor || !aData ||!aDataLen ) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aFlavor && aData && aDataLen); - PRBool found = PR_FALSE; + nsresult rv = NS_OK; // first look and see if the data is present in one of the intrinsic flavors PRInt32 i; - for ( i=0; iCount(); ++i ) { + for (i = 0; i < mDataArray->Count(); ++i ) { DataStruct * data = (DataStruct *)mDataArray->ElementAt(i); if ( data->GetFlavor().Equals(aFlavor) ) { data->GetData(aData, aDataLen); + if (*aDataLen == kFlavorHasDataProvider) { + // do we have a data provider? + nsCOMPtr dataProvider = do_QueryInterface(*aData); + if (dataProvider) { + rv = dataProvider->GetFlavorData(this, aFlavor, aData, aDataLen); + if (NS_FAILED(rv)) + break; // the provider failed. fall into the conveter code below. + } + } if (*aData && *aDataLen > 0) return NS_OK; + + break; } } + PRBool found = PR_FALSE; + // if not, try using a format converter to get the requested flavor - if ( !found && mFormatConv ) { - for (i=0;iCount();i++) { + if ( mFormatConv ) { + for (i = 0; i < mDataArray->Count(); ++i) { DataStruct * data = (DataStruct *)mDataArray->ElementAt(i); PRBool canConvert = PR_FALSE; mFormatConv->CanConvert(data->GetFlavor().get(), aFlavor, &canConvert); @@ -383,8 +386,18 @@ nsTransferable :: GetTransferData(const char *aFlavor, nsISupports **aData, PRUi nsCOMPtr dataBytes; PRUint32 len; data->GetData(getter_AddRefs(dataBytes), &len); + if (len == kFlavorHasDataProvider) { + // do we have a data provider? + nsCOMPtr dataProvider = do_QueryInterface(dataBytes); + if (dataProvider) { + rv = dataProvider->GetFlavorData(this, aFlavor, getter_AddRefs(dataBytes), &len); + if (NS_FAILED(rv)) + break; // give up + } + } mFormatConv->Convert(data->GetFlavor().get(), dataBytes, len, aFlavor, aData, aDataLen); found = PR_TRUE; + break; } } } @@ -401,8 +414,7 @@ nsTransferable :: GetTransferData(const char *aFlavor, nsISupports **aData, PRUi NS_IMETHODIMP nsTransferable::GetAnyTransferData(char **aFlavor, nsISupports **aData, PRUint32 *aDataLen) { - if ( !aFlavor || !aData || !aDataLen ) - return NS_ERROR_FAILURE; + NS_ENSURE_ARG_POINTER(aFlavor && aData && aDataLen); for ( PRInt32 i=0; i < mDataArray->Count(); ++i ) { DataStruct * data = (DataStruct *)mDataArray->ElementAt(i); @@ -425,12 +437,11 @@ nsTransferable::GetAnyTransferData(char **aFlavor, nsISupports **aData, PRUint32 NS_IMETHODIMP nsTransferable::SetTransferData(const char *aFlavor, nsISupports *aData, PRUint32 aDataLen) { - if ( !aFlavor ) - return NS_ERROR_FAILURE; + NS_ENSURE_ARG(aFlavor); // first check our intrinsic flavors to see if one has been registered. PRInt32 i = 0; - for ( i=0; iCount(); ++i ) { + for (i = 0; i < mDataArray->Count(); ++i) { DataStruct * data = (DataStruct *)mDataArray->ElementAt(i); if ( data->GetFlavor().Equals(aFlavor) ) { data->SetData ( aData, aDataLen ); @@ -440,7 +451,7 @@ nsTransferable::SetTransferData(const char *aFlavor, nsISupports *aData, PRUint3 // if not, try using a format converter to find a flavor to put the data in if ( mFormatConv ) { - for ( i=0; iCount(); ++i) { + for (i = 0; i < mDataArray->Count(); ++i) { DataStruct * data = (DataStruct *)mDataArray->ElementAt(i); PRBool canConvert = PR_FALSE; mFormatConv->CanConvert(aFlavor, data->GetFlavor().get(), &canConvert); @@ -470,7 +481,7 @@ nsTransferable::SetTransferData(const char *aFlavor, nsISupports *aData, PRUint3 // Adds a data flavor to our list with no data. Error if it already exists. // NS_IMETHODIMP -nsTransferable :: AddDataFlavor(const char *aDataFlavor) +nsTransferable::AddDataFlavor(const char *aDataFlavor) { if (GetDataForFlavor (mDataArray, aDataFlavor)) return NS_ERROR_FAILURE; @@ -512,11 +523,8 @@ nsTransferable::RemoveDataFlavor(const char *aDataFlavor) NS_IMETHODIMP nsTransferable::IsLargeDataSet(PRBool *_retval) { - if ( !_retval ) - return NS_ERROR_FAILURE; - + NS_ENSURE_ARG_POINTER(_retval); *_retval = PR_FALSE; - return NS_OK; } @@ -527,7 +535,7 @@ nsTransferable::IsLargeDataSet(PRBool *_retval) */ NS_IMETHODIMP nsTransferable::SetConverter(nsIFormatConverter * aConverter) { - mFormatConv = dont_QueryInterface(aConverter); + mFormatConv = aConverter; return NS_OK; } @@ -538,15 +546,9 @@ NS_IMETHODIMP nsTransferable::SetConverter(nsIFormatConverter * aConverter) */ NS_IMETHODIMP nsTransferable::GetConverter(nsIFormatConverter * *aConverter) { - if ( !aConverter ) - return NS_ERROR_FAILURE; - - if ( mFormatConv ) { - *aConverter = mFormatConv; - NS_ADDREF(*aConverter); - } else - *aConverter = nsnull; - + NS_ENSURE_ARG_POINTER(aConverter); + *aConverter = mFormatConv; + NS_IF_ADDREF(*aConverter); return NS_OK; } @@ -558,10 +560,9 @@ NS_IMETHODIMP nsTransferable::GetConverter(nsIFormatConverter * *aConverter) // intrinsic knowledge or input data converters. // NS_IMETHODIMP -nsTransferable :: FlavorsTransferableCanImport(nsISupportsArray **_retval) +nsTransferable::FlavorsTransferableCanImport(nsISupportsArray **_retval) { - if ( !_retval ) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); // Get the flavor list, and on to the end of it, append the list of flavors we // can also get to through a converter. This is so that we can just walk the list @@ -602,10 +603,9 @@ nsTransferable :: FlavorsTransferableCanImport(nsISupportsArray **_retval) // intrinsic knowledge or output data converters. // NS_IMETHODIMP -nsTransferable :: FlavorsTransferableCanExport(nsISupportsArray **_retval) +nsTransferable::FlavorsTransferableCanExport(nsISupportsArray **_retval) { - if ( !_retval ) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); // Get the flavor list, and on to the end of it, append the list of flavors we // can also get to through a converter. This is so that we can just walk the list diff --git a/mozilla/widget/src/xpwidgets/nsTransferable.h b/mozilla/widget/src/xpwidgets/nsTransferable.h index f2b1c776422..9a8588edfb8 100644 --- a/mozilla/widget/src/xpwidgets/nsTransferable.h +++ b/mozilla/widget/src/xpwidgets/nsTransferable.h @@ -62,23 +62,12 @@ public: // nsISupports NS_DECL_ISUPPORTS - - // nsITransferable - NS_IMETHOD FlavorsTransferableCanExport(nsISupportsArray **_retval) ; - NS_IMETHOD GetTransferData(const char *aFlavor, nsISupports **aData, PRUint32 *aDataLen); - NS_IMETHOD GetAnyTransferData(char **aFlavor, nsISupports **aData, PRUint32 *aDataLen); - NS_IMETHOD IsLargeDataSet(PRBool *_retval); - NS_IMETHOD FlavorsTransferableCanImport(nsISupportsArray **_retval) ; - NS_IMETHOD SetTransferData(const char *aFlavor, nsISupports *aData, PRUint32 aDataLen); - NS_IMETHOD AddDataFlavor(const char *aDataFlavor) ; - NS_IMETHOD RemoveDataFlavor(const char *aDataFlavor) ; - NS_IMETHOD GetConverter(nsIFormatConverter * *aConverter); - NS_IMETHOD SetConverter(nsIFormatConverter * aConverter); + NS_DECL_NSITRANSFERABLE protected: // get flavors w/out converter - NS_IMETHOD GetTransferDataFlavors(nsISupportsArray** aDataFlavorList); + nsresult GetTransferDataFlavors(nsISupportsArray** aDataFlavorList); nsVoidArray * mDataArray; nsCOMPtr mFormatConv;