[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