[Pkg-mozext-commits] [firegestures] 02/08: [e10s] add support to multi-process tabs (part 2)
David Prévot
taffit at moszumanska.debian.org
Sat Dec 13 21:16:39 UTC 2014
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository firegestures.
commit bb5e3e9e1a64bb02457226e437b3f8e996838f39
Author: Gomita <gomita at xuldev.org>
Date: Sat Dec 13 13:42:46 2014 +0900
[e10s] add support to multi-process tabs (part 2)
---
FireGestures.idl | 7 +-
chrome/content/firegestures/browser.js | 61 +++++++
chrome/content/firegestures/remote.js | 291 +++++++++++++++++++++++++++++++++
components/FireGestures.xpt | Bin 1395 -> 1449 bytes
components/xdGestureHandler.js | 50 +++++-
5 files changed, 406 insertions(+), 3 deletions(-)
diff --git a/FireGestures.idl b/FireGestures.idl
index 22c5e5b..47963b5 100644
--- a/FireGestures.idl
+++ b/FireGestures.idl
@@ -81,7 +81,7 @@ interface xdIGestureHandler : nsISupports
/**
* Get DOM element at the starting point of current mouse gesture.
*/
- readonly attribute nsIDOMEventTarget sourceNode;
+ attribute nsIVariant sourceNode;
/**
* This method starts to handle mouse gestures at |nsIDOMEventTarget|
@@ -129,6 +129,11 @@ interface xdIGestureObserver : nsISupports
*/
void onExtraGesture(in nsIDOMEvent event, in ACString aGestureType);
+ /**
+ * [e10s] Called when gesture handler requests to send message to remote browser.
+ */
+ void sendAsyncMessage(in AUTF8String name, in nsIVariant data);
+
};
diff --git a/chrome/content/firegestures/browser.js b/chrome/content/firegestures/browser.js
index 8f1d5b3..758993f 100644
--- a/chrome/content/firegestures/browser.js
+++ b/chrome/content/firegestures/browser.js
@@ -37,9 +37,19 @@ var FireGestures = {
this._statusTextField = gBrowser.getStatusPanel();
// disable built-in swipe gesture
window.removeEventListener("MozSwipeGesture", gGestureSupport, true);
+ // [e10s] load frame script into every browser in window
+ if (gMultiProcessBrowser) {
+ window.messageManager.loadFrameScript("chrome://firegestures/content/remote.js", true);
+ window.messageManager.addMessageListener("FireGesturesRemote:Response", this);
+ }
},
uninit: function() {
+ // [e10s] stop loading delayed frame script if exists
+ if (gMultiProcessBrowser) {
+ window.messageManager.removeDelayedFrameScript("chrome://firegestures/content/remote.js");
+ window.messageManager.removeMessageListener("FireGesturesRemote:Response", this);
+ }
if (this._gestureHandler) {
this._gestureHandler.detach();
this._gestureHandler = null;
@@ -52,6 +62,37 @@ var FireGestures = {
},
+ /* ::::: [e10s] ::::: */
+
+ // check whether the current browser is remote or not
+ get isRemote() {
+ return gBrowser.mCurrentBrowser.getAttribute("remote") == "true";
+ },
+
+ // send async message to remote browser
+ sendAsyncMessage: function(aName, aData) {
+ gBrowser.mCurrentBrowser.messageManager.sendAsyncMessage(aName, aData);
+ },
+
+ // receive message from remote browser
+ receiveMessage: function(aMsg) {
+ // #debug-begin
+ var val = aMsg.name + ":\n" + aMsg.data.toSource() + "\n" + (aMsg.objects.elt || aMsg.objects);
+ Services.console.logStringMessage(val);
+ // #debug-end
+ switch (aMsg.data.name) {
+ case "sourceNode":
+ // replace |sourceNode| of gesture handler by CPOW object
+ this._gestureHandler.sourceNode = aMsg.objects.elt;
+ break;
+ case "linkURLs":
+ this._linkURLs = aMsg.data.linkURLs;
+ break;
+ default:
+ }
+ },
+
+
/* ::::: xdIGestureObserver ::::: */
canStartGesture: function(event) {
@@ -117,11 +158,25 @@ var FireGestures = {
this.onMouseGesture(event, aGesture);
break;
case "keypress-start":
+ // [e10s]
+ if (this.isRemote) {
+ this._linkURLs = [];
+ this.sendAsyncMessage("FireGestures:KeypressStart", {});
+ return;
+ }
this.clearStatusText(0);
this._linkURLs = [];
this._linkElts = [];
break;
case "keypress-progress":
+ // [e10s]
+ if (this.isRemote) {
+ this.sendAsyncMessage("FireGestures:KeypressProgress", {
+ x: event.screenX - gBrowser.mCurrentBrowser.boxObject.screenX,
+ y: event.screenY - gBrowser.mCurrentBrowser.boxObject.screenY,
+ });
+ return;
+ }
var linkURL = this.getLinkURL(event.target);
if (!this._linkURLs)
this._linkURLs = [];
@@ -136,6 +191,12 @@ var FireGestures = {
}
break;
case "keypress-stop":
+ // [e10s]
+ if (this.isRemote) {
+ this._linkURLs = null;
+ this.sendAsyncMessage("FireGestures:KeypressStop", {});
+ return;
+ }
for (var i = 0; i < this._linkURLs.length; i++) {
this._linkElts[i].style.outline = "";
this._linkElts[i] = null; // just in case
diff --git a/chrome/content/firegestures/remote.js b/chrome/content/firegestures/remote.js
new file mode 100644
index 0000000..69af8b7
--- /dev/null
+++ b/chrome/content/firegestures/remote.js
@@ -0,0 +1,291 @@
+//////////////////////////////////////////////////
+// FireGesturesRemote
+
+let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm");
+
+// #debug-begin
+Cu.import("resource://gre/modules/Services.jsm");
+function log(aText) {
+ Services.console.logStringMessage("FireGesturesRemote> " + aText);
+}
+// #debug-end
+
+let FireGesturesRemote = {
+
+ init: function FGR_init() {
+ log("init: " + new Date().toLocaleTimeString()); // #debug
+ addMessageListener("FireGestures:GestureStart", this);
+ addMessageListener("FireGestures:KeypressStart", this);
+ addMessageListener("FireGestures:KeypressProgress", this);
+ addMessageListener("FireGestures:KeypressStop", this);
+ addMessageListener("FireGestures:ContextMenu", this);
+ addMessageListener("FireGestures:DoCommand", this);
+ addMessageListener("FireGestures:SendKeyEvent", this);
+ addMessageListener("FireGestures:CreateTrail", this);
+ addMessageListener("FireGestures:DrawTrail", this);
+ addMessageListener("FireGestures:EraseTrail", this);
+ },
+
+ receiveMessage: function FGR_receiveMessage(aMsg) {
+ // log("receiveMessage: " + aMsg.name + "\t" + aMsg.data.toSource()); // #debug
+ switch (aMsg.name) {
+ case "FireGestures:GestureStart" : this._onGestureStart(aMsg.data); break;
+ case "FireGestures:KeypressStart" : this._onKeypressStart(); break;
+ case "FireGestures:KeypressProgress": this._onKeypressProgress(aMsg.data); break;
+ case "FireGestures:KeypressStop" : this._onKeypressStop(); break;
+ case "FireGestures:ContextMenu" : this._displayContextMenu(aMsg.data); break;
+ case "FireGestures:DoCommand" : this._doCommand(aMsg.data); break;
+ case "FireGestures:SendKeyEvent": this._sendKeyEvent(aMsg.data); break;
+ case "FireGestures:CreateTrail" : this._createTrail(aMsg.data); break;
+ case "FireGestures:DrawTrail" : this._drawTrail(aMsg.data); break;
+ case "FireGestures:EraseTrail" : this._eraseTrail(); break;
+ }
+ },
+
+
+ /* ::::: Mouse Gesture ::::: */
+
+ // coordinates which the gesture starts, originated on the left-upper corner of browser
+ _startX: 0,
+ _startY: 0,
+
+ _onGestureStart: function FGR__onGestureStart(aData) {
+ log("onStartGesture: " + aData.toSource()); // #debug
+ this._startX = aData.x;
+ this._startY = aData.y;
+ let { doc: doc, elt: elt } = this._elementFromPoint(aData.x, aData.y);
+ if (aData.button == 0) {
+ // [ToDo] get the element under mouse pointer with the use of document.elementFromPoint
+ // if the element is scrollbar, cancel starting gesture
+ // select event should be cancelled
+ }
+ else if (aData.button == 1) {
+ // [ToDo] cancel auto-scrolling?
+ }
+ // tell parent browser the source node and some info
+ sendSyncMessage("FireGesturesRemote:Response", { name: "sourceNode" }, { elt: elt });
+ },
+
+
+ /* ::::: Keypress Gesture ::::: */
+
+ _linkURLs: null,
+ _linkElts: null,
+
+ _onKeypressStart: function FGR__onKeypressStart() {
+ this._linkURLs = [];
+ this._linkElts = [];
+ },
+
+ _onKeypressProgress: function FGR__onKeypressProgress(aData) {
+ let { doc: doc, elt: elt } = this._elementFromPoint(aData.x, aData.y);
+ let linkURL = this.getLinkURL(elt);
+ if (!this._linkURLs)
+ this._linkURLs = [];
+ if (!linkURL || this._linkURLs.indexOf(linkURL) >= 0)
+ return;
+ try {
+ BrowserUtils.urlSecurityCheck(linkURL, doc.nodePrincipal);
+ }
+ catch(ex) {
+ // unsafe link
+ return;
+ }
+ this._linkURLs.push(linkURL);
+ this._linkElts.push(elt);
+ elt.style.outline = "1px dashed darkorange";
+ // tell parent browser the array of link URL
+ sendSyncMessage("FireGesturesRemote:Response", { name: "linkURLs", linkURLs: this._linkURLs });
+ },
+
+ _onKeypressStop: function FGR__onKeypressStop() {
+ for (let i = 0; i < this._linkURLs.length; i++) {
+ this._linkElts[i].style.outline = "";
+ this._linkElts[i] = null; // just in case
+ }
+ this._linkURLs = null;
+ this._linkElts = null;
+ },
+
+ getLinkURL: function FGR_getLinkURL(aNode) {
+ while (aNode) {
+ if (aNode instanceof Ci.nsIDOMHTMLAnchorElement || aNode instanceof Ci.nsIDOMHTMLAreaElement) {
+ if (aNode.href)
+ return aNode.href;
+ }
+ aNode = aNode.parentNode;
+ }
+ // not on a link
+ return null;
+ },
+
+
+ /* ::::: Commands ::::: */
+
+ _displayContextMenu: function FGR__displayContextMenu(aData) {
+ // log("_displayContextMenu: " + aData.toSource()); // #debug
+ let { doc: doc, elt: elt, x: x, y: y } = this._elementFromPoint(aData.x, aData.y);
+ // open the context menu artificially
+ let evt = doc.createEvent("MouseEvents");
+ evt.initMouseEvent(
+ "contextmenu", true, true, doc.defaultView, 0,
+ aData.x, aData.y, x, y,
+ false, false, false, false, 2, null
+ );
+ elt.dispatchEvent(evt);
+ },
+
+ _doCommand: function FGR__doCommand(aData) {
+ if (docShell.isCommandEnabled(aData.cmd))
+ docShell.doCommand(aData.cmd);
+ },
+
+ _sendKeyEvent: function FGR__sendKeyEvent(aOptions) {
+ let { elt: elt, doc: doc } = this._elementFromPoint(this._startX, this._startY);
+ let evt = doc.createEvent("KeyEvents");
+ evt.initKeyEvent(
+ "keypress", true, true, null,
+ aOptions.ctrl || false,
+ aOptions.alt || false,
+ aOptions.shift || false,
+ aOptions.meta || false,
+ aOptions.keyCode ? evt[aOptions.keyCode] : null,
+ aOptions.key ? aOptions.key.charCodeAt(0) : null
+ );
+ elt.dispatchEvent(evt);
+ },
+
+
+ /* ::::: Utils ::::: */
+
+// // returns DOM element and some related data which is under the mouse pointer
+// _elementAtPointer: function FGR__elementAtPointer() {
+// let doc = content.document;
+// let elt = doc.querySelector(":hover") || doc.body || doc.documentElement;
+// while (/^i?frame$/.test(elt.localName.toLowerCase())) {
+// doc = elt.contentDocument;
+// elt = doc.querySelector(":hover");
+// }
+// log("_elementAtPointer: " + [doc.location, elt.localName].join(", ")); // #debug
+// return elt;
+// },
+
+ // returns DOM element and some data related which is located at given coordinates
+ _elementFromPoint: function FGR__elementFromPoint(x, y) {
+ let doc = content.document;
+ let elt = doc.elementFromPoint(x, y) || doc.body || doc.documentElement;
+ while (/^i?frame$/.test(elt.localName.toLowerCase())) {
+ x -= elt.getBoundingClientRect().left;
+ y -= elt.getBoundingClientRect().top;
+ doc = elt.contentDocument;
+ elt = doc.elementFromPoint(x, y);
+ }
+ // log("_elementFromPoint: " + [doc.location, elt.localName, x, y].join(", ")); // #debug
+ return { doc: doc, elt: elt, x: x, y: y };
+ },
+
+
+ /* ::::: Mouse Trail ::::: */
+
+ _trailSize: 0,
+ _trailColor: "",
+ _trailZoom: 1,
+ _trailDot: null,
+ _trailArea: null,
+ _trailLastDot: null,
+ _trailOffsetX: 0,
+ _trailOffsetY: 0,
+
+ _createTrail: function FGR__createTrail(aData) {
+ let win = content.window;
+ let doc = content.document;
+ this._trailSize = aData.size;
+ this._trailColor = aData.color;
+ this._trailZoom = aData.zoom;
+ this._trailOffsetX = (win.mozInnerScreenX - win.scrollX) * this._trailZoom;
+ this._trailOffsetY = (win.mozInnerScreenY - win.scrollY) * this._trailZoom;
+ this._trailArea = doc.createElementNS(HTML_NS, "xdTrailArea");
+ (doc.documentElement || doc).appendChild(this._trailArea);
+ this._trailDot = doc.createElementNS(HTML_NS, "xdTrailDot");
+ this._trailDot.style.width = this._trailSize + "px";
+ this._trailDot.style.height = this._trailSize + "px";
+ this._trailDot.style.background = this._trailColor;
+ this._trailDot.style.border = "0px";
+ this._trailDot.style.position = "absolute";
+ this._trailDot.style.zIndex = 2147483647;
+ },
+
+ _drawTrail: function FGR__drawTrail(aData) {
+ if (!this._trailArea)
+ return;
+ let x1 = aData.x1, y1 = aData.y1, x2 = aData.x2, y2 = aData.y2;
+ let xMove = x2 - x1;
+ let yMove = y2 - y1;
+ let xDecrement = xMove < 0 ? 1 : -1;
+ let yDecrement = yMove < 0 ? 1 : -1;
+ x2 -= this._trailOffsetX;
+ y2 -= this._trailOffsetY;
+ if (Math.abs(xMove) >= Math.abs(yMove))
+ for (let i = xMove; i != 0; i += xDecrement)
+ this._strokeDot(x2 - i, y2 - Math.round(yMove * i / xMove));
+ else
+ for (let i = yMove; i != 0; i += yDecrement)
+ this._strokeDot(x2 - Math.round(xMove * i / yMove), y2 - i);
+ },
+
+ _eraseTrail: function FGR__eraseTrail() {
+ if (this._trailArea && this._trailArea.parentNode) {
+ while (this._trailArea.lastChild)
+ this._trailArea.removeChild(this._trailArea.lastChild);
+ this._trailArea.parentNode.removeChild(this._trailArea);
+ }
+ this._trailDot = null;
+ this._trailArea = null;
+ this._trailLastDot = null;
+ },
+
+ _strokeDot: function FGR__strokeDot(x, y) {
+ if (this._trailArea.y == y && this._trailArea.h == this._trailSize) {
+ // draw vertical line
+ let newX = Math.min(this._trailArea.x, x);
+ let newW = Math.max(this._trailArea.x + this._trailArea.w, x + this._trailSize) - newX;
+ this._trailArea.x = newX;
+ this._trailArea.w = newW;
+ this._trailLastDot.style.left = newX.toString() + "px";
+ this._trailLastDot.style.width = newW.toString() + "px";
+ return;
+ }
+ else if (this._trailArea.x == x && this._trailArea.w == this._trailSize) {
+ // draw horizontal line
+ let newY = Math.min(this._trailArea.y, y);
+ let newH = Math.max(this._trailArea.y + this._trailArea.h, y + this._trailSize) - newY;
+ this._trailArea.y = newY;
+ this._trailArea.h = newH;
+ this._trailLastDot.style.top = newY.toString() + "px";
+ this._trailLastDot.style.height = newH.toString() + "px";
+ return;
+ }
+ if (this._trailZoom != 1) {
+ x = Math.floor(x / this._trailZoom);
+ y = Math.floor(y / this._trailZoom);
+ }
+ let dot = this._trailDot.cloneNode(true);
+ dot.style.left = x + "px";
+ dot.style.top = y + "px";
+ this._trailArea.x = x;
+ this._trailArea.y = y;
+ this._trailArea.w = this._trailSize;
+ this._trailArea.h = this._trailSize;
+ this._trailArea.appendChild(dot);
+ this._trailLastDot = dot;
+ },
+
+};
+
+FireGesturesRemote.init();
+
diff --git a/components/FireGestures.xpt b/components/FireGestures.xpt
index 4341b48..3e4b033 100644
Binary files a/components/FireGestures.xpt and b/components/FireGestures.xpt differ
diff --git a/components/xdGestureHandler.js b/components/xdGestureHandler.js
index 255ee16..c33623b 100644
--- a/components/xdGestureHandler.js
+++ b/components/xdGestureHandler.js
@@ -73,6 +73,9 @@ xdGestureHandler.prototype = {
// xdIGestureObserver
_gestureObserver: null,
+ // [e10s] a flag to indicate whether the current browser is remote or not
+ _isRemote: false,
+
attach: function FGH_attach(aDrawArea, aObserver) {
var appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
this._drawArea = aDrawArea;
@@ -212,7 +215,8 @@ xdGestureHandler.prototype = {
this._state = STATE_GESTURE;
this._startGesture(event);
// prevent selecting (only if mouse gesture is enabled)
- if (this._mouseGestureEnabled)
+ // [e10s] don't prevent in remote mode since event.target always becomes to xul:tabbrowser
+ if (!this._isRemote && this._mouseGestureEnabled)
event.preventDefault();
}
// rocker gesture
@@ -441,6 +445,14 @@ xdGestureHandler.prototype = {
}
}
this._enableContextMenu(true);
+ if (this._isRemote) {
+ // [e10s] display context menu on remote browser
+ this._gestureObserver.sendAsyncMessage("FireGestures:ContextMenu", {
+ x: event.screenX - this._drawArea.mCurrentBrowser.boxObject.screenX,
+ y: event.screenY - this._drawArea.mCurrentBrowser.boxObject.screenY,
+ });
+ return;
+ }
// open the context menu artificially
var evt = event.originalTarget.ownerDocument.createEvent("MouseEvents");
evt.initMouseEvent(
@@ -482,7 +494,9 @@ xdGestureHandler.prototype = {
// called from handleEvent (type is "mousedown")
_startGesture: function FGH__startGesture(event) {
- log("_startGesture()"); // #debug
+ if (this._drawArea.localName == "tabbrowser")
+ this._isRemote = this._drawArea.mCurrentBrowser.getAttribute("remote") == "true";
+ log("_startGesture(" + event.target.localName + ") " + (this._isRemote ? "[e10s]" : "")); // #debug
this.sourceNode = event.target;
this._lastX = event.screenX;
this._lastY = event.screenY;
@@ -491,6 +505,14 @@ xdGestureHandler.prototype = {
// trail drawing
if (this._trailEnabled)
this.createTrail(event);
+ // [e10s] tell remote browser that mouse gesture has started
+ if (this._isRemote) {
+ this._gestureObserver.sendAsyncMessage("FireGestures:GestureStart", {
+ button: event.button,
+ x: event.screenX - this._drawArea.mCurrentBrowser.boxObject.screenX,
+ y: event.screenY - this._drawArea.mCurrentBrowser.boxObject.screenY,
+ });
+ }
},
// called from handleEvent (type is "mousemove")
@@ -649,6 +671,15 @@ xdGestureHandler.prototype = {
// called from _startGesture
createTrail: function FGH_createTrail(event) {
+ if (this._isRemote) {
+ // [e10s]
+ this._gestureObserver.sendAsyncMessage("FireGestures:CreateTrail", {
+ size : this._trailSize,
+ color: this._trailColor,
+ zoom : this._drawArea.fullZoom || 1,
+ });
+ return;
+ }
var win = this.sourceNode.ownerDocument.defaultView;
if (win.top.document instanceof Ci.nsIDOMHTMLDocument)
win = win.top;
@@ -671,6 +702,16 @@ xdGestureHandler.prototype = {
// called from _progressGesture
drawTrail: function FGH_drawTrail(x1, y1, x2, y2) {
+ if (this._isRemote) {
+ // [e10s]
+ this._gestureObserver.sendAsyncMessage("FireGestures:DrawTrail", {
+ x1: x1 - this._drawArea.mCurrentBrowser.boxObject.screenX,
+ y1: y1 - this._drawArea.mCurrentBrowser.boxObject.screenY,
+ x2: x2 - this._drawArea.mCurrentBrowser.boxObject.screenX,
+ y2: y2 - this._drawArea.mCurrentBrowser.boxObject.screenY,
+ });
+ return;
+ }
if (!this._trailArea)
return;
var xMove = x2 - x1;
@@ -689,6 +730,11 @@ xdGestureHandler.prototype = {
// called from _stopGesture
eraseTrail: function FGH_eraseTrail() {
+ if (this._isRemote) {
+ // [e10s]
+ this._gestureObserver.sendAsyncMessage("FireGestures:EraseTrail", {});
+ return;
+ }
if (this._trailArea && this._trailArea.parentNode) {
while (this._trailArea.lastChild)
this._trailArea.removeChild(this._trailArea.lastChild);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/firegestures.git
More information about the Pkg-mozext-commits
mailing list