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:
pinkerton%netscape.com 2002-04-23 14:24:48 +00:00
Родитель bf83785982
Коммит 4008c80d05
7 изменённых файлов: 218 добавлений и 31 удалений

Просмотреть файл

@ -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|.