/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include"nsReadableUtils.h"
// Local Includes #include"nsContentAreaDragDrop.h"
// SaveURIToFile // used on platforms where it's possible to drag items (e.g. images) // into the file system
nsresult nsContentAreaDragDropDataProvider::SaveURIToFile(
nsIURI* inSourceURI, nsIPrincipal* inTriggeringPrincipal,
nsICookieJarSettings* inCookieJarSettings, nsIFile* inDestFile,
nsContentPolicyType inContentPolicyType, bool isPrivate) {
nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(inSourceURI); if (!sourceURL) { return NS_ERROR_NO_INTERFACE;
}
// 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<nsIWebBrowserPersist> persist = do_CreateInstance( "@mozilla.org/embedding/browser/nsWebBrowserPersist;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
// referrer policy can be anything since the referrer is nullptr return persist->SaveURI(inSourceURI, inTriggeringPrincipal, 0, nullptr,
inCookieJarSettings, nullptr, nullptr, inDestFile,
inContentPolicyType, isPrivate);
}
/* * Check if the provided filename extension is valid for the MIME type and * return the MIME type's primary extension. * * @param aExtension [in] the extension to check * @param aMimeType [in] the MIME type to check the extension with * @param aIsValidExtension [out] true if |aExtension| is valid for * |aMimeType| * @param aPrimaryExtension [out] the primary extension for the MIME type * to potentially be used as a replacement * for |aExtension|
*/
nsresult CheckAndGetExtensionForMime(const nsCString& aExtension, const nsCString& aMimeType, bool* aIsValidExtension,
nsACString* aPrimaryExtension) {
nsresult rv;
nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1"); if (NS_WARN_IF(!mimeService)) { return NS_ERROR_FAILURE;
}
// 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 in AddStringsToDataTransfer. // // 2. Someone put a kFilePromiseDirectoryMime flavor into the // transferable with an nsIFile 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
nsContentAreaDragDropDataProvider::GetFlavorData(nsITransferable* aTransferable, constchar* aFlavor,
nsISupports** aData) {
NS_ENSURE_ARG_POINTER(aData);
*aData = nullptr;
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
if (strcmp(aFlavor, kFilePromiseMime) == 0) { // get the URI from the kFilePromiseURLMime flavor
NS_ENSURE_ARG(aTransferable);
nsCOMPtr<nsISupports> tmp;
rv = aTransferable->GetTransferData(kFilePromiseURLMime,
getter_AddRefs(tmp));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupportsString> supportsString = do_QueryInterface(tmp); if (!supportsString) return NS_ERROR_FAILURE;
nsAutoString sourceURLString;
supportsString->GetData(sourceURLString); if (sourceURLString.IsEmpty()) return NS_ERROR_FAILURE;
nsAutoString targetFilename;
supportsString->GetData(targetFilename); if (targetFilename.IsEmpty()) return NS_ERROR_FAILURE;
#ifdefined(XP_MACOSX) // Use the image request's MIME type to ensure the filename's // extension is compatible with the OS's handler for this type. // If it isn't, or is missing, replace the extension with the // primary extension. On Mac, do this in the parent process // because sandboxing blocks access to MIME-handler info from // content processes. if (XRE_IsParentProcess()) {
rv = aTransferable->GetTransferData(kImageRequestMime,
getter_AddRefs(tmp));
NS_ENSURE_SUCCESS(rv, rv);
supportsString = do_QueryInterface(tmp); if (!supportsString) return NS_ERROR_FAILURE;
// // CreateLinkText // // Creates the html for an anchor in the form // <a href="inURL">inText</a> // void DragDataProducer::CreateLinkText(const nsAString& inURL, const nsAString& inText,
nsAString& outLinkText) { // use a temp var in case |inText| is the same string as // |outLinkText| to avoid overwriting it while building up the // string in pieces.
nsAutoString linkText(u""_ns + inURL + u"\">"_ns + inText +
u""_ns);
#ifdefined(XP_MACOSX) // Save the MIME type so we can make sure the extension // is compatible (and replace it if it isn't) when the // image is dropped. On Mac, we need to get the OS MIME // handler information in the parent due to sandboxing.
CopyUTF8toUTF16(mimeType, mImageRequestMime);
CopyUTF8toUTF16(fileName, mImageDestFileName); #else
nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1"); if (NS_WARN_IF(!mimeService)) { return NS_ERROR_FAILURE;
}
// Find the selection to see what we could be dragging and if what we're // dragging is in what is selected. If this is an editable textbox, use // the textbox's selection, otherwise use the window's selection.
RefPtr<Selection> selection;
nsIContent* editingElement = mSelectionTargetNode->IsEditable()
? mSelectionTargetNode->GetEditingHost()
: nullptr;
RefPtr<TextControlElement> textControlElement =
TextControlElement::GetTextControlElementFromEditingHost(editingElement); if (textControlElement) {
nsISelectionController* selcon =
textControlElement->GetSelectionController(); if (selcon) {
selection =
selcon->GetSelection(nsISelectionController::SELECTION_NORMAL);
}
if (!selection) return NS_OK;
} else {
selection = mWindow->GetSelection(); if (!selection) return NS_OK;
// Check if the node is inside a form control. Don't set aCanDrag to false // however, as we still want to allow the drag.
nsCOMPtr<nsIContent> findFormNode = mSelectionTargetNode;
nsIContent* findFormParent = findFormNode->GetParent(); while (findFormParent) { constauto* form = nsIFormControl::FromNode(findFormParent); if (form && !form->AllowDraggableChildren()) { return NS_OK;
}
findFormParent = findFormParent->GetParent();
}
}
// if set, serialize the content under this node
nsCOMPtr<nsIContent> nodeToSerialize;
BrowsingContext* bc = mWindow->GetBrowsingContext(); constbool isChromeShell = bc && bc->IsChrome();
// In chrome shells, only allow dragging inside editable areas. if (isChromeShell && !editingElement) { // This path should already be filtered out in // EventStateManager::DetermineDragTargetAndDefaultData.
MOZ_ASSERT_UNREACHABLE("Shouldn't be generating drag data for chrome"); return NS_OK;
}
if (isChromeShell && textControlElement) { // Only use the selection if the target node is in the selection. if (!selection->ContainsNode(*mSelectionTargetNode, false, IgnoreErrors())) return NS_OK;
selection.swap(*aSelection);
} else { // In content shells, a number of checks are made below to determine // whether an image or a link is being dragged. If so, add additional // data to the data transfer. This is also done for chrome shells, but // only when in a non-textbox editor.
bool haveSelectedContent = false;
// only drag form elements by using the alt key, // otherwise buttons and select widgets are hard to use
// Note that while <object> elements implement nsIFormControl, we should // really allow dragging them if they happen to be images. if (!mIsAltKeyPressed) { constauto* form = nsIFormControl::FromNodeOrNull(mTarget); if (form && form->ControlType() != FormControlType::Object) {
*aCanDrag = false; return NS_OK;
}
}
// possible parent link node
nsCOMPtr<nsIContent> parentLink;
nsCOMPtr<nsIContent> draggedNode = FindDragTarget(mTarget);
// either plain text or anchor text is selected if (haveSelectedContent) {
selection.swap(*aSelection);
} elseif (selectedImageOrLinkNode) { // an image is selected
image = do_QueryInterface(selectedImageOrLinkNode);
} else { // nothing is selected - // // look for draggable elements under the mouse // // if the alt key is down, don't start a drag if we're in an // anchor because we want to do selection.
parentLink = nsContentUtils::GetClosestLinkInFlatTree(draggedNode); if (parentLink && mIsAltKeyPressed) {
*aCanDrag = false; return NS_OK;
}
image = do_QueryInterface(draggedNode);
}
{ // set for linked images, and links
nsCOMPtr<nsIContent> linkNode; if (constauto* areaElem = HTMLAreaElement::FromNodeOrNull(draggedNode)) { // use the alt text (or, if missing, the href) as the title
areaElem->GetAttr(nsGkAtoms::alt, mTitleString); if (mTitleString.IsEmpty()) { // this can be a relative link
areaElem->GetAttr(nsGkAtoms::href, mTitleString);
}
// gives an absolute link
nsresult rv = GetAnchorURL(draggedNode, mUrlString);
NS_ENSURE_SUCCESS(rv, rv);
// we'll generate HTML like <a href="absurl">alt text</a>
mIsAnchor = true;
dragNode = draggedNode;
} elseif (image) { // grab the href as the url, use alt text as the title of the // area if it's there. the drag data is the image tag and src // attribute.
nsCOMPtr<nsIURI> imageURI;
image->GetCurrentURI(getter_AddRefs(imageURI));
nsCOMPtr<Element> imageElement(do_QueryInterface(image)); if (imageURI) {
nsAutoCString spec;
rv = imageURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
nsIScriptSecurityManager* secMan =
nsContentUtils::GetSecurityManager();
rv = secMan->CheckLoadURIStrWithPrincipal(
imageElement->NodePrincipal(), spec, 0);
NS_ENSURE_SUCCESS(rv, rv);
mIsAnchor = true;
CopyUTF8toUTF16(spec, mUrlString);
}
// XXXbz Shouldn't we use the "title" attr for title? Using // "alt" seems very wrong.... // XXXbz Also, what if this is an nsIImageLoadingContent // that's not an <html:img>? if (imageElement) {
imageElement->GetAttr(nsGkAtoms::alt, mTitleString);
}
if (mTitleString.IsEmpty()) {
mTitleString = mUrlString;
}
nsCOMPtr<imgIRequest> imgRequest;
// grab the image data, and its request.
nsCOMPtr<imgIContainer> img = nsContentUtils::GetImageFromContent(
image, getter_AddRefs(imgRequest)); if (imgRequest) {
rv = GetImageData(img, imgRequest);
NS_ENSURE_SUCCESS(rv, rv);
}
if (parentLink) { // If we are dragging around an image in an anchor, then we // are dragging the entire anchor
linkNode = parentLink;
nodeToSerialize = linkNode;
} else {
nodeToSerialize = draggedNode;
}
dragNode = nodeToSerialize;
} elseif (parentLink) { // parentLink will always be null if there's selected content
linkNode = parentLink;
nodeToSerialize = linkNode;
} elseif (!haveSelectedContent) { // nothing draggable return NS_OK;
}
// if we have selected text, use it in preference to the node
nsCOMPtr<nsITransferable> transferable; if (*aSelection) {
rv = nsCopySupport::GetTransferableForSelection(
*aSelection, doc, getter_AddRefs(transferable));
} else {
rv = nsCopySupport::GetTransferableForNode(nodeToSerialize, doc,
getter_AddRefs(transferable));
}
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupports> supports;
nsCOMPtr<nsISupportsString> data;
rv = transferable->GetTransferData(kHTMLMime, getter_AddRefs(supports));
data = do_QueryInterface(supports); if (NS_SUCCEEDED(rv)) {
data->GetData(mHtmlString);
}
rv = transferable->GetTransferData(kHTMLContext, getter_AddRefs(supports));
data = do_QueryInterface(supports); if (NS_SUCCEEDED(rv)) {
data->GetData(mContextString);
}
rv = transferable->GetTransferData(kHTMLInfo, getter_AddRefs(supports));
data = do_QueryInterface(supports); if (NS_SUCCEEDED(rv)) {
data->GetData(mInfoString);
}
rv = transferable->GetTransferData(kTextMime, getter_AddRefs(supports));
data = do_QueryInterface(supports);
NS_ENSURE_SUCCESS(rv, rv); // require plain text at a minimum
data->GetData(mTitleString);
}
// default text value is the URL if (mTitleString.IsEmpty()) {
mTitleString = mUrlString;
}
// if we haven't constructed a html version, make one now if (mHtmlString.IsEmpty() && !mUrlString.IsEmpty())
CreateLinkText(mUrlString, mTitleString, mHtmlString);
// if there is no drag node, which will be the case for a selection, just // use the selection target node.
rv = AddStringsToDataTransfer(
dragNode ? dragNode : mSelectionTargetNode.get(), aDataTransfer);
NS_ENSURE_SUCCESS(rv, rv);
// set all of the data to have the principal of the node where the data came // from
nsIPrincipal* principal = aDragNode->NodePrincipal();
// add a special flavor if we're an anchor to indicate that we have // a URL in the drag data if (!mUrlString.IsEmpty() && mIsAnchor) {
nsAutoString dragData(mUrlString);
dragData.Append('\n'); // Remove leading and trailing newlines in the title and replace them with // space in remaining positions - they confuse PlacesUtils::unwrapNodes // that expects url\ntitle formatted data for x-moz-url.
nsAutoString title(mTitleString);
title.Trim("\r\n");
title.ReplaceChar(u"\r\n", ' ');
dragData += title;
// add a special flavor for the html context data if (!mContextString.IsEmpty())
AddString(aDataTransfer, NS_LITERAL_STRING_FROM_CSTRING(kHTMLContext),
mContextString, principal);
// add a special flavor if we have html info data if (!mInfoString.IsEmpty())
AddString(aDataTransfer, NS_LITERAL_STRING_FROM_CSTRING(kHTMLInfo),
mInfoString, principal);
// add the full html if (!mHtmlString.IsEmpty())
AddString(aDataTransfer, NS_LITERAL_STRING_FROM_CSTRING(kHTMLMime),
mHtmlString, principal);
// add the plain text. we use the url for text/plain data if an anchor is // being dragged, rather than the title text of the link or the alt text for // an anchor image.
AddString(aDataTransfer, NS_LITERAL_STRING_FROM_CSTRING(kTextMime),
mIsAnchor ? mUrlString : mTitleString, principal);
// 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 (mImage) {
RefPtr<nsVariantCC> variant = new nsVariantCC();
variant->SetAsISupports(mImage);
aDataTransfer->SetDataWithPrincipal(
NS_LITERAL_STRING_FROM_CSTRING(kNativeImageMime), variant, 0,
principal);
// 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.
nsCOMPtr<nsIFlavorDataProvider> dataProvider = new nsContentAreaDragDropDataProvider(); if (dataProvider) {
RefPtr<nsVariantCC> variant = new nsVariantCC();
variant->SetAsISupports(dataProvider);
aDataTransfer->SetDataWithPrincipal(
NS_LITERAL_STRING_FROM_CSTRING(kFilePromiseMime), variant, 0,
principal);
}
// if not an anchor, add the image url if (!mIsAnchor) {
AddString(aDataTransfer, NS_LITERAL_STRING_FROM_CSTRING(kURLDataMime),
mUrlString, principal);
AddString(aDataTransfer, u"text/uri-list"_ns, mUrlString, principal);
}
}
return NS_OK;
}
// note that this can return NS_OK, but a null out param (by design) // static
nsresult DragDataProducer::GetDraggableSelectionData(
Selection* inSelection, nsIContent* inRealTargetNode,
nsIContent** outImageOrLinkNode, bool* outDragSelectedText) {
NS_ENSURE_ARG(inSelection);
NS_ENSURE_ARG(inRealTargetNode);
NS_ENSURE_ARG_POINTER(outImageOrLinkNode);
if (!inSelection->AreNormalAndCrossShadowBoundaryRangesCollapsed()) { if (inSelection->ContainsNode(*inRealTargetNode, false, IgnoreErrors())) { // track down the anchor node, if any, for the url
nsINode* selectionStart =
inSelection->GetMayCrossShadowBoundaryAnchorNode();
nsINode* selectionEnd = inSelection->GetMayCrossShadowBoundaryFocusNode();
// look for a selection around a single node, like an image. // in this case, drag the image, rather than a serialization of the HTML // XXX generalize this to other draggable element types? if (selectionStart == selectionEnd) {
nsCOMPtr<nsIContent> selStartContent =
nsIContent::FromNodeOrNull(selectionStart); if (selStartContent && selStartContent->HasChildNodes()) { // see if just one node is selected
uint32_t anchorOffset = inSelection->AnchorOffset();
uint32_t focusOffset = inSelection->FocusOffset(); if (anchorOffset == focusOffset + 1 ||
focusOffset == anchorOffset + 1) {
uint32_t childOffset = std::min(anchorOffset, focusOffset);
nsIContent* childContent =
selStartContent->GetChildAt_Deprecated(childOffset); // if we find an image, we'll fall into the node-dragging code, // rather the the selection-dragging code if (nsContentUtils::IsDraggableImage(childContent)) {
NS_ADDREF(*outImageOrLinkNode = childContent); return NS_OK;
}
}
}
}
// indicate that a link or text is selected
*outDragSelectedText = true;
}
}
return NS_OK;
}
¤ Dauer der Verarbeitung: 0.37 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.