Bug 1058712, e10s, support for copy image command, r=ehsan,mconley

This commit is contained in:
Neil Deakin 2015-04-21 20:09:14 -04:00
parent 124eaea6e3
commit 3b7fec7dde
5 changed files with 112 additions and 14 deletions

View File

@ -123,6 +123,13 @@ let handleContentContextMenu = function (event) {
InlineSpellCheckerContent.initContextMenu(event, editFlags, this);
}
// Set the event target first as the copy image command needs it to
// determine what was context-clicked on. Then, update the state of the
// commands on the context menu.
docShell.contentViewer.QueryInterface(Ci.nsIContentViewerEdit)
.setCommandNode(event.target);
event.target.ownerDocument.defaultView.updateCommands("contentcontextmenu");
let customMenuItems = PageMenuChild.build(event.target);
let principal = doc.nodePrincipal;
sendSyncMessage("contextmenu",

View File

@ -628,7 +628,9 @@ nsContextMenu.prototype = {
this.inSyntheticDoc = ownerDoc.mozSyntheticDocument;
// First, do checks for nodes that never have children.
if (this.target.nodeType == Node.ELEMENT_NODE) {
// See if the user clicked on an image.
// See if the user clicked on an image. This check mirrors
// nsDocumentViewer::GetInImage. Make sure to update both if this is
// changed.
if (this.target instanceof Ci.nsIImageLoadingContent &&
this.target.currentURI) {
this.onImage = true;

View File

@ -1,7 +1,9 @@
// This test is used to check copy and paste in editable areas to ensure that non-text
// types (html and images) are copied to and pasted from the clipboard properly.
let testPage = "<div id='main' contenteditable='true'>Test <b>Bold</b> After Text</div>";
let testPage = "<body style='margin: 0'><img id='img' tabindex='1' src='http://example.org/browser/browser/base/content/test/general/moz.png'>" +
" <div id='main' contenteditable='true'>Test <b>Bold</b> After Text</div>" +
"</body>";
add_task(function*() {
let tab = gBrowser.addTab();
@ -12,7 +14,12 @@ add_task(function*() {
yield promiseTabLoadEvent(tab, "data:text/html," + escape(testPage));
yield SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
let results = yield ContentTask.spawn(browser, {}, function* () {
const modifier = (content.navigator.platform.indexOf("Mac") >= 0) ?
Components.interfaces.nsIDOMWindowUtils.MODIFIER_META :
Components.interfaces.nsIDOMWindowUtils.MODIFIER_CONTROL;
let results = yield ContentTask.spawn(browser, { modifier: modifier },
function* (arg) {
var doc = content.document;
var main = doc.getElementById("main");
main.focus();
@ -20,10 +27,7 @@ add_task(function*() {
const utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
const modifier = (content.navigator.platform.indexOf("Mac") >= 0) ?
Components.interfaces.nsIDOMWindowUtils.MODIFIER_META :
Components.interfaces.nsIDOMWindowUtils.MODIFIER_CONTROL;
const modifier = arg.modifier;
function sendKey(key)
{
if (utils.sendKeyEvent("keydown", key, 0, modifier)) {
@ -46,7 +50,7 @@ add_task(function*() {
selection.modify("extend", "right", "word");
selection.modify("extend", "right", "word");
yield new content.Promise((resolve, reject) => {
yield new Promise((resolve, reject) => {
addEventListener("copy", function copyEvent(event) {
removeEventListener("copy", copyEvent, true);
// The data is empty as the selection is copied during the event default phase.
@ -59,7 +63,7 @@ add_task(function*() {
selection.modify("move", "right", "line");
yield new content.Promise((resolve, reject) => {
yield new Promise((resolve, reject) => {
addEventListener("paste", function copyEvent(event) {
removeEventListener("paste", copyEvent, true);
let clipboardData = event.clipboardData;
@ -80,7 +84,7 @@ add_task(function*() {
selection.modify("extend", "left", "word");
selection.modify("extend", "left", "character");
yield new content.Promise((resolve, reject) => {
yield new Promise((resolve, reject) => {
addEventListener("cut", function copyEvent(event) {
removeEventListener("cut", copyEvent, true);
event.clipboardData.setData("text/plain", "Some text");
@ -94,7 +98,7 @@ add_task(function*() {
selection.modify("move", "left", "line");
yield new content.Promise((resolve, reject) => {
yield new Promise((resolve, reject) => {
addEventListener("paste", function copyEvent(event) {
removeEventListener("paste", copyEvent, true);
let clipboardData = event.clipboardData;
@ -110,6 +114,7 @@ add_task(function*() {
});
is(main.innerHTML, "<i>Italic</i> Test <b>Bold</b> After<b></b>", "Copy and paste html 2");
return results;
});
@ -118,6 +123,61 @@ add_task(function*() {
ok(results[t].startsWith("PASSED"), results[t]);
}
// Next, check that the Copy Image command works.
// The context menu needs to be opened to properly initialize for the copy
// image command to run.
let contextMenu = document.getElementById("contentAreaContextMenu");
let contextMenuShown = promisePopupShown(contextMenu);
BrowserTestUtils.synthesizeMouseAtCenter("#img", { type: "contextmenu", button: 2 }, gBrowser.selectedBrowser);
yield contextMenuShown;
document.getElementById("context-copyimage-contents").doCommand();
contextMenu.hidePopup();
yield promisePopupHidden(contextMenu);
// Focus the content again
yield SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
let expectedContent = yield ContentTask.spawn(browser, { modifier: modifier },
function* (arg) {
var doc = content.document;
var main = doc.getElementById("main");
main.focus();
yield new Promise((resolve, reject) => {
addEventListener("paste", function copyEvent(event) {
removeEventListener("paste", copyEvent, true);
let clipboardData = event.clipboardData;
// DataTransfer doesn't support the image types yet, so only text/html
// will be present.
if (clipboardData.getData("text/html") !=
'<img id="img" tabindex="1" src="http://example.org/browser/browser/base/content/test/general/moz.png">') {
reject();
}
resolve();
}, true)
const utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
const modifier = arg.modifier;
if (utils.sendKeyEvent("keydown", "v", 0, modifier)) {
utils.sendKeyEvent("keypress", "v", "v".charCodeAt(0), modifier);
}
utils.sendKeyEvent("keyup", "v", 0, modifier);
});
// Return the new content which should now include an image.
return main.innerHTML;
});
is(expectedContent, '<i>Italic</i> <img id="img" tabindex="1" ' +
'src="http://example.org/browser/browser/base/content/test/general/moz.png">' +
'Test <b>Bold</b> After<b></b>', "Paste after copy image");
gBrowser.removeCurrentTab();
});

View File

@ -6,7 +6,9 @@
#include "nsISupports.idl"
[scriptable, uuid(AF13EA3A-D488-4308-B843-526E055AB943)]
interface nsIDOMNode;
[scriptable, uuid(35BE2D7E-F29B-48EC-BF7E-80A30A724DE3)]
interface nsIContentViewerEdit : nsISupports
{
void clearSelection();
@ -27,4 +29,8 @@ interface nsIContentViewerEdit : nsISupports
AString getContents(in string aMimeType, in boolean aSelectionOnly);
readonly attribute boolean canGetContents;
// Set the node that will be the subject of the editing commands above.
// Usually this will be the node that was context-clicked.
void setCommandNode(in nsIDOMNode aNode);
};

View File

@ -60,6 +60,7 @@
#include "nsIImageLoadingContent.h"
#include "nsCopySupport.h"
#include "nsIDOMHTMLFrameSetElement.h"
#include "nsIDOMHTMLImageElement.h"
#ifdef MOZ_XUL
#include "nsIXULDocument.h"
#include "nsXULPopupManager.h"
@ -2707,6 +2708,20 @@ NS_IMETHODIMP nsDocumentViewer::GetCanGetContents(bool *aCanGetContents)
return NS_OK;
}
NS_IMETHODIMP nsDocumentViewer::SetCommandNode(nsIDOMNode* aNode)
{
nsIDocument* document = GetDocument();
NS_ENSURE_STATE(document);
nsCOMPtr<nsPIDOMWindow> window(document->GetWindow());
NS_ENSURE_TRUE(window, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
NS_ENSURE_STATE(root);
root->SetPopupNode(aNode);
return NS_OK;
}
/* ========================================================================================
* nsIContentViewerFile
@ -3529,8 +3544,16 @@ NS_IMETHODIMP nsDocumentViewer::GetInImage(bool* aInImage)
if (NS_FAILED(rv)) return rv;
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
// if we made it here, we're in an image
*aInImage = true;
// Make sure there is a URI assigned. This allows <input type="image"> to
// be an image but rejects other <input> types. This matches what
// nsContextMenu.js does.
nsCOMPtr<nsIURI> uri;
node->GetCurrentURI(getter_AddRefs(uri));
if (uri) {
// if we made it here, we're in an image
*aInImage = true;
}
return NS_OK;
}