Bug 664717 - Part 3: Include file promise when copying an image in Windows. r?seth draft
authorHector Zhao <bzhao@mozilla.com>
Thu, 30 Jun 2016 16:23:30 +0800
changeset 383108 ca2fa839de6cdaefa3c8d24d0b82db18c0442267
parent 383107 d4002835c36390de9cd486867fd825bc71badfd4
child 524395 c9e48432bcadb64fe395fa5450ef6b1f7b3ef691
push id21936
push userbmo:bzhao@mozilla.com
push dateFri, 01 Jul 2016 08:06:55 +0000
reviewersseth
bugs664717
milestone50.0a1
Bug 664717 - Part 3: Include file promise when copying an image in Windows. r?seth MozReview-Commit-ID: ANSey2vGwaG
dom/base/nsCopySupport.cpp
--- a/dom/base/nsCopySupport.cpp
+++ b/dom/base/nsCopySupport.cpp
@@ -14,16 +14,17 @@
 #include "nsIFormControl.h"
 #include "nsISelection.h"
 #include "nsWidgetsCID.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIDOMRange.h"
 #include "nsRange.h"
 #include "imgIContainer.h"
+#include "imgIRequest.h"
 #include "nsIPresShell.h"
 #include "nsFocusManager.h"
 #include "mozilla/dom/DataTransfer.h"
 
 #include "nsIDocShell.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIClipboardDragDropHooks.h"
 #include "nsIClipboardDragDropHookList.h"
@@ -42,16 +43,26 @@
 #include "nsISimpleEnumerator.h"
 
 // image copy stuff
 #include "nsIImageLoadingContent.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsContentUtils.h"
 #include "nsContentCID.h"
 
+#ifdef XP_WIN
+#include "nsCExternalHandlerService.h"
+#include "nsEscape.h"
+#include "nsIMimeInfo.h"
+#include "nsIMIMEService.h"
+#include "nsIURL.h"
+#include "nsReadableUtils.h"
+#include "nsXULAppAPI.h"
+#endif
+
 #include "mozilla/ContentEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/IntegerRange.h"
 
 using namespace mozilla;
@@ -67,16 +78,23 @@ static NS_DEFINE_CID(kHTMLConverterCID, 
 static nsresult AppendString(nsITransferable *aTransferable,
                              const nsAString& aString,
                              const char* aFlavor);
 
 // copy HTML node data
 static nsresult AppendDOMNode(nsITransferable *aTransferable,
                               nsINode* aDOMNode);
 
+#ifdef XP_WIN
+// copy image as file promise onto the transferable
+static nsresult AppendImagePromise(nsITransferable* aTransferable,
+                                   imgIRequest* aImgRequest,
+                                   nsIImageLoadingContent* aImageElement);
+#endif
+
 // Helper used for HTMLCopy and GetTransferableForSelection since both routines
 // share common code.
 static nsresult
 SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
                     bool doPutOnClipboard, int16_t aClipboardID,
                     uint32_t aFlags, nsITransferable ** aTransferable)
 {
   // Clear the output parameter for the transferable, if provided.
@@ -434,21 +452,28 @@ nsCopySupport::ImageCopy(nsIImageLoading
     nsCOMPtr<nsINode> node(do_QueryInterface(aImageElement, &rv));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = AppendDOMNode(trans, node);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_DATA) {
-    // get the image data from the element
+    // get the image data and its request from the element
+    nsCOMPtr<imgIRequest> imgRequest;
     nsCOMPtr<imgIContainer> image =
-      nsContentUtils::GetImageFromContent(aImageElement);
+      nsContentUtils::GetImageFromContent(aImageElement,
+                                          getter_AddRefs(imgRequest));
     NS_ENSURE_TRUE(image, NS_ERROR_FAILURE);
 
+#ifdef XP_WIN
+    rv = AppendImagePromise(trans, imgRequest, aImageElement);
+    NS_ENSURE_SUCCESS(rv, rv);
+#endif
+
     nsCOMPtr<nsISupportsInterfacePointer>
       imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = imgPtr->SetData(image);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // copy the image data onto the transferable
@@ -540,16 +565,101 @@ static nsresult AppendDOMNode(nsITransfe
     rv = AppendString(aTransferable, info, kHTMLInfo);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // add a special flavor, even if we don't have html context data
   return AppendString(aTransferable, context, kHTMLContext);
 }
 
+#ifdef XP_WIN
+static nsresult AppendImagePromise(nsITransferable* aTransferable,
+                                   imgIRequest* aImgRequest,
+                                   nsIImageLoadingContent* aImageElement)
+{
+  nsresult rv;
+
+  NS_ENSURE_TRUE(aImgRequest, NS_OK);
+  nsCOMPtr<nsINode> node(do_QueryInterface(aImageElement, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Fix the file extension in the URL if necessary
+  nsCOMPtr<nsIMIMEService> mimeService =
+    do_GetService(NS_MIMESERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(mimeService, NS_OK);
+
+  nsCOMPtr<nsIURI> imgUri;
+  rv = aImgRequest->GetCurrentURI(getter_AddRefs(imgUri));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIURL> imgUrl(do_QueryInterface(imgUri));
+  NS_ENSURE_TRUE(imgUrl, NS_OK);
+
+  nsAutoCString extension;
+  rv = imgUrl->GetFileExtension(extension);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsXPIDLCString mimeType;
+  rv = aImgRequest->GetMimeType(getter_Copies(mimeType));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMIMEInfo> mimeInfo;
+  mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
+                                       getter_AddRefs(mimeInfo));
+  NS_ENSURE_TRUE(mimeInfo, NS_OK);
+
+  nsAutoCString spec;
+  rv = imgUrl->GetSpec(spec);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // pass out the image source string
+  nsString imageSourceString;
+  CopyUTF8toUTF16(spec, imageSourceString);
+
+  bool validExtension;
+  if (extension.IsEmpty() ||
+      NS_FAILED(mimeInfo->ExtensionExists(extension,
+                                          &validExtension)) ||
+      !validExtension) {
+    // Fix the file extension in the URL
+    rv = imgUrl->Clone(getter_AddRefs(imgUri));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    imgUrl = do_QueryInterface(imgUri);
+
+    nsAutoCString primaryExtension;
+    mimeInfo->GetPrimaryExtension(primaryExtension);
+
+    imgUrl->SetFileExtension(primaryExtension);
+  }
+
+  nsAutoCString fileName;
+  imgUrl->GetFileName(fileName);
+
+  NS_UnescapeURL(fileName);
+
+  // make the filename safe for the filesystem
+  fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
+
+  nsString imageDestFileName;
+  CopyUTF8toUTF16(fileName, imageDestFileName);
+
+  rv = AppendString(aTransferable, imageSourceString, kFilePromiseURLMime);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = AppendString(aTransferable, imageDestFileName, kFilePromiseDestFilename);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  aTransferable->SetRequestingPrincipal(node->NodePrincipal());
+
+  // add the dataless file promise flavor
+  return aTransferable->AddDataFlavor(kFilePromiseMime);
+}
+#endif // XP_WIN
+
 nsIContent*
 nsCopySupport::GetSelectionForCopy(nsIDocument* aDocument, nsISelection** aSelection)
 {
   *aSelection = nullptr;
 
   nsIPresShell* presShell = aDocument->GetShell();
   if (!presShell)
     return nullptr;