зеркало из https://github.com/mozilla/gecko-dev.git
Bug 544614 - Touch Events [r=mfinkle, bstover]
This commit is contained in:
Родитель
df4a6c7a1b
Коммит
1c4760b2d3
|
@ -584,6 +584,9 @@ pref("image.mem.decodeondraw", true);
|
||||||
pref("content.image.allow_locking", false);
|
pref("content.image.allow_locking", false);
|
||||||
pref("image.mem.min_discard_timeout_ms", 20000);
|
pref("image.mem.min_discard_timeout_ms", 20000);
|
||||||
|
|
||||||
|
// enable touch events interfaces
|
||||||
|
pref("dom.w3c_touch_events.enabled", true);
|
||||||
|
|
||||||
#ifdef MOZ_SAFE_BROWSING
|
#ifdef MOZ_SAFE_BROWSING
|
||||||
// Safe browsing does nothing unless this pref is set
|
// Safe browsing does nothing unless this pref is set
|
||||||
pref("browser.safebrowsing.enabled", true);
|
pref("browser.safebrowsing.enabled", true);
|
||||||
|
@ -633,4 +636,5 @@ pref("urlclassifier.updatecachemax", 4194304);
|
||||||
|
|
||||||
// URL for checking the reason for a malware warning.
|
// URL for checking the reason for a malware warning.
|
||||||
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1197,6 +1197,10 @@ Browser.MainDragger = function MainDragger() {
|
||||||
|
|
||||||
Elements.browsers.addEventListener("PanBegin", this, false);
|
Elements.browsers.addEventListener("PanBegin", this, false);
|
||||||
Elements.browsers.addEventListener("PanFinished", this, false);
|
Elements.browsers.addEventListener("PanFinished", this, false);
|
||||||
|
|
||||||
|
// allow pages to to override panning, but should
|
||||||
|
// still allow the sidebars to be panned out of view
|
||||||
|
this.contentMouseCapture = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Browser.MainDragger.prototype = {
|
Browser.MainDragger.prototype = {
|
||||||
|
@ -1227,48 +1231,42 @@ Browser.MainDragger.prototype = {
|
||||||
dragMove: function dragMove(dx, dy, scroller, aIsKinetic) {
|
dragMove: function dragMove(dx, dy, scroller, aIsKinetic) {
|
||||||
let doffset = new Point(dx, dy);
|
let doffset = new Point(dx, dy);
|
||||||
|
|
||||||
// First calculate any panning to take sidebars out of view
|
// If the sidebars are showing, we pan them out of the way before panning the content.
|
||||||
let panOffset = this._panControlsAwayOffset(doffset);
|
// The panning distance that should be used for the sidebars in is stored in sidebarOffset,
|
||||||
|
// and subtracted from doffset
|
||||||
|
let sidebarOffset = this._getSidebarOffset(doffset);
|
||||||
|
|
||||||
// If we started at one sidebar, stop when we get to the other.
|
// If we started with one sidebar open, stop when we get to the other.
|
||||||
if (panOffset.x != 0 && !this._stopAtSidebar) {
|
if (sidebarOffset.x != 0)
|
||||||
this._stopAtSidebar = panOffset.x; // negative: stop at left; positive: stop at right
|
this._blockSidebars(sidebarOffset);
|
||||||
|
|
||||||
|
if (!this.contentMouseCapture)
|
||||||
|
this._panContent(doffset);
|
||||||
|
|
||||||
|
if (this._hitSidebar && aIsKinetic)
|
||||||
|
return false; // No kinetic panning after we've stopped at the sidebar.
|
||||||
|
|
||||||
|
// allow panning the sidebars if the page hasn't prevented it, or if any of the sidebars are showing
|
||||||
|
// (i.e. we always allow panning sidebars off screen but not necessarily panning them back on)
|
||||||
|
if (!this.contentMouseCapture || sidebarOffset.x != 0 || sidebarOffset.y > 0)
|
||||||
|
this._panChrome(doffset, sidebarOffset);
|
||||||
|
|
||||||
|
this._updateScrollbars();
|
||||||
|
|
||||||
|
return !doffset.equals(dx, dy);
|
||||||
|
},
|
||||||
|
|
||||||
|
_blockSidebars: function md_blockSidebars(aSidebarOffset) {
|
||||||
|
// only call this code once
|
||||||
|
if (!this._stopAtSidebar) {
|
||||||
|
this._stopAtSidebar = aSidebarOffset.x; // negative: stop at left; positive: stop at right
|
||||||
|
|
||||||
|
// after a timeout, we allow showing the sidebar, to give the appearance of some "friction" at the edge
|
||||||
this._sidebarTimeout = setTimeout(function(self) {
|
this._sidebarTimeout = setTimeout(function(self) {
|
||||||
self._stopAtSidebar = 0;
|
self._stopAtSidebar = 0;
|
||||||
self._sidebarTimeout = null;
|
self._sidebarTimeout = null;
|
||||||
}, 350, this);
|
}, 350, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._contentView && !this._contentView.isRoot()) {
|
|
||||||
this._panContentView(this._contentView, doffset);
|
|
||||||
// XXX we may need to have "escape borders" for iframe panning
|
|
||||||
// XXX does not deal with scrollables within scrollables
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do content panning
|
|
||||||
this._panContentView(getBrowser().getRootView(), doffset);
|
|
||||||
|
|
||||||
if (this._hitSidebar && aIsKinetic)
|
|
||||||
return; // No kinetic panning after we've stopped at the sidebar.
|
|
||||||
|
|
||||||
// Any leftover panning in doffset would bring controls into view. Add to sidebar
|
|
||||||
// away panning for the total scroll offset.
|
|
||||||
let offsetX = doffset.x;
|
|
||||||
if ((this._stopAtSidebar > 0 && offsetX > 0) ||
|
|
||||||
(this._stopAtSidebar < 0 && offsetX < 0)) {
|
|
||||||
if (offsetX != panOffset.x)
|
|
||||||
this._hitSidebar = true;
|
|
||||||
doffset.x = panOffset.x;
|
|
||||||
} else {
|
|
||||||
doffset.add(panOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
Browser.tryFloatToolbar(doffset.x, 0);
|
|
||||||
this._panScroller(Browser.controlsScrollboxScroller, doffset);
|
|
||||||
this._panScroller(Browser.pageScrollboxScroller, doffset);
|
|
||||||
this._updateScrollbars();
|
|
||||||
|
|
||||||
return !doffset.equals(dx, dy);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleEvent: function handleEvent(aEvent) {
|
handleEvent: function handleEvent(aEvent) {
|
||||||
|
@ -1299,8 +1297,38 @@ Browser.MainDragger.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_panContent: function md_panContent(aOffset) {
|
||||||
|
if (this._contentView && !this._contentView.isRoot()) {
|
||||||
|
this._panContentView(this._contentView, aOffset);
|
||||||
|
// XXX we may need to have "escape borders" for iframe panning
|
||||||
|
// XXX does not deal with scrollables within scrollables
|
||||||
|
}
|
||||||
|
// Do content panning
|
||||||
|
this._panContentView(getBrowser().getRootView(), aOffset);
|
||||||
|
},
|
||||||
|
|
||||||
|
_panChrome: function md_panSidebars(aOffset, aSidebarOffset) {
|
||||||
|
// Any panning aOffset would bring controls into view. Add to aSidebarOffset
|
||||||
|
let offsetX = aOffset.x;
|
||||||
|
if ((this._stopAtSidebar > 0 && offsetX > 0) ||
|
||||||
|
(this._stopAtSidebar < 0 && offsetX < 0)) {
|
||||||
|
if (offsetX != aSidebarOffset.x)
|
||||||
|
this._hitSidebar = true;
|
||||||
|
aOffset.x = aSidebarOffset.x;
|
||||||
|
} else {
|
||||||
|
aOffset.add(aSidebarOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Browser.tryFloatToolbar(aOffset.x, 0);
|
||||||
|
|
||||||
|
// pan the sidebars
|
||||||
|
this._panScroller(Browser.controlsScrollboxScroller, aOffset);
|
||||||
|
// pan the urlbar
|
||||||
|
this._panScroller(Browser.pageScrollboxScroller, aOffset);
|
||||||
|
},
|
||||||
|
|
||||||
/** Return offset that pans controls away from screen. Updates doffset with leftovers. */
|
/** Return offset that pans controls away from screen. Updates doffset with leftovers. */
|
||||||
_panControlsAwayOffset: function(doffset) {
|
_getSidebarOffset: function(doffset) {
|
||||||
let x = 0, y = 0, rect;
|
let x = 0, y = 0, rect;
|
||||||
|
|
||||||
rect = Rect.fromRect(Browser.pageScrollbox.getBoundingClientRect()).map(Math.round);
|
rect = Rect.fromRect(Browser.pageScrollbox.getBoundingClientRect()).map(Math.round);
|
||||||
|
@ -1603,6 +1631,7 @@ const ContentTouchHandler = {
|
||||||
document.addEventListener("TapSingle", this, false);
|
document.addEventListener("TapSingle", this, false);
|
||||||
document.addEventListener("TapDouble", this, false);
|
document.addEventListener("TapDouble", this, false);
|
||||||
document.addEventListener("TapLong", this, false);
|
document.addEventListener("TapLong", this, false);
|
||||||
|
document.addEventListener("TapMove", this, false);
|
||||||
|
|
||||||
document.addEventListener("PanBegin", this, false);
|
document.addEventListener("PanBegin", this, false);
|
||||||
document.addEventListener("PopupChanged", this, false);
|
document.addEventListener("PopupChanged", this, false);
|
||||||
|
@ -1619,8 +1648,8 @@ const ContentTouchHandler = {
|
||||||
// a long tap, without waiting for child process.
|
// a long tap, without waiting for child process.
|
||||||
//
|
//
|
||||||
messageManager.addMessageListener("Browser:ContextMenu", this);
|
messageManager.addMessageListener("Browser:ContextMenu", this);
|
||||||
|
|
||||||
messageManager.addMessageListener("Browser:Highlight", this);
|
messageManager.addMessageListener("Browser:Highlight", this);
|
||||||
|
messageManager.addMessageListener("Browser:CaptureEvents", this);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleEvent: function handleEvent(aEvent) {
|
handleEvent: function handleEvent(aEvent) {
|
||||||
|
@ -1661,12 +1690,12 @@ const ContentTouchHandler = {
|
||||||
this.tapSingle(aEvent.clientX, aEvent.clientY, aEvent.modifiers);
|
this.tapSingle(aEvent.clientX, aEvent.clientY, aEvent.modifiers);
|
||||||
aEvent.preventDefault();
|
aEvent.preventDefault();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.tapUp(aEvent.clientX, aEvent.clientY);
|
|
||||||
}
|
}
|
||||||
|
this._dispatchMouseEvent("Browser:MouseUp", aEvent.clientX, aEvent.clientY);
|
||||||
break;
|
break;
|
||||||
case "TapSingle":
|
case "TapSingle":
|
||||||
this.tapSingle(aEvent.clientX, aEvent.clientY, aEvent.modifiers);
|
this.tapSingle(aEvent.clientX, aEvent.clientY, aEvent.modifiers);
|
||||||
|
this._dispatchMouseEvent("Browser:MouseUp", aEvent.clientX, aEvent.clientY);
|
||||||
break;
|
break;
|
||||||
case "TapDouble":
|
case "TapDouble":
|
||||||
this.tapDouble(aEvent.clientX, aEvent.clientY, aEvent.modifiers);
|
this.tapDouble(aEvent.clientX, aEvent.clientY, aEvent.modifiers);
|
||||||
|
@ -1674,6 +1703,9 @@ const ContentTouchHandler = {
|
||||||
case "TapLong":
|
case "TapLong":
|
||||||
this.tapLong(aEvent.clientX, aEvent.clientY);
|
this.tapLong(aEvent.clientX, aEvent.clientY);
|
||||||
break;
|
break;
|
||||||
|
case "TapMove":
|
||||||
|
this.tapMove(aEvent.clientX, aEvent.clientY);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1694,6 +1726,9 @@ const ContentTouchHandler = {
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "Browser:CaptureEvents":
|
||||||
|
Elements.browsers.customDragger.contentMouseCapture = aMessage.json.panning;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1735,6 +1770,7 @@ const ContentTouchHandler = {
|
||||||
try {
|
try {
|
||||||
fl.activateRemoteFrame();
|
fl.activateRemoteFrame();
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
Elements.browsers.customDragger.contentMouseCapture = false;
|
||||||
this._dispatchMouseEvent("Browser:MouseDown", aX, aY);
|
this._dispatchMouseEvent("Browser:MouseDown", aX, aY);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1750,7 +1786,11 @@ const ContentTouchHandler = {
|
||||||
tapSingle: function tapSingle(aX, aY, aModifiers) {
|
tapSingle: function tapSingle(aX, aY, aModifiers) {
|
||||||
// Cancel the mouse click if we are showing a context menu
|
// Cancel the mouse click if we are showing a context menu
|
||||||
if (!ContextHelper.popupState)
|
if (!ContextHelper.popupState)
|
||||||
this._dispatchMouseEvent("Browser:MouseUp", aX, aY, { modifiers: aModifiers });
|
this._dispatchMouseEvent("Browser:MouseClick", aX, aY, { modifiers: aModifiers });
|
||||||
|
},
|
||||||
|
|
||||||
|
tapMove: function tapMove(aX, aY) {
|
||||||
|
this._dispatchMouseEvent("Browser:MouseMove", aX, aY);
|
||||||
},
|
},
|
||||||
|
|
||||||
tapDouble: function tapDouble(aX, aY, aModifiers) {
|
tapDouble: function tapDouble(aX, aY, aModifiers) {
|
||||||
|
@ -2733,7 +2773,7 @@ Tab.prototype = {
|
||||||
// If the scale level has not changed we want to be sure the content
|
// If the scale level has not changed we want to be sure the content
|
||||||
// render correctly since the page refresh process could have been
|
// render correctly since the page refresh process could have been
|
||||||
// stalled during page load. In this case if the page has the exact
|
// stalled during page load. In this case if the page has the exact
|
||||||
// same width (like the same page, so by doing 'refresh') and the
|
// same width (like the same page, so by doing 'refresh') and the
|
||||||
// page was scrolled the content is just checkerboard at this point
|
// page was scrolled the content is just checkerboard at this point
|
||||||
// and this call ensure we render it correctly.
|
// and this call ensure we render it correctly.
|
||||||
browser.getRootView()._updateCacheViewport();
|
browser.getRootView()._updateCacheViewport();
|
||||||
|
|
|
@ -262,7 +262,7 @@ let Content = {
|
||||||
addMessageListener("Browser:MouseOver", this);
|
addMessageListener("Browser:MouseOver", this);
|
||||||
addMessageListener("Browser:MouseLong", this);
|
addMessageListener("Browser:MouseLong", this);
|
||||||
addMessageListener("Browser:MouseDown", this);
|
addMessageListener("Browser:MouseDown", this);
|
||||||
addMessageListener("Browser:MouseUp", this);
|
addMessageListener("Browser:MouseClick", this);
|
||||||
addMessageListener("Browser:MouseCancel", this);
|
addMessageListener("Browser:MouseCancel", this);
|
||||||
addMessageListener("Browser:SaveAs", this);
|
addMessageListener("Browser:SaveAs", this);
|
||||||
addMessageListener("Browser:ZoomToPoint", this);
|
addMessageListener("Browser:ZoomToPoint", this);
|
||||||
|
@ -474,15 +474,17 @@ let Content = {
|
||||||
|
|
||||||
ContextHandler.messageId = json.messageId;
|
ContextHandler.messageId = json.messageId;
|
||||||
|
|
||||||
let event = content.document.createEvent("PopupEvents");
|
let event = content.document.createEvent("MouseEvent");
|
||||||
event.initEvent("contextmenu", true, true);
|
event.initMouseEvent("contextmenu", true, true, content,
|
||||||
|
0, x, y, x, y, false, false, false, false,
|
||||||
|
0, null);
|
||||||
event.x = x;
|
event.x = x;
|
||||||
event.y = y;
|
event.y = y;
|
||||||
element.dispatchEvent(event);
|
element.dispatchEvent(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "Browser:MouseUp": {
|
case "Browser:MouseClick": {
|
||||||
this._formAssistant.focusSync = true;
|
this._formAssistant.focusSync = true;
|
||||||
let element = elementFromPoint(x, y);
|
let element = elementFromPoint(x, y);
|
||||||
if (modifiers == Ci.nsIDOMNSEvent.CONTROL_MASK) {
|
if (modifiers == Ci.nsIDOMNSEvent.CONTROL_MASK) {
|
||||||
|
@ -1188,3 +1190,63 @@ var ConsoleAPIObserver = {
|
||||||
};
|
};
|
||||||
|
|
||||||
ConsoleAPIObserver.init();
|
ConsoleAPIObserver.init();
|
||||||
|
|
||||||
|
var TouchEventHandler = {
|
||||||
|
element: null,
|
||||||
|
init: function() {
|
||||||
|
addMessageListener("Browser:MouseUp", this);
|
||||||
|
addMessageListener("Browser:MouseDown", this);
|
||||||
|
addMessageListener("Browser:MouseMove", this);
|
||||||
|
},
|
||||||
|
|
||||||
|
receiveMessage: function(aMessage) {
|
||||||
|
if (Util.isParentProcess())
|
||||||
|
return;
|
||||||
|
|
||||||
|
let json = aMessage.json;
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
switch (aMessage.name) {
|
||||||
|
case "Browser:MouseDown":
|
||||||
|
let cwu = Util.getWindowUtils(content);
|
||||||
|
this.element = cwu.elementFromPoint(json.x, json.y, false, false);
|
||||||
|
cancelled = !this.sendEvent("touchstart", json, this.element);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Browser:MouseUp":
|
||||||
|
if (this.element)
|
||||||
|
this.sendEvent("touchend", json, this.element);
|
||||||
|
this.element = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Browser:MouseMove":
|
||||||
|
if (this.element)
|
||||||
|
cancelled = !this.sendEvent("touchmove", json, this.element);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancelled)
|
||||||
|
sendAsyncMessage("Browser:CaptureEvents", { messageId: json.messageId,
|
||||||
|
panning: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
sendEvent: function(aName, aData, aElement) {
|
||||||
|
if (!Services.prefs.getBoolPref("dom.w3c_touch_events.enabled"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
let evt = content.document.createEvent("touchevent");
|
||||||
|
let point = content.document.createTouch(content, aElement, 0,
|
||||||
|
aData.x, aData.y, aData.x, aData.y, aData.x, aData.y,
|
||||||
|
1, 1, 0, 0);
|
||||||
|
let touches = content.document.createTouchList(point);
|
||||||
|
if (aName == "touchend") {
|
||||||
|
let empty = content.document.createTouchList();
|
||||||
|
evt.initTouchEvent(aName, true, true, content, 0, true, true, true, true, empty, empty, touches);
|
||||||
|
} else {
|
||||||
|
evt.initTouchEvent(aName, true, true, content, 0, true, true, true, true, touches, touches, touches);
|
||||||
|
}
|
||||||
|
return aElement.dispatchEvent(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TouchEventHandler.init();
|
||||||
|
|
|
@ -335,6 +335,7 @@ MouseModule.prototype = {
|
||||||
this.dY += dragData.prevPanY - sY;
|
this.dY += dragData.prevPanY - sY;
|
||||||
|
|
||||||
if (dragData.isPan()) {
|
if (dragData.isPan()) {
|
||||||
|
this.sendMove(aEvent.clientX, aEvent.clientY, aEvent.target);
|
||||||
// Only pan when mouse event isn't part of a click. Prevent jittering on tap.
|
// Only pan when mouse event isn't part of a click. Prevent jittering on tap.
|
||||||
this._kinetic.addData(sX - dragData.prevPanX, sY - dragData.prevPanY);
|
this._kinetic.addData(sX - dragData.prevPanX, sY - dragData.prevPanY);
|
||||||
this._dragBy(this.dX, this.dY);
|
this._dragBy(this.dX, this.dY);
|
||||||
|
@ -360,6 +361,14 @@ MouseModule.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sendMove: function(aX, aY, aTarget) {
|
||||||
|
let event = document.createEvent("Events");
|
||||||
|
event.initEvent("TapMove", true, true);
|
||||||
|
event.clientX = aX;
|
||||||
|
event.clientY = aY;
|
||||||
|
aTarget.dispatchEvent(event);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inform our dragger of a dragStart.
|
* Inform our dragger of a dragStart.
|
||||||
*/
|
*/
|
||||||
|
@ -1246,4 +1255,3 @@ GestureModule.prototype = {
|
||||||
return r0.translate(offsetX, offsetY);
|
return r0.translate(offsetX, offsetY);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче