зеркало из https://github.com/mozilla/gecko-dev.git
Bug 499008, part 4, convert editor drop handling to use datatransfers instead of the drag service, r=ehsan
This commit is contained in:
Родитель
11d52d2eeb
Коммит
8acdaab321
|
@ -61,8 +61,6 @@
|
|||
// Drag & Drop, Clipboard
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIDragService.h"
|
||||
#include "nsIDragSession.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIDOMRange.h"
|
||||
|
@ -700,6 +698,10 @@ nsEditorEventListener::DragOver(nsIDOMDragEvent* aDragEvent)
|
|||
}
|
||||
else
|
||||
{
|
||||
// This is needed when dropping on an input, to prevent the editor for
|
||||
// the editable parent from receiving the event.
|
||||
aDragEvent->StopPropagation();
|
||||
|
||||
if (mCaret)
|
||||
{
|
||||
mCaret->EraseCaret();
|
||||
|
@ -771,8 +773,6 @@ nsEditorEventListener::Drop(nsIDOMDragEvent* aMouseEvent)
|
|||
|
||||
aMouseEvent->StopPropagation();
|
||||
aMouseEvent->PreventDefault();
|
||||
// Beware! This may flush notifications via synchronous
|
||||
// ScrollSelectionIntoView.
|
||||
return mEditor->InsertFromDrop(aMouseEvent);
|
||||
}
|
||||
|
||||
|
|
|
@ -257,7 +257,6 @@ class nsEditorUtils
|
|||
};
|
||||
|
||||
|
||||
class nsIDragSession;
|
||||
class nsITransferable;
|
||||
class nsIDOMEvent;
|
||||
class nsISimpleEnumerator;
|
||||
|
|
|
@ -64,6 +64,8 @@
|
|||
#include "nsIContent.h"
|
||||
#include "nsIContentIterator.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsIDOMDOMStringList.h"
|
||||
#include "nsIDOMDragEvent.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIURL.h"
|
||||
|
@ -1204,6 +1206,116 @@ nsHTMLEditor::ParseCFHTML(nsCString & aCfhtml, PRUnichar **aStuffToPaste, PRUnic
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool nsHTMLEditor::IsSafeToInsertData(nsIDOMDocument* aSourceDoc)
|
||||
{
|
||||
// Try to determine whether we should use a sanitizing fragment sink
|
||||
bool isSafe = false;
|
||||
nsCOMPtr<nsIDOMDocument> destdomdoc;
|
||||
GetDocument(getter_AddRefs(destdomdoc));
|
||||
|
||||
nsCOMPtr<nsIDocument> destdoc = do_QueryInterface(destdomdoc);
|
||||
NS_ASSERTION(destdoc, "Where is our destination doc?");
|
||||
nsCOMPtr<nsISupports> container = destdoc->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> dsti(do_QueryInterface(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
||||
if (dsti)
|
||||
dsti->GetRootTreeItem(getter_AddRefs(root));
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
|
||||
PRUint32 appType;
|
||||
if (docShell && NS_SUCCEEDED(docShell->GetAppType(&appType)))
|
||||
isSafe = appType == nsIDocShell::APP_TYPE_EDITOR;
|
||||
if (!isSafe && aSourceDoc) {
|
||||
nsCOMPtr<nsIDocument> srcdoc = do_QueryInterface(aSourceDoc);
|
||||
NS_ASSERTION(srcdoc, "Where is our source doc?");
|
||||
|
||||
nsIPrincipal* srcPrincipal = srcdoc->NodePrincipal();
|
||||
nsIPrincipal* destPrincipal = destdoc->NodePrincipal();
|
||||
NS_ASSERTION(srcPrincipal && destPrincipal, "How come we don't have a principal?");
|
||||
srcPrincipal->Subsumes(destPrincipal, &isSafe);
|
||||
}
|
||||
|
||||
return isSafe;
|
||||
}
|
||||
|
||||
nsresult nsHTMLEditor::InsertObject(const char* aType, nsISupports* aObject, bool aIsSafe,
|
||||
nsIDOMDocument *aSourceDoc,
|
||||
nsIDOMNode *aDestinationNode,
|
||||
PRInt32 aDestOffset,
|
||||
bool aDoDeleteSelection)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
const char* type = aType;
|
||||
|
||||
// Check to see if we can insert an image file
|
||||
bool insertAsImage = false;
|
||||
nsCOMPtr<nsIURI> fileURI;
|
||||
if (0 == nsCRT::strcmp(type, kFileMime))
|
||||
{
|
||||
nsCOMPtr<nsIFile> fileObj(do_QueryInterface(aObject));
|
||||
if (fileObj)
|
||||
{
|
||||
rv = NS_NewFileURI(getter_AddRefs(fileURI), fileObj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
|
||||
NS_ENSURE_TRUE(mime, NS_ERROR_FAILURE);
|
||||
nsCAutoString contentType;
|
||||
rv = mime->GetTypeFromFile(fileObj, contentType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Accept any image type fed to us
|
||||
if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("image/"))) {
|
||||
insertAsImage = true;
|
||||
type = contentType.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == nsCRT::strcmp(type, kJPEGImageMime) ||
|
||||
0 == nsCRT::strcmp(type, kPNGImageMime) ||
|
||||
0 == nsCRT::strcmp(type, kGIFImageMime) ||
|
||||
insertAsImage)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> imageStream;
|
||||
if (insertAsImage) {
|
||||
NS_ASSERTION(fileURI, "The file URI should be retrieved earlier");
|
||||
rv = NS_OpenURI(getter_AddRefs(imageStream), fileURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
imageStream = do_QueryInterface(aObject);
|
||||
NS_ENSURE_TRUE(imageStream, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
nsCString imageData;
|
||||
rv = NS_ConsumeStream(imageStream, PR_UINT32_MAX, imageData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = imageStream->Close();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
char * base64 = PL_Base64Encode(imageData.get(), imageData.Length(), nsnull);
|
||||
NS_ENSURE_TRUE(base64, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsAutoString stuffToPaste;
|
||||
stuffToPaste.AssignLiteral("<IMG src=\"data:");
|
||||
AppendUTF8toUTF16(aType, stuffToPaste);
|
||||
stuffToPaste.AppendLiteral(";base64,");
|
||||
AppendUTF8toUTF16(base64, stuffToPaste);
|
||||
stuffToPaste.AppendLiteral("\" alt=\"\" >");
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
rv = DoInsertHTMLWithContext(stuffToPaste, EmptyString(), EmptyString(),
|
||||
NS_LITERAL_STRING(kFileMime),
|
||||
aSourceDoc,
|
||||
aDestinationNode, aDestOffset,
|
||||
aDoDeleteSelection,
|
||||
aIsSafe);
|
||||
PR_Free(base64);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable,
|
||||
nsIDOMDocument *aSourceDoc,
|
||||
const nsAString & aContextStr,
|
||||
|
@ -1226,59 +1338,16 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable
|
|||
printf("Got flavor [%s]\n", bestFlavor.get());
|
||||
#endif
|
||||
|
||||
// Try to determine whether we should use a sanitizing fragment sink
|
||||
bool isSafe = false;
|
||||
nsCOMPtr<nsIDOMDocument> destdomdoc;
|
||||
rv = GetDocument(getter_AddRefs(destdomdoc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDocument> destdoc = do_QueryInterface(destdomdoc);
|
||||
NS_ASSERTION(destdoc, "Where is our destination doc?");
|
||||
nsCOMPtr<nsISupports> container = destdoc->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> dsti(do_QueryInterface(container));
|
||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
||||
if (dsti)
|
||||
dsti->GetRootTreeItem(getter_AddRefs(root));
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
|
||||
PRUint32 appType;
|
||||
if (docShell && NS_SUCCEEDED(docShell->GetAppType(&appType)))
|
||||
isSafe = appType == nsIDocShell::APP_TYPE_EDITOR;
|
||||
if (!isSafe && aSourceDoc) {
|
||||
nsCOMPtr<nsIDocument> srcdoc = do_QueryInterface(aSourceDoc);
|
||||
NS_ASSERTION(srcdoc, "Where is our source doc?");
|
||||
bool isSafe = IsSafeToInsertData(aSourceDoc);
|
||||
|
||||
nsIPrincipal* srcPrincipal = srcdoc->NodePrincipal();
|
||||
nsIPrincipal* destPrincipal = destdoc->NodePrincipal();
|
||||
NS_ASSERTION(srcPrincipal && destPrincipal, "How come we don't have a principal?");
|
||||
rv = srcPrincipal->Subsumes(destPrincipal, &isSafe);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (0 == nsCRT::strcmp(bestFlavor, kFileMime) ||
|
||||
0 == nsCRT::strcmp(bestFlavor, kJPEGImageMime) ||
|
||||
0 == nsCRT::strcmp(bestFlavor, kPNGImageMime) ||
|
||||
0 == nsCRT::strcmp(bestFlavor, kGIFImageMime)) {
|
||||
rv = InsertObject(bestFlavor, genericDataObj, isSafe,
|
||||
aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
|
||||
}
|
||||
|
||||
// Check to see if we can insert an image file
|
||||
bool insertAsImage = false;
|
||||
nsCOMPtr<nsIURI> fileURI;
|
||||
if (0 == nsCRT::strcmp(bestFlavor, kFileMime))
|
||||
{
|
||||
nsCOMPtr<nsIFile> fileObj(do_QueryInterface(genericDataObj));
|
||||
if (fileObj && len > 0)
|
||||
{
|
||||
rv = NS_NewFileURI(getter_AddRefs(fileURI), fileObj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
|
||||
NS_ENSURE_TRUE(mime, NS_ERROR_FAILURE);
|
||||
nsCAutoString contentType;
|
||||
rv = mime->GetTypeFromFile(fileObj, contentType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Accept any image type fed to us
|
||||
if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("image/"))) {
|
||||
insertAsImage = true;
|
||||
bestFlavor = contentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == nsCRT::strcmp(bestFlavor, kNativeHTMLMime))
|
||||
else if (0 == nsCRT::strcmp(bestFlavor, kNativeHTMLMime))
|
||||
{
|
||||
// note cf_html uses utf8, hence use length = len, not len/2 as in flavors below
|
||||
nsCOMPtr<nsISupportsCString> textDataObj(do_QueryInterface(genericDataObj));
|
||||
|
@ -1302,8 +1371,9 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (0 == nsCRT::strcmp(bestFlavor, kHTMLMime))
|
||||
{
|
||||
else if (0 == nsCRT::strcmp(bestFlavor, kHTMLMime) ||
|
||||
0 == nsCRT::strcmp(bestFlavor, kUnicodeMime) ||
|
||||
0 == nsCRT::strcmp(bestFlavor, kMozTextInternal)) {
|
||||
nsCOMPtr<nsISupportsString> textDataObj(do_QueryInterface(genericDataObj));
|
||||
if (textDataObj && len > 0)
|
||||
{
|
||||
|
@ -1311,113 +1381,148 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable
|
|||
textDataObj->GetData(text);
|
||||
NS_ASSERTION(text.Length() <= (len/2), "Invalid length!");
|
||||
stuffToPaste.Assign(text.get(), len / 2);
|
||||
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
rv = DoInsertHTMLWithContext(stuffToPaste,
|
||||
aContextStr, aInfoStr, flavor,
|
||||
aSourceDoc,
|
||||
aDestinationNode, aDestOffset,
|
||||
aDoDeleteSelection,
|
||||
isSafe);
|
||||
if (0 == nsCRT::strcmp(bestFlavor, kHTMLMime)) {
|
||||
rv = DoInsertHTMLWithContext(stuffToPaste,
|
||||
aContextStr, aInfoStr, flavor,
|
||||
aSourceDoc,
|
||||
aDestinationNode, aDestOffset,
|
||||
aDoDeleteSelection,
|
||||
isSafe);
|
||||
} else {
|
||||
rv = InsertTextAt(stuffToPaste, aDestinationNode, aDestOffset, aDoDeleteSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (0 == nsCRT::strcmp(bestFlavor, kUnicodeMime) ||
|
||||
0 == nsCRT::strcmp(bestFlavor, kMozTextInternal))
|
||||
{
|
||||
nsCOMPtr<nsISupportsString> textDataObj(do_QueryInterface(genericDataObj));
|
||||
if (textDataObj && len > 0)
|
||||
{
|
||||
nsAutoString text;
|
||||
textDataObj->GetData(text);
|
||||
NS_ASSERTION(text.Length() <= (len/2), "Invalid length!");
|
||||
stuffToPaste.Assign(text.get(), len / 2);
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
// need to provide a hook from this point
|
||||
rv = InsertTextAt(stuffToPaste, aDestinationNode, aDestOffset, aDoDeleteSelection);
|
||||
}
|
||||
}
|
||||
else if (0 == nsCRT::strcmp(bestFlavor, kJPEGImageMime) ||
|
||||
0 == nsCRT::strcmp(bestFlavor, kPNGImageMime) ||
|
||||
0 == nsCRT::strcmp(bestFlavor, kGIFImageMime) ||
|
||||
insertAsImage)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> imageStream;
|
||||
if (insertAsImage) {
|
||||
NS_ASSERTION(fileURI, "The file URI should be retrieved earlier");
|
||||
rv = NS_OpenURI(getter_AddRefs(imageStream), fileURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
imageStream = do_QueryInterface(genericDataObj);
|
||||
NS_ENSURE_TRUE(imageStream, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
nsCString imageData;
|
||||
rv = NS_ConsumeStream(imageStream, PR_UINT32_MAX, imageData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = imageStream->Close();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
char * base64 = PL_Base64Encode(imageData.get(), imageData.Length(), nsnull);
|
||||
NS_ENSURE_TRUE(base64, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
stuffToPaste.AssignLiteral("<IMG src=\"data:");
|
||||
AppendUTF8toUTF16(bestFlavor, stuffToPaste);
|
||||
stuffToPaste.AppendLiteral(";base64,");
|
||||
AppendUTF8toUTF16(base64, stuffToPaste);
|
||||
stuffToPaste.AppendLiteral("\" alt=\"\" >");
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
rv = DoInsertHTMLWithContext(stuffToPaste, EmptyString(), EmptyString(),
|
||||
NS_LITERAL_STRING(kFileMime),
|
||||
aSourceDoc,
|
||||
aDestinationNode, aDestOffset,
|
||||
aDoDeleteSelection,
|
||||
isSafe);
|
||||
PR_Free(base64);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to scroll the selection into view if the paste/drop succeeded
|
||||
|
||||
// After ScrollSelectionIntoView(), the pending notifications might be
|
||||
// flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
|
||||
// Try to scroll the selection into view if the paste succeeded
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ScrollSelectionIntoView(false);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
GetStringFromDataTransfer(nsIDOMDataTransfer *aDataTransfer, const nsAString& aType,
|
||||
PRInt32 aIndex, nsAString& aOutputString)
|
||||
{
|
||||
nsCOMPtr<nsIVariant> variant;
|
||||
aDataTransfer->MozGetDataAt(aType, aIndex, getter_AddRefs(variant));
|
||||
if (variant)
|
||||
variant->GetAsAString(aOutputString);
|
||||
}
|
||||
|
||||
nsresult nsHTMLEditor::InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
|
||||
PRInt32 aIndex,
|
||||
nsIDOMDocument *aSourceDoc,
|
||||
const nsAString & aContextStr,
|
||||
const nsAString & aInfoStr,
|
||||
nsIDOMNode *aDestinationNode,
|
||||
PRInt32 aDestOffset,
|
||||
bool aDoDeleteSelection)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMDOMStringList> types;
|
||||
aDataTransfer->MozTypesAt(aIndex, getter_AddRefs(types));
|
||||
|
||||
bool hasPrivateHTMLFlavor;
|
||||
types->Contains(NS_LITERAL_STRING(kHTMLContext), &hasPrivateHTMLFlavor);
|
||||
|
||||
bool isText = IsPlaintextEditor();
|
||||
bool isSafe = IsSafeToInsertData(aSourceDoc);
|
||||
|
||||
PRUint32 length;
|
||||
types->GetLength(&length);
|
||||
for (PRUint32 t = 0; t < length; t++) {
|
||||
nsAutoString type;
|
||||
types->Item(t, type);
|
||||
|
||||
if (!isText) {
|
||||
if (type.EqualsLiteral(kFileMime) ||
|
||||
type.EqualsLiteral(kJPEGImageMime) ||
|
||||
type.EqualsLiteral(kPNGImageMime) ||
|
||||
type.EqualsLiteral(kGIFImageMime)) {
|
||||
nsCOMPtr<nsIVariant> variant;
|
||||
aDataTransfer->MozGetDataAt(type, aIndex, getter_AddRefs(variant));
|
||||
if (variant) {
|
||||
nsCOMPtr<nsISupports> object;
|
||||
variant->GetAsISupports(getter_AddRefs(object));
|
||||
rv = InsertObject(NS_ConvertUTF16toUTF8(type).get(), object, isSafe,
|
||||
aSourceDoc, aDestinationNode, aDestOffset, aDoDeleteSelection);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
else if (!hasPrivateHTMLFlavor && type.EqualsLiteral(kNativeHTMLMime)) {
|
||||
nsAutoString text;
|
||||
GetStringFromDataTransfer(aDataTransfer, NS_LITERAL_STRING(kNativeHTMLMime), aIndex, text);
|
||||
NS_ConvertUTF16toUTF8 cfhtml(text);
|
||||
|
||||
nsXPIDLString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
|
||||
|
||||
rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
|
||||
if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty())
|
||||
{
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
rv = DoInsertHTMLWithContext(cffragment,
|
||||
cfcontext, cfselection, type,
|
||||
aSourceDoc,
|
||||
aDestinationNode, aDestOffset,
|
||||
aDoDeleteSelection,
|
||||
isSafe);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
else if (type.EqualsLiteral(kHTMLMime)) {
|
||||
nsAutoString text;
|
||||
GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
|
||||
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
if (type.EqualsLiteral(kHTMLMime)) {
|
||||
rv = DoInsertHTMLWithContext(text,
|
||||
aContextStr, aInfoStr, type,
|
||||
aSourceDoc,
|
||||
aDestinationNode, aDestOffset,
|
||||
aDoDeleteSelection,
|
||||
isSafe);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type.EqualsLiteral(kTextMime) ||
|
||||
type.EqualsLiteral(kMozTextInternal)) {
|
||||
nsAutoString text;
|
||||
GetStringFromDataTransfer(aDataTransfer, type, aIndex, text);
|
||||
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
rv = InsertTextAt(text, aDestinationNode, aDestOffset, aDoDeleteSelection);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
||||
{
|
||||
ForceCompositionEnd();
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDragService> dragService =
|
||||
do_GetService("@mozilla.org/widget/dragservice;1", &rv);
|
||||
|
||||
nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aDropEvent));
|
||||
NS_ENSURE_TRUE(dragEvent, NS_OK);
|
||||
|
||||
nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
|
||||
nsresult rv = dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDragSession> dragSession;
|
||||
dragService->GetCurrentSession(getter_AddRefs(dragSession));
|
||||
NS_ENSURE_TRUE(dragSession, NS_OK);
|
||||
|
||||
// transferable hooks here
|
||||
nsCOMPtr<nsIDOMDocument> domdoc;
|
||||
GetDocument(getter_AddRefs(domdoc));
|
||||
|
||||
// find out if we have our internal html flavor on the clipboard. We don't want to mess
|
||||
// around with cfhtml if we do.
|
||||
bool bHavePrivateHTMLFlavor = false;
|
||||
rv = dragSession->IsDataFlavorSupported(kHTMLContext, &bHavePrivateHTMLFlavor);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the nsITransferable interface for getting the data from the drop
|
||||
nsCOMPtr<nsITransferable> trans;
|
||||
rv = PrepareHTMLTransferable(getter_AddRefs(trans), bHavePrivateHTMLFlavor);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(trans, NS_OK); // NS_ERROR_FAILURE; SHOULD WE FAIL?
|
||||
|
||||
PRUint32 numItems = 0;
|
||||
rv = dragSession->GetNumDropItems(&numItems);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PRUint32 numItems = 0;
|
||||
dataTransfer->GetMozItemCount(&numItems);
|
||||
|
||||
// Combine any deletion and drop insertion into one transaction
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
|
@ -1427,80 +1532,25 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
|||
nsCOMPtr<nsIDOMNode> newSelectionParent;
|
||||
PRInt32 newSelectionOffset = 0;
|
||||
|
||||
// Source doc is null if source is *not* the current editor document
|
||||
nsCOMPtr<nsIDOMNode> sourceNode;
|
||||
dataTransfer->GetMozSourceNode(getter_AddRefs(sourceNode));
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> srcdomdoc;
|
||||
rv = dragSession->GetSourceDocument(getter_AddRefs(srcdomdoc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (sourceNode) {
|
||||
sourceNode->GetOwnerDocument(getter_AddRefs(srcdomdoc));
|
||||
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
PRUint32 i;
|
||||
bool doPlaceCaret = true;
|
||||
for (i = 0; i < numItems; ++i)
|
||||
{
|
||||
rv = dragSession->GetData(trans, i);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(trans, NS_OK); // NS_ERROR_FAILURE; Should we fail?
|
||||
|
||||
// get additional html copy hints, if present
|
||||
nsAutoString contextStr, infoStr;
|
||||
nsCOMPtr<nsISupports> contextDataObj, infoDataObj;
|
||||
PRUint32 contextLen, infoLen;
|
||||
nsCOMPtr<nsISupportsString> textDataObj;
|
||||
|
||||
nsCOMPtr<nsITransferable> contextTrans =
|
||||
do_CreateInstance("@mozilla.org/widget/transferable;1");
|
||||
NS_ENSURE_TRUE(contextTrans, NS_ERROR_NULL_POINTER);
|
||||
contextTrans->AddDataFlavor(kHTMLContext);
|
||||
dragSession->GetData(contextTrans, i);
|
||||
contextTrans->GetTransferData(kHTMLContext, getter_AddRefs(contextDataObj), &contextLen);
|
||||
|
||||
nsCOMPtr<nsITransferable> infoTrans =
|
||||
do_CreateInstance("@mozilla.org/widget/transferable;1");
|
||||
NS_ENSURE_TRUE(infoTrans, NS_ERROR_NULL_POINTER);
|
||||
infoTrans->AddDataFlavor(kHTMLInfo);
|
||||
dragSession->GetData(infoTrans, i);
|
||||
infoTrans->GetTransferData(kHTMLInfo, getter_AddRefs(infoDataObj), &infoLen);
|
||||
|
||||
if (contextDataObj)
|
||||
{
|
||||
nsAutoString text;
|
||||
textDataObj = do_QueryInterface(contextDataObj);
|
||||
textDataObj->GetData(text);
|
||||
NS_ASSERTION(text.Length() <= (contextLen/2), "Invalid length!");
|
||||
contextStr.Assign(text.get(), contextLen / 2);
|
||||
}
|
||||
|
||||
if (infoDataObj)
|
||||
{
|
||||
nsAutoString text;
|
||||
textDataObj = do_QueryInterface(infoDataObj);
|
||||
textDataObj->GetData(text);
|
||||
NS_ASSERTION(text.Length() <= (infoLen/2), "Invalid length!");
|
||||
infoStr.Assign(text.get(), infoLen / 2);
|
||||
}
|
||||
nsAutoString contextString, infoString;
|
||||
GetStringFromDataTransfer(dataTransfer, NS_LITERAL_STRING(kHTMLContext), i, contextString);
|
||||
GetStringFromDataTransfer(dataTransfer, NS_LITERAL_STRING(kHTMLInfo), i, infoString);
|
||||
|
||||
if (doPlaceCaret)
|
||||
{
|
||||
// check if the user pressed the key to force a copy rather than a move
|
||||
// if we run into problems here, we'll just assume the user doesn't want a copy
|
||||
bool userWantsCopy = false;
|
||||
|
||||
nsCOMPtr<nsIDOMUIEvent> uiEvent = do_QueryInterface(aDropEvent);
|
||||
NS_ENSURE_TRUE(uiEvent, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aDropEvent);
|
||||
if (mouseEvent) {
|
||||
#if defined(XP_MACOSX)
|
||||
mouseEvent->GetAltKey(&userWantsCopy);
|
||||
#else
|
||||
mouseEvent->GetCtrlKey(&userWantsCopy);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Current doc is destination
|
||||
nsCOMPtr<nsIDOMDocument> destdomdoc;
|
||||
rv = GetDocument(getter_AddRefs(destdomdoc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
rv = GetSelection(getter_AddRefs(selection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1509,7 +1559,10 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
|||
bool isCollapsed;
|
||||
rv = selection->GetIsCollapsed(&isCollapsed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
||||
nsCOMPtr<nsIDOMUIEvent> uiEvent = do_QueryInterface(aDropEvent);
|
||||
NS_ENSURE_TRUE(uiEvent, NS_ERROR_FAILURE);
|
||||
|
||||
// Parent and offset under the mouse cursor
|
||||
rv = uiEvent->GetRangeParent(getter_AddRefs(newSelectionParent));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1565,6 +1618,11 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
|||
if(cursorIsInSelection)
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> destdomdoc;
|
||||
GetDocument(getter_AddRefs(destdomdoc));
|
||||
NS_ENSURE_TRUE(destdomdoc, NS_ERROR_FAILURE);
|
||||
|
||||
if (cursorIsInSelection)
|
||||
{
|
||||
// Dragging within same doc can't drop on itself -- leave!
|
||||
|
@ -1583,7 +1641,9 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
|||
if (srcdomdoc == destdomdoc)
|
||||
{
|
||||
// Within the same doc: delete if user doesn't want to copy
|
||||
deleteSelection = !userWantsCopy;
|
||||
PRUint32 dropEffect;
|
||||
dataTransfer->GetDropEffectInt(&dropEffect);
|
||||
deleteSelection = !(dropEffect & nsIDragService::DRAGDROP_ACTION_COPY);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1597,17 +1657,14 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
|||
doPlaceCaret = false;
|
||||
}
|
||||
|
||||
// handle transferable hooks
|
||||
if (!nsEditorHookUtils::DoInsertionHook(domdoc, aDropEvent, trans))
|
||||
return NS_OK;
|
||||
|
||||
// Beware! This may flush notifications via synchronous
|
||||
// ScrollSelectionIntoView.
|
||||
rv = InsertFromTransferable(trans, srcdomdoc, contextStr, infoStr,
|
||||
newSelectionParent,
|
||||
rv = InsertFromDataTransfer(dataTransfer, i, srcdomdoc,
|
||||
contextString, infoString, newSelectionParent,
|
||||
newSelectionOffset, deleteSelection);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ScrollSelectionIntoView(false);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1701,8 +1758,6 @@ NS_IMETHODIMP nsHTMLEditor::Paste(PRInt32 aSelectionType)
|
|||
if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, trans))
|
||||
return NS_OK;
|
||||
|
||||
// Beware! This may flush notifications via synchronous
|
||||
// ScrollSelectionIntoView.
|
||||
rv = InsertFromTransferable(trans, nsnull, contextStr, infoStr,
|
||||
nsnull, 0, true);
|
||||
}
|
||||
|
@ -1722,8 +1777,6 @@ NS_IMETHODIMP nsHTMLEditor::PasteTransferable(nsITransferable *aTransferable)
|
|||
if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, aTransferable))
|
||||
return NS_OK;
|
||||
|
||||
// Beware! This may flush notifications via synchronous
|
||||
// ScrollSelectionIntoView.
|
||||
nsAutoString contextStr, infoStr;
|
||||
return InsertFromTransferable(aTransferable, nsnull, contextStr, infoStr,
|
||||
nsnull, 0, true);
|
||||
|
@ -1751,8 +1804,6 @@ NS_IMETHODIMP nsHTMLEditor::PasteNoFormatting(PRInt32 aSelectionType)
|
|||
if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable())
|
||||
{
|
||||
const nsAFlatString& empty = EmptyString();
|
||||
// Beware! This may flush notifications via synchronous
|
||||
// ScrollSelectionIntoView.
|
||||
rv = InsertFromTransferable(trans, nsnull, empty, empty, nsnull, 0,
|
||||
true);
|
||||
}
|
||||
|
|
|
@ -572,6 +572,16 @@ protected:
|
|||
NS_IMETHOD InsertAsPlaintextQuotation(const nsAString & aQuotedText,
|
||||
bool aAddCites,
|
||||
nsIDOMNode **aNodeInserted);
|
||||
// Return true if the data is safe to insert as the source and destination
|
||||
// principals match, or we are in a editor context where this doesn't matter.
|
||||
// Otherwise, the data must be sanitized first.
|
||||
bool IsSafeToInsertData(nsIDOMDocument* aSourceDoc);
|
||||
|
||||
nsresult InsertObject(const char* aType, nsISupports* aObject, bool aIsSafe,
|
||||
nsIDOMDocument *aSourceDoc,
|
||||
nsIDOMNode *aDestinationNode,
|
||||
PRInt32 aDestOffset,
|
||||
bool aDoDeleteSelection);
|
||||
|
||||
// factored methods for handling insertion of data from transferables (drag&drop or clipboard)
|
||||
NS_IMETHOD PrepareTransferable(nsITransferable **transferable);
|
||||
|
@ -583,6 +593,14 @@ protected:
|
|||
nsIDOMNode *aDestinationNode,
|
||||
PRInt32 aDestinationOffset,
|
||||
bool aDoDeleteSelection);
|
||||
nsresult InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
|
||||
PRInt32 aIndex,
|
||||
nsIDOMDocument *aSourceDoc,
|
||||
const nsAString & aContextStr,
|
||||
const nsAString & aInfoStr,
|
||||
nsIDOMNode *aDestinationNode,
|
||||
PRInt32 aDestOffset,
|
||||
bool aDoDeleteSelection);
|
||||
bool HavePrivateHTMLFlavor( nsIClipboard *clipboard );
|
||||
nsresult ParseCFHTML(nsCString & aCfhtml, PRUnichar **aStuffToPaste, PRUnichar **aCfcontext);
|
||||
nsresult DoContentFilterCallback(const nsAString &aFlavor,
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsIDOMDOMStringList.h"
|
||||
#include "nsIDocumentEncoder.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
|
||||
|
@ -61,6 +62,7 @@
|
|||
#include "nsIDragService.h"
|
||||
#include "nsIDOMUIEvent.h"
|
||||
#include "nsCopySupport.h"
|
||||
#include "nsITransferable.h"
|
||||
|
||||
// Misc
|
||||
#include "nsEditorUtils.h"
|
||||
|
@ -70,6 +72,10 @@
|
|||
#include "nsEventDispatcher.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
// private clipboard data flavors for html copy/paste
|
||||
#define kHTMLContext "text/_moz_htmlcontext"
|
||||
#define kHTMLInfo "text/_moz_htmlinfo"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMETHODIMP nsPlaintextEditor::PrepareTransferable(nsITransferable **transferable)
|
||||
|
@ -151,8 +157,6 @@ NS_IMETHODIMP nsPlaintextEditor::InsertTextFromTransferable(nsITransferable *aTr
|
|||
|
||||
// Try to scroll the selection into view if the paste/drop succeeded
|
||||
|
||||
// After ScrollSelectionIntoView(), the pending notifications might be flushed
|
||||
// and PresShell/PresContext/Frames may be dead. See bug 418470.
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ScrollSelectionIntoView(false);
|
||||
|
||||
|
@ -162,29 +166,21 @@ NS_IMETHODIMP nsPlaintextEditor::InsertTextFromTransferable(nsITransferable *aTr
|
|||
NS_IMETHODIMP nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
||||
{
|
||||
ForceCompositionEnd();
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDragService> dragService =
|
||||
do_GetService("@mozilla.org/widget/dragservice;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDragSession> dragSession;
|
||||
dragService->GetCurrentSession(getter_AddRefs(dragSession));
|
||||
NS_ENSURE_TRUE(dragSession, NS_OK);
|
||||
nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aDropEvent));
|
||||
NS_ENSURE_TRUE(dragEvent, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
|
||||
nsresult rv = dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Current doc is destination
|
||||
nsCOMPtr<nsIDOMDocument> destdomdoc;
|
||||
rv = GetDocument(getter_AddRefs(destdomdoc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the nsITransferable interface for getting the data from the drop
|
||||
nsCOMPtr<nsITransferable> trans;
|
||||
rv = PrepareTransferable(getter_AddRefs(trans));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(trans, NS_OK); // NS_ERROR_FAILURE; SHOULD WE FAIL?
|
||||
|
||||
PRUint32 numItems = 0;
|
||||
rv = dragSession->GetNumDropItems(&numItems);
|
||||
rv = dataTransfer->GetMozItemCount(&numItems);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (numItems < 1) return NS_ERROR_FAILURE; // nothing to drop?
|
||||
|
||||
|
@ -240,11 +236,14 @@ NS_IMETHODIMP nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
|||
break;
|
||||
}
|
||||
|
||||
// Source doc is null if source is *not* the current editor document
|
||||
// Current doc is destination (set earlier)
|
||||
nsCOMPtr<nsIDOMNode> sourceNode;
|
||||
dataTransfer->GetMozSourceNode(getter_AddRefs(sourceNode));
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> srcdomdoc;
|
||||
rv = dragSession->GetSourceDocument(getter_AddRefs(srcdomdoc));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (sourceNode) {
|
||||
sourceNode->GetOwnerDocument(getter_AddRefs(srcdomdoc));
|
||||
NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
if (cursorIsInSelection)
|
||||
{
|
||||
|
@ -263,9 +262,9 @@ NS_IMETHODIMP nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
|||
if (srcdomdoc == destdomdoc)
|
||||
{
|
||||
// Within the same doc: delete if user doesn't want to copy
|
||||
PRUint32 action;
|
||||
dragSession->GetDragAction(&action);
|
||||
deleteSelection = !(action & nsIDragService::DRAGDROP_ACTION_COPY);
|
||||
PRUint32 dropEffect;
|
||||
dataTransfer->GetDropEffectInt(&dropEffect);
|
||||
deleteSelection = !(dropEffect & nsIDragService::DRAGDROP_ACTION_COPY);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -285,7 +284,6 @@ NS_IMETHODIMP nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
|||
if (formControl && !formControl->AllowDrop()) {
|
||||
// Don't allow dropping into a form control that doesn't allow being
|
||||
// dropped into.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -295,15 +293,20 @@ NS_IMETHODIMP nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
|||
PRUint32 i;
|
||||
for (i = 0; i < numItems; ++i)
|
||||
{
|
||||
rv = dragSession->GetData(trans, i);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(trans, NS_OK); // NS_ERROR_FAILURE; Should we fail?
|
||||
nsCOMPtr<nsIVariant> data;
|
||||
dataTransfer->MozGetDataAt(NS_LITERAL_STRING("text/plain"), i,
|
||||
getter_AddRefs(data));
|
||||
nsAutoString insertText;
|
||||
data->GetAsAString(insertText);
|
||||
nsContentUtils::PlatformToDOMLineBreaks(insertText);
|
||||
|
||||
// Beware! This may flush notifications via synchronous
|
||||
// ScrollSelectionIntoView.
|
||||
rv = InsertTextFromTransferable(trans, newSelectionParent, newSelectionOffset, deleteSelection);
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
rv = InsertTextAt(insertText, newSelectionParent, newSelectionOffset, deleteSelection);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ScrollSelectionIntoView(false);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -332,8 +335,6 @@ NS_IMETHODIMP nsPlaintextEditor::Paste(PRInt32 aSelectionType)
|
|||
if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, trans))
|
||||
return NS_OK;
|
||||
|
||||
// Beware! This may flush notifications via synchronous
|
||||
// ScrollSelectionIntoView.
|
||||
rv = InsertTextFromTransferable(trans, nsnull, nsnull, true);
|
||||
}
|
||||
}
|
||||
|
@ -355,8 +356,6 @@ NS_IMETHODIMP nsPlaintextEditor::PasteTransferable(nsITransferable *aTransferabl
|
|||
if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, aTransferable))
|
||||
return NS_OK;
|
||||
|
||||
// Beware! This may flush notifications via synchronous
|
||||
// ScrollSelectionIntoView.
|
||||
return InsertTextFromTransferable(aTransferable, nsnull, nsnull, true);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче