diff --git a/mobile/chrome/content/browser.js b/mobile/chrome/content/browser.js index 2766b3956db..fc677523eca 100644 --- a/mobile/chrome/content/browser.js +++ b/mobile/chrome/content/browser.js @@ -1501,6 +1501,7 @@ const ContentTouchHandler = { init: function init() { document.addEventListener("TapDown", this, true); + document.addEventListener("TapOver", this, false); document.addEventListener("TapUp", this, false); document.addEventListener("TapSingle", this, false); document.addEventListener("TapDouble", this, false); @@ -1554,6 +1555,9 @@ const ContentTouchHandler = { case "TapDown": this.tapDown(aEvent.clientX, aEvent.clientY); break; + case "TapOver": + this.tapOver(aEvent.clientX, aEvent.clientY); + break; case "TapUp": this.tapUp(aEvent.clientX, aEvent.clientY); break; @@ -1633,6 +1637,10 @@ const ContentTouchHandler = { this._dispatchMouseEvent("Browser:MouseDown", aX, aY); }, + tapOver: function tapOver(aX, aY) { + this._dispatchMouseEvent("Browser:MouseOver", aX, aY); + }, + tapUp: function tapUp(aX, aY) { TapHighlightHelper.hide(200); this._contextMenu = null; diff --git a/mobile/chrome/content/content.js b/mobile/chrome/content/content.js index 837c13b4581..c5dcfc85585 100644 --- a/mobile/chrome/content/content.js +++ b/mobile/chrome/content/content.js @@ -293,6 +293,7 @@ function Content() { addMessageListener("Browser:Blur", this); addMessageListener("Browser:KeyEvent", this); addMessageListener("Browser:MouseDown", this); + addMessageListener("Browser:MouseOver", this); addMessageListener("Browser:MouseUp", this); addMessageListener("Browser:SaveAs", this); addMessageListener("Browser:ZoomToPoint", this); @@ -377,6 +378,7 @@ Content.prototype = { case "Browser:Blur": gFocusManager.clearFocus(content); break; + case "Browser:KeyEvent": let utils = Util.getWindowUtils(content); let defaultAction; @@ -399,15 +401,6 @@ Content.prototype = { if (!element) return; - let highlightRects = null; - if (element.mozMatchesSelector("*:link,*:visited,*[role=button],button,input,option,select,textarea,label")) - highlightRects = getContentClientRects(element); - else if (element.mozMatchesSelector("*:link *, *:visited *")) - highlightRects = getContentClientRects(element.parentNode); - - if (highlightRects) - sendAsyncMessage("Browser:Highlight", { rects: highlightRects, messageId: json.messageId }); - ContextHandler.messageId = json.messageId; let event = content.document.createEvent("PopupEvents"); @@ -416,6 +409,27 @@ Content.prototype = { break; } + case "Browser:MouseOver": { + let element = elementFromPoint(x, y); + if (!element) + return; + + // Sending a mousemove force the dispatching of mouseover/mouseout + this._sendMouseEvent("mousemove", element, x, y); + + // XXX Could we replace all this javascript code by something CSS based + // using a mix on some -moz-focus-ring/-moz-focus-inner rules + let highlightRects = null; + if (element.mozMatchesSelector("*:-moz-any-link, *[role=button],button,input,option,select,textarea,label")) + highlightRects = getContentClientRects(element); + else if (element.mozMatchesSelector("*:-moz-any-link *")) + highlightRects = getContentClientRects(element.parentNode); + + if (highlightRects) + sendAsyncMessage("Browser:Highlight", { rects: highlightRects, messageId: json.messageId }); + break; + } + case "Browser:MouseUp": { this._formAssistant.focusSync = true; let element = elementFromPoint(x, y); @@ -488,7 +502,7 @@ Content.prototype = { sendAsyncMessage("Browser:ZoomToPoint:Return", { x: x, y: y, rect: rect }); break; } - + case "Browser:MozApplicationCache:Fetch": { let currentURI = Services.io.newURI(json.location, json.charset, null); let manifestURI = Services.io.newURI(json.manifest, json.charset, currentURI); diff --git a/mobile/chrome/content/input.js b/mobile/chrome/content/input.js index a0f407eacdc..86c53c40bf6 100644 --- a/mobile/chrome/content/input.js +++ b/mobile/chrome/content/input.js @@ -48,6 +48,9 @@ const kDoubleClickInterval = 400; // Maximum distance in inches between the taps of a double-tap const kDoubleClickRadius = 0.4; +// Amount of time to wait before tap is generate a mousemove +const kOverTapWait = 150; + // Amount of time to wait before tap becomes long tap const kLongTapWait = 500; @@ -102,6 +105,7 @@ function MouseModule() { this._kineticStop.bind(this)); this._singleClickTimeout = new Util.Timeout(this._doSingleClick.bind(this)); + this._mouseOverTimeout = new Util.Timeout(this._doMouseOver.bind(this)); this._longClickTimeout = new Util.Timeout(this._doLongClick.bind(this)); this._doubleClickRadius = Util.getWindowUtils(window).displayDPI * kDoubleClickRadius; @@ -207,6 +211,7 @@ MouseModule.prototype = { if (success) { this._recordEvent(aEvent); this._target = aEvent.target; + this._mouseOverTimeout.once(kOverTapWait); this._longClickTimeout.once(kLongTapWait); } else { // cancel all pending content clicks @@ -266,6 +271,7 @@ MouseModule.prototype = { } } + this._mouseOverTimeout.clear(); this._longClickTimeout.clear(); this._target = null; @@ -303,6 +309,7 @@ MouseModule.prototype = { // Let everyone know when mousemove begins a pan if (!oldIsPan && dragData.isPan()) { + this._mouseOverTimeout.clear(); this._longClickTimeout.clear(); let event = document.createEvent("Events"); @@ -401,6 +408,12 @@ MouseModule.prototype = { } }, + /** Called when tap down times is long enought to generate a mousemove **/ + _doMouseOver: function _doMouseOver() { + let ev = this._downUpEvents[0]; + this._dispatchTap("TapOver", ev); + }, + /** Called when tap down times out and becomes a long tap. */ _doLongClick: function _doLongClick() { let ev = this._downUpEvents[0]; @@ -480,6 +493,7 @@ MouseModule.prototype = { */ _cleanClickBuffer: function _cleanClickBuffer() { this._singleClickTimeout.clear(); + this._mouseOverTimeout.clear(); this._longClickTimeout.clear(); this._downUpEvents.splice(0); },