зеркало из https://github.com/mozilla/gecko-dev.git
add first stage of dragging images. advertise os-native image format to other applications. r=ccarlen/sr=alecf. bug# 138049
This commit is contained in:
Родитель
bf83785982
Коммит
4008c80d05
|
@ -83,6 +83,19 @@
|
|||
#include "nsUnicharUtils.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIImage.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIImageFrame.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "gfxIImageFrame.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
|
||||
|
||||
|
||||
NS_IMPL_ADDREF(nsContentAreaDragDrop)
|
||||
NS_IMPL_RELEASE(nsContentAreaDragDrop)
|
||||
|
@ -700,15 +713,15 @@ nsContentAreaDragDrop::GetEventDocument(nsIDOMEvent* inEvent, nsIDOMDocument** o
|
|||
//
|
||||
PRBool
|
||||
nsContentAreaDragDrop::BuildDragData(nsIDOMEvent* inMouseEvent, nsAString & outURLString, nsAString & outTitleString,
|
||||
nsAString & outHTMLString, PRBool* outIsAnchor)
|
||||
nsAString & outHTMLString, nsIImage** outImage, PRBool* outIsAnchor)
|
||||
{
|
||||
if ( !outIsAnchor )
|
||||
if ( !outIsAnchor || !outImage )
|
||||
return PR_FALSE;
|
||||
|
||||
outURLString.Truncate();
|
||||
outTitleString.Truncate();
|
||||
outHTMLString.Truncate();
|
||||
|
||||
*outImage = nsnull;
|
||||
*outIsAnchor = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMUIEvent> uiEvent(do_QueryInterface(inMouseEvent));
|
||||
|
@ -821,6 +834,9 @@ nsContentAreaDragDrop::BuildDragData(nsIDOMEvent* inMouseEvent, nsAString & outU
|
|||
GetAnchorURL(parentAnchor, urlString);
|
||||
CreateLinkText(urlString, htmlString, htmlString);
|
||||
}
|
||||
|
||||
// also grab the image data
|
||||
GetImageFromDOMNode(draggedNode, outImage);
|
||||
} // img
|
||||
else {
|
||||
nsCOMPtr<nsIDOMHTMLLinkElement> link(do_QueryInterface(draggedNode));
|
||||
|
@ -875,7 +891,8 @@ nsContentAreaDragDrop::BuildDragData(nsIDOMEvent* inMouseEvent, nsAString & outU
|
|||
//
|
||||
nsresult
|
||||
nsContentAreaDragDrop::CreateTransferable(const nsAString & inURLString, const nsAString & inTitleString,
|
||||
const nsAString & inHTMLString, PRBool inIsAnchor, nsITransferable** outTrans)
|
||||
const nsAString & inHTMLString, nsIImage* inImage, PRBool inIsAnchor,
|
||||
nsITransferable** outTrans)
|
||||
{
|
||||
if ( !outTrans )
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -892,7 +909,7 @@ nsContentAreaDragDrop::CreateTransferable(const nsAString & inURLString, const n
|
|||
nsAutoString dragData ( inURLString );
|
||||
dragData += NS_LITERAL_STRING("\n");
|
||||
dragData += inTitleString;
|
||||
nsCOMPtr<nsISupportsWString> urlPrimitive(do_CreateInstance("@mozilla.org/supports-wstring;1"));
|
||||
nsCOMPtr<nsISupportsWString> urlPrimitive(do_CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID));
|
||||
if ( !urlPrimitive )
|
||||
return NS_ERROR_FAILURE;
|
||||
urlPrimitive->SetData(dragData.get());
|
||||
|
@ -900,7 +917,7 @@ nsContentAreaDragDrop::CreateTransferable(const nsAString & inURLString, const n
|
|||
}
|
||||
|
||||
// add the full html
|
||||
nsCOMPtr<nsISupportsWString> htmlPrimitive(do_CreateInstance("@mozilla.org/supports-wstring;1"));
|
||||
nsCOMPtr<nsISupportsWString> htmlPrimitive(do_CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID));
|
||||
if ( !htmlPrimitive )
|
||||
return NS_ERROR_FAILURE;
|
||||
htmlPrimitive->SetData(PromiseFlatString(inHTMLString).get());
|
||||
|
@ -909,11 +926,22 @@ nsContentAreaDragDrop::CreateTransferable(const nsAString & inURLString, const n
|
|||
// add the plain (unicode) text. we use the url for text/unicode data if an anchor
|
||||
// is being dragged, rather than the title text of the link or the alt text for
|
||||
// an anchor image.
|
||||
nsCOMPtr<nsISupportsWString> textPrimitive(do_CreateInstance("@mozilla.org/supports-wstring;1"));
|
||||
nsCOMPtr<nsISupportsWString> textPrimitive(do_CreateInstance(NS_SUPPORTS_WSTRING_CONTRACTID));
|
||||
if ( !textPrimitive )
|
||||
return NS_ERROR_FAILURE;
|
||||
textPrimitive->SetData(PromiseFlatString(inIsAnchor ? inURLString : inTitleString).get());
|
||||
trans->SetTransferData(kUnicodeMime, textPrimitive, (inIsAnchor ? inURLString.Length() : inTitleString.Length()) * 2);
|
||||
trans->SetTransferData(kUnicodeMime, textPrimitive, (inIsAnchor ? inURLString.Length() : inTitleString.Length()) * 2);
|
||||
|
||||
// add image data, if present. For now, all we're going to do with this is turn it
|
||||
// into a native data flavor, so indicate that with a new flavor so as not to confuse
|
||||
// anyone who is really registered for image/gif or image/jpg.
|
||||
if ( inImage ) {
|
||||
nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID));
|
||||
if ( !ptrPrimitive )
|
||||
return NS_ERROR_FAILURE;
|
||||
ptrPrimitive->SetData(inImage);
|
||||
trans->SetTransferData(kNativeImageMime, ptrPrimitive, sizeof(nsIImage*));
|
||||
}
|
||||
|
||||
*outTrans = trans;
|
||||
NS_IF_ADDREF(*outTrans);
|
||||
|
@ -949,13 +977,14 @@ nsContentAreaDragDrop::DragGesture(nsIDOMEvent* inMouseEvent)
|
|||
|
||||
nsAutoString urlString, titleString, htmlString;
|
||||
PRBool isAnchor = PR_FALSE;
|
||||
nsCOMPtr<nsIImage> image;
|
||||
|
||||
// crawl the dom for the appropriate drag data depending on what was clicked
|
||||
PRBool startDrag = BuildDragData(inMouseEvent, urlString, titleString, htmlString, &isAnchor);
|
||||
PRBool startDrag = BuildDragData(inMouseEvent, urlString, titleString, htmlString, getter_AddRefs(image), &isAnchor);
|
||||
if ( startDrag ) {
|
||||
// build up the transferable with all this data.
|
||||
nsCOMPtr<nsITransferable> trans;
|
||||
nsresult rv = CreateTransferable(urlString, titleString, htmlString, isAnchor, getter_AddRefs(trans));
|
||||
nsresult rv = CreateTransferable(urlString, titleString, htmlString, image, isAnchor, getter_AddRefs(trans));
|
||||
if ( trans ) {
|
||||
// if the client has provided an override callback, let them manipulate
|
||||
// the flavors or drag data
|
||||
|
@ -990,3 +1019,104 @@ nsContentAreaDragDrop::HandleEvent(nsIDOMEvent *event)
|
|||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GetImageFrame
|
||||
//
|
||||
// Finds the image from from a content node
|
||||
//
|
||||
nsresult
|
||||
nsContentAreaDragDrop::GetImageFrame(nsIContent* aContent, nsIDocument *aDocument, nsIPresContext *aPresContext,
|
||||
nsIPresShell *aPresShell, nsIImageFrame** aImageFrame)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aImageFrame);
|
||||
*aImageFrame = nsnull;
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
if (aDocument) {
|
||||
// Make sure the presentation is up-to-date
|
||||
rv = aDocument->FlushPendingNotifications();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aContent && aDocument && aPresContext && aPresShell) {
|
||||
nsIFrame* frame = nsnull;
|
||||
rv = aPresShell->GetPrimaryFrameFor(aContent, &frame);
|
||||
if (NS_SUCCEEDED(rv) && frame) {
|
||||
nsCOMPtr<nsIAtom> type;
|
||||
frame->GetFrameType(getter_AddRefs(type));
|
||||
if (type.get() == nsLayoutAtoms::imageFrame) {
|
||||
nsIImageFrame* imageFrame;
|
||||
rv = frame->QueryInterface(NS_GET_IID(nsIImageFrame), (void**)&imageFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Should not happen - frame is not image frame even though type is nsLayoutAtoms::imageFrame");
|
||||
return rv;
|
||||
}
|
||||
*aImageFrame = imageFrame;
|
||||
}
|
||||
else
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
else
|
||||
rv = NS_OK;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GetImage
|
||||
//
|
||||
// Given a dom node that's an image, finds the nsIImage associated with it.
|
||||
//
|
||||
nsresult
|
||||
nsContentAreaDragDrop::GetImageFromDOMNode(nsIDOMNode* inNode, nsIImage**outImage)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(outImage);
|
||||
*outImage = nsnull;
|
||||
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(inNode));
|
||||
if ( content ) {
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
content->GetDocument(*getter_AddRefs(document));
|
||||
if ( document ) {
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
document->GetShellAt(0, getter_AddRefs(presShell));
|
||||
if ( presShell ) {
|
||||
nsCOMPtr<nsIPresContext> presContext;
|
||||
presShell->GetPresContext(getter_AddRefs(presContext));
|
||||
if (presContext) {
|
||||
nsCOMPtr<imgIContainer> imgContainer;
|
||||
|
||||
nsIImageFrame* imageFrame = nsnull;
|
||||
if ( NS_SUCCEEDED(GetImageFrame(content, document, presContext, presShell, &imageFrame)) && imageFrame ) {
|
||||
nsCOMPtr<imgIRequest> imgRequest;
|
||||
imageFrame->GetImageRequest(getter_AddRefs(imgRequest));
|
||||
if (imgRequest)
|
||||
imgRequest->GetImage(getter_AddRefs(imgContainer));
|
||||
}
|
||||
else {
|
||||
// We could try the background image, but we really don't want to be dragging
|
||||
// the bg image in any case.
|
||||
}
|
||||
|
||||
if (imgContainer) {
|
||||
nsCOMPtr<gfxIImageFrame> imgFrame;
|
||||
imgContainer->GetFrameAt(0, getter_AddRefs(imgFrame));
|
||||
if ( imgFrame ) {
|
||||
nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(imgFrame);
|
||||
if ( ir )
|
||||
rv = ir->GetInterface(NS_GET_IID(nsIImage), (void**)outImage); // will addreff
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,12 @@ class nsISelection;
|
|||
class nsITransferable;
|
||||
class nsIOverrideDragSource;
|
||||
class nsIOverrideDropSite;
|
||||
class nsIImage;
|
||||
class nsIPresShell;
|
||||
class nsIPresContext;
|
||||
class nsIImageFrame;
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
|
||||
|
||||
// {1f34bc80-1bc7-11d6-a384-d705dd0746fc}
|
||||
|
@ -99,11 +105,14 @@ private:
|
|||
static void GetNodeString(nsIDOMNode* inNode, nsAString & outNodeString);
|
||||
static void NormalizeSelection(nsIDOMNode* inBaseNode, nsISelection* inSelection);
|
||||
static void GetEventDocument(nsIDOMEvent* inEvent, nsIDOMDocument** outDocument);
|
||||
static nsresult GetImageFromDOMNode(nsIDOMNode* inNode, nsIImage** outImage);
|
||||
static nsresult GetImageFrame(nsIContent* aContent, nsIDocument *aDocument, nsIPresContext *aPresContext,
|
||||
nsIPresShell *aPresShell, nsIImageFrame** aImageFrame);
|
||||
|
||||
PRBool BuildDragData(nsIDOMEvent* inMouseEvent, nsAString & outURLString, nsAString & outTitleString,
|
||||
nsAString & outHTMLString, PRBool* outIsAnchor);
|
||||
nsAString & outHTMLString, nsIImage** outImage, PRBool* outIsAnchor);
|
||||
nsresult CreateTransferable(const nsAString & inURLString, const nsAString & inTitleString,
|
||||
const nsAString & inHTMLString, PRBool inIsAnchor,
|
||||
const nsAString & inHTMLString, nsIImage* inImage, PRBool inIsAnchor,
|
||||
nsITransferable** outTrans);
|
||||
void ExtractURLFromData(const nsACString & inFlavor, nsISupports* inDataWrapper, PRUint32 inDataLen,
|
||||
nsAString & outURL);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#define kGIFImageMime "image/gif"
|
||||
#define kFileMime "application/x-moz-file"
|
||||
#define kURLMime "text/x-moz-url"
|
||||
#define kNativeImageMime "application/x-moz-nativeimage"
|
||||
|
||||
%}
|
||||
|
||||
|
|
|
@ -77,6 +77,8 @@
|
|||
|
||||
#include "nsIXULContent.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIImageMac.h"
|
||||
#include "nsIImage.h"
|
||||
|
||||
|
||||
// we need our own stuff for MacOS because of nsIDragSessionMac.
|
||||
|
@ -673,7 +675,8 @@ nsDragService :: DragSendDataProc ( FlavorType inFlavor, void* inRefCon, ItemRef
|
|||
retVal = ::SetDragItemFlavorData ( inDragRef, inItemRef, inFlavor, data, dataSize, 0 );
|
||||
NS_ASSERTION ( retVal == noErr, "SDIFD failed in DragSendDataProc" );
|
||||
}
|
||||
nsMemory::Free ( data );
|
||||
if ( data )
|
||||
nsMemory::Free ( data );
|
||||
} // if valid refcon
|
||||
|
||||
return retVal;
|
||||
|
@ -729,22 +732,47 @@ nsDragService :: GetDataForFlavor ( nsISupportsArray* inDragItems, DragReference
|
|||
*outDataSize = 0;
|
||||
nsCOMPtr<nsISupports> data;
|
||||
if ( NS_SUCCEEDED(item->GetTransferData(actualFlavor, getter_AddRefs(data), outDataSize)) ) {
|
||||
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;
|
||||
nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText ( castedUnicode, *outDataSize / 2, &plainTextData, &plainTextLen );
|
||||
if ( *outData ) {
|
||||
nsMemory::Free(*outData);
|
||||
*outData = plainTextData;
|
||||
*outDataSize = plainTextLen;
|
||||
if ( strcmp(actualFlavor, kNativeImageMime) == 0 ) {
|
||||
// unwrap the image from its nsISupportsPrimitive wrapper
|
||||
nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(data));
|
||||
nsCOMPtr<nsIImage> 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<nsIImageMac> 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
|
||||
retVal = cantGetFlavorErr;
|
||||
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;
|
||||
nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText ( castedUnicode, *outDataSize / 2, &plainTextData, &plainTextLen );
|
||||
if ( *outData ) {
|
||||
nsMemory::Free(*outData);
|
||||
*outData = plainTextData;
|
||||
*outDataSize = plainTextLen;
|
||||
}
|
||||
else
|
||||
retVal = cantGetFlavorErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -95,18 +95,22 @@ nsMimeMapperMac :: MapMimeTypeToMacOSType ( const char* aMimeStr, PRBool inAddIf
|
|||
// pick them up by special casing MapMacsOSTypeToMimeType(). This means that
|
||||
// the low two bytes of the generated flavor can be used as an index into the list.
|
||||
if ( !format ) {
|
||||
if ( PL_strcmp(aMimeStr, kTextMime) == 0 )
|
||||
if ( PL_strcmp(aMimeStr, kUnicodeMime) == 0 )
|
||||
format = kScrapFlavorTypeUnicode;
|
||||
else if ( PL_strcmp(aMimeStr, kTextMime) == 0 )
|
||||
format = kScrapFlavorTypeText;
|
||||
else if ( PL_strcmp(aMimeStr, kFileMime) == 0 )
|
||||
format = flavorTypeHFS;
|
||||
else if ( PL_strcmp(aMimeStr, kNativeImageMime) == 0 )
|
||||
format = kScrapFlavorTypePicture;
|
||||
#if NOT_YET
|
||||
else if ( PL_strcmp(aMimeStr, kPNGImageMime) == 0 )
|
||||
format = kScrapFlavorTypePicture;
|
||||
else if ( PL_strcmp(aMimeStr, kJPEGImageMime) == 0 )
|
||||
format = kScrapFlavorTypePicture;
|
||||
else if ( PL_strcmp(aMimeStr, kGIFImageMime) == 0 )
|
||||
format = kScrapFlavorTypePicture;
|
||||
else if ( PL_strcmp(aMimeStr, kUnicodeMime) == 0 )
|
||||
format = kScrapFlavorTypeUnicode;
|
||||
#endif
|
||||
|
||||
else if ( inAddIfNotPresent ) {
|
||||
// create the flavor based on the unique id in the lower two bytes and 'MZ' in the
|
||||
|
@ -143,6 +147,10 @@ nsMimeMapperMac :: MapMacOSTypeToMimeType ( ResType inMacType, nsCAutoString & o
|
|||
case kScrapFlavorTypeUnicode: outMimeStr = kUnicodeMime; break;
|
||||
case flavorTypeHFS: outMimeStr = kFileMime; break;
|
||||
|
||||
// if someone gives us PICT (or we could have put it there), use
|
||||
// the native image mime type.
|
||||
case kScrapFlavorTypePicture: outMimeStr = kNativeImageMime; break;
|
||||
|
||||
// This flavor is the old 4.x Composer flavor for HTML. The actual data is a binary
|
||||
// data structure which we do NOT want to deal with in any way shape or form. I am
|
||||
// only including this flavor here so we don't accidentally use it ourselves and
|
||||
|
|
|
@ -199,7 +199,7 @@ nsresult nsClipboard::SetupNativeDataObject(nsITransferable * aTransferable, IDa
|
|||
#endif
|
||||
}
|
||||
else if ( strcmp(flavorStr, kPNGImageMime) == 0 || strcmp(flavorStr, kJPEGImageMime) == 0 ||
|
||||
strcmp(flavorStr, kGIFImageMime) == 0 ) {
|
||||
strcmp(flavorStr, kGIFImageMime) == 0 || strcmp(flavorStr, kNativeImageMime) == 0 ) {
|
||||
// if we're an image, register the native bitmap flavor
|
||||
FORMATETC imageFE;
|
||||
SET_FORMATETC(imageFE, CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL)
|
||||
|
|
|
@ -382,10 +382,21 @@ nsDataObj :: GetDib ( const nsACString& inFlavor, FORMATETC &, STGMEDIUM & aSTG
|
|||
PRNTDEBUG("nsDataObj::GetDib\n");
|
||||
ULONG result = E_FAIL;
|
||||
|
||||
|
||||
PRUint32 len = 0;
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
mTransferable->GetTransferData(PromiseFlatCString(inFlavor).get(), 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 ) {
|
||||
// use a the helper class to build up a bitmap. We now own the bits,
|
||||
// and pass them back to the OS in |aSTG|.
|
||||
|
|
Загрузка…
Ссылка в новой задаче