Main patch (original patch by mstange) - Bug 678392 - [10.7] Add support for swipe animation as in Safari. r=smichaud r=felipc

This commit is contained in:
Stephen Pohl 2013-02-08 13:56:50 -08:00
parent 5e0f441d46
commit e5e20d9c36
18 changed files with 970 additions and 101 deletions

View File

@ -532,6 +532,8 @@ pref("browser.gesture.twist.left", "cmd_gestureRotateLeft");
pref("browser.gesture.twist.end", "cmd_gestureRotateEnd");
pref("browser.gesture.tap", "cmd_fullZoomReset");
pref("browser.snapshots.limit", 20);
// 0: Nothing happens
// 1: Scrolling contents
// 2: Go back or go forward, in your history

View File

@ -0,0 +1,526 @@
# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
// History Swipe Animation Support (bug 678392)
let gHistorySwipeAnimation = {
active: false,
isLTR: false,
/**
* Initializes the support for history swipe animations, if it is supported
* by the platform/configuration.
*/
init: function HSA_init() {
if (!this._isSupported())
return;
gBrowser.addEventListener("pagehide", this, false);
gBrowser.addEventListener("pageshow", this, false);
gBrowser.addEventListener("popstate", this, false);
gBrowser.tabContainer.addEventListener("TabClose", this, false);
this.active = true;
this.isLTR = document.documentElement.mozMatchesSelector(
":-moz-locale-dir(ltr)");
this._trackedSnapshots = [];
this._historyIndex = -1;
this._boxWidth = -1;
this._maxSnapshots = this._getMaxSnapshots();
this._lastSwipeDir = "";
},
/**
* Uninitializes the support for history swipe animations.
*/
uninit: function HSA_uninit() {
gBrowser.removeEventListener("pagehide", this, false);
gBrowser.removeEventListener("pageshow", this, false);
gBrowser.removeEventListener("popstate", this, false);
gBrowser.tabContainer.removeEventListener("TabClose", this, false);
this.active = false;
this.isLTR = false;
},
/**
* Starts the swipe animation and handles fast swiping (i.e. a swipe animation
* is already in progress when a new one is initiated).
*/
startAnimation: function HSA_startAnimation() {
if (this.isAnimationRunning()) {
gBrowser.stop();
this._lastSwipeDir = "RELOAD"; // just ensure that != ""
this._canGoBack = this.canGoBack();
this._canGoForward = this.canGoForward();
this._handleFastSwiping();
}
else {
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
this._canGoBack = this.canGoBack();
this._canGoForward = this.canGoForward();
this._takeSnapshot();
this._installPrevAndNextSnapshots();
this._addBoxes();
this._lastSwipeDir = "";
}
this.updateAnimation(0);
},
/**
* Stops the swipe animation.
*/
stopAnimation: function HSA_stopAnimation() {
gHistorySwipeAnimation._removeBoxes();
},
/**
* Updates the animation between two pages in history.
*
* @param aVal
* A floating point value that represents the progress of the
* swipe gesture.
*/
updateAnimation: function HSA_updateAnimation(aVal) {
if (!this.isAnimationRunning())
return;
if ((aVal >= 0 && this.isLTR) ||
(aVal <= 0 && !this.isLTR)) {
if (aVal > 1)
aVal = 1; // Cap value to avoid sliding the page further than allowed.
if (this._canGoBack)
this._prevBox.collapsed = false;
else
this._prevBox.collapsed = true;
// The current page is pushed to the right (LTR) or left (RTL),
// the intention is to go back.
// If there is a page to go back to, it should show in the background.
this._positionBox(this._curBox, aVal);
// The forward page should be pushed offscreen all the way to the right.
this._positionBox(this._nextBox, 1);
}
else {
if (aVal < -1)
aVal = -1; // Cap value to avoid sliding the page further than allowed.
// The intention is to go forward. If there is a page to go forward to,
// it should slide in from the right (LTR) or left (RTL).
// Otherwise, the current page should slide to the left (LTR) or
// right (RTL) and the backdrop should appear in the background.
// For the backdrop to be visible in that case, the previous page needs
// to be hidden (if it exists).
if (this._canGoForward) {
let offset = this.isLTR ? 1 : -1;
this._positionBox(this._curBox, 0);
this._positionBox(this._nextBox, offset + aVal); // aVal is negative
}
else {
this._prevBox.collapsed = true;
this._positionBox(this._curBox, aVal);
}
}
},
/**
* Event handler for events relevant to the history swipe animation.
*
* @param aEvent
* An event to process.
*/
handleEvent: function HSA_handleEvent(aEvent) {
switch (aEvent.type) {
case "TabClose":
let browser = gBrowser.getBrowserForTab(aEvent.target);
this._removeTrackedSnapshot(-1, browser);
break;
case "pageshow":
case "popstate":
if (this.isAnimationRunning()) {
if (aEvent.target != gBrowser.selectedBrowser.contentDocument)
break;
this.stopAnimation();
}
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
break;
case "pagehide":
if (aEvent.target == gBrowser.selectedBrowser.contentDocument) {
// Take a snapshot of a page whenever it's about to be navigated away
// from.
this._takeSnapshot();
}
break;
}
},
/**
* Checks whether the history swipe animation is currently running or not.
*
* @return true if the animation is currently running, false otherwise.
*/
isAnimationRunning: function HSA_isAnimationRunning() {
return !!this._container;
},
/**
* Process a swipe event based on the given direction.
*
* @param aEvent
* The swipe event to handle
* @param aDir
* The direction for the swipe event
*/
processSwipeEvent: function HSA_processSwipeEvent(aEvent, aDir) {
if (aDir == "RIGHT")
this._historyIndex += this.isLTR ? 1 : -1;
else if (aDir == "LEFT")
this._historyIndex += this.isLTR ? -1 : 1;
else
return;
this._lastSwipeDir = aDir;
},
/**
* Checks if there is a page in the browser history to go back to.
*
* @return true if there is a previous page in history, false otherwise.
*/
canGoBack: function HSA_canGoBack() {
if (this.isAnimationRunning())
return this._doesIndexExistInHistory(this._historyIndex - 1);
return gBrowser.webNavigation.canGoBack;
},
/**
* Checks if there is a page in the browser history to go forward to.
*
* @return true if there is a next page in history, false otherwise.
*/
canGoForward: function HSA_canGoForward() {
if (this.isAnimationRunning())
return this._doesIndexExistInHistory(this._historyIndex + 1);
return gBrowser.webNavigation.canGoForward;
},
/**
* Used to notify the history swipe animation that the OS sent a swipe end
* event and that we should navigate to the page that the user swiped to, if
* any. This will also result in the animation overlay to be torn down.
*/
swipeEndEventReceived: function HSA_swipeEndEventReceived() {
if (this._lastSwipeDir != "")
this._navigateToHistoryIndex();
else
this.stopAnimation();
},
/**
* Checks whether a particular index exists in the browser history or not.
*
* @param aIndex
* The index to check for availability for in the history.
* @return true if the index exists in the browser history, false otherwise.
*/
_doesIndexExistInHistory: function HSA__doesIndexExistInHistory(aIndex) {
try {
gBrowser.webNavigation.sessionHistory.getEntryAtIndex(aIndex, false);
}
catch(ex) {
return false;
}
return true;
},
/**
* Navigates to the index in history that is currently being tracked by
* |this|.
*/
_navigateToHistoryIndex: function HSA__navigateToHistoryIndex() {
if (this._doesIndexExistInHistory(this._historyIndex)) {
gBrowser.webNavigation.gotoIndex(this._historyIndex);
}
},
/**
* Checks to see if history swipe animations are supported by this
* platform/configuration.
*
* return true if supported, false otherwise.
*/
_isSupported: function HSA__isSupported() {
// Only activate on Lion.
// TODO: Only if [NSEvent isSwipeTrackingFromScrollEventsEnabled]
return window.matchMedia("(-moz-mac-lion-theme)").matches;
},
/**
* Handle fast swiping (i.e. a swipe animation is already in
* progress when a new one is initiated). This will swap out the snapshots
* used in the previous animation with the appropriate new ones.
*/
_handleFastSwiping: function HSA__handleFastSwiping() {
this._installCurrentPageSnapshot(null);
this._installPrevAndNextSnapshots();
},
/**
* Adds the boxes that contain the snapshots used during the swipe animation.
*/
_addBoxes: function HSA__addBoxes() {
let browserStack =
document.getAnonymousElementByAttribute(gBrowser.getNotificationBox(),
"class", "browserStack");
this._container = this._createElement("historySwipeAnimationContainer",
"stack");
browserStack.appendChild(this._container);
this._prevBox = this._createElement("historySwipeAnimationPreviousPage",
"box");
this._container.appendChild(this._prevBox);
this._curBox = this._createElement("historySwipeAnimationCurrentPage",
"box");
this._container.appendChild(this._curBox);
this._nextBox = this._createElement("historySwipeAnimationNextPage",
"box");
this._container.appendChild(this._nextBox);
this._boxWidth = this._curBox.getBoundingClientRect().width; // cache width
},
/**
* Removes the boxes.
*/
_removeBoxes: function HSA__removeBoxes() {
this._curBox = null;
this._prevBox = null;
this._nextBox = null;
if (this._container)
this._container.parentNode.removeChild(this._container);
this._container = null;
this._boxWidth = -1;
},
/**
* Creates an element with a given identifier and tag name.
*
* @param aID
* An identifier to create the element with.
* @param aTagName
* The name of the tag to create the element for.
* @return the newly created element.
*/
_createElement: function HSA__createElement(aID, aTagName) {
let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let element = document.createElementNS(XULNS, aTagName);
element.id = aID;
return element;
},
/**
* Moves a given box to a given X coordinate position.
*
* @param aBox
* The box element to position.
* @param aPosition
* The position (in X coordinates) to move the box element to.
*/
_positionBox: function HSA__positionBox(aBox, aPosition) {
aBox.style.transform = "translateX(" + this._boxWidth * aPosition + "px)";
},
/**
* Takes a snapshot of the page the browser is currently on.
*/
_takeSnapshot: function HSA__takeSnapshot() {
if ((this._maxSnapshots < 1) ||
(gBrowser.webNavigation.sessionHistory.index < 0))
return;
let browser = gBrowser.selectedBrowser;
let r = browser.getBoundingClientRect();
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml",
"canvas");
canvas.mozOpaque = true;
canvas.width = r.width;
canvas.height = r.height;
let ctx = canvas.getContext("2d");
let zoom = browser.markupDocumentViewer.fullZoom;
ctx.scale(zoom, zoom);
ctx.drawWindow(browser.contentWindow, 0, 0, r.width, r.height, "white",
ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_VIEW |
ctx.DRAWWINDOW_ASYNC_DECODE_IMAGES |
ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
this._installCurrentPageSnapshot(canvas);
this._assignSnapshotToCurrentBrowser(canvas);
},
/**
* Retrieves the maximum number of snapshots that should be kept in memory.
* This limit is a global limit and is valid across all open tabs.
*/
_getMaxSnapshots: function HSA__getMaxSnapshots() {
return gPrefService.getIntPref("browser.snapshots.limit");
},
/**
* Adds a snapshot to the list and initiates the compression of said snapshot.
* Once the compression is completed, it will replace the uncompressed
* snapshot in the list.
*
* @param aCanvas
* The snapshot to add to the list and compress.
*/
_assignSnapshotToCurrentBrowser:
function HSA__assignSnapshotToCurrentBrowser(aCanvas) {
let browser = gBrowser.selectedBrowser;
let currIndex = browser.webNavigation.sessionHistory.index;
this._removeTrackedSnapshot(currIndex, browser);
this._addSnapshotRefToArray(currIndex, browser);
if (!("snapshots" in browser))
browser.snapshots = [];
let snapshots = browser.snapshots;
// Temporarily store the canvas as the compressed snapshot.
// This avoids a blank page if the user swipes quickly
// between pages before the compression could complete.
snapshots[currIndex] = aCanvas;
// Kick off snapshot compression.
aCanvas.toBlob(function(aBlob) {
snapshots[currIndex] = aBlob;
}, "image/png"
);
},
/**
* Removes a snapshot identified by the browser and index in the array of
* snapshots for that browser, if present. If no snapshot could be identified
* the method simply returns without taking any action. If aIndex is negative,
* all snapshots for a particular browser will be removed.
*
* @param aIndex
* The index in history of the new snapshot, or negative value if all
* snapshots for a browser should be removed.
* @param aBrowser
* The browser the new snapshot was taken in.
*/
_removeTrackedSnapshot: function HSA__removeTrackedSnapshot(aIndex, aBrowser) {
let arr = this._trackedSnapshots;
let requiresExactIndexMatch = aIndex >= 0;
for (let i = 0; i < arr.length; i++) {
if ((arr[i].browser == aBrowser) &&
(aIndex < 0 || aIndex == arr[i].index)) {
delete aBrowser.snapshots[arr[i].index];
arr.splice(i, 1);
if (requiresExactIndexMatch)
return; // Found and removed the only element.
i--; // Make sure to revisit the index that we just removed an
// element at.
}
}
},
/**
* Adds a new snapshot reference for a given index and browser to the array
* of references to tracked snapshots.
*
* @param aIndex
* The index in history of the new snapshot.
* @param aBrowser
* The browser the new snapshot was taken in.
*/
_addSnapshotRefToArray:
function HSA__addSnapshotRefToArray(aIndex, aBrowser) {
let id = { index: aIndex,
browser: aBrowser };
let arr = this._trackedSnapshots;
arr.unshift(id);
while (arr.length > this._maxSnapshots) {
let lastElem = arr[arr.length - 1];
delete lastElem.browser.snapshots[lastElem.index];
arr.splice(-1, 1);
}
},
/**
* Converts a compressed blob to an Image object. In some situations
* (especially during fast swiping) aBlob may still be a canvas, not a
* compressed blob. In this case, we simply return the canvas.
*
* @param aBlob
* The compressed blob to convert, or a canvas if a blob compression
* couldn't complete before this method was called.
* @return A new Image object representing the converted blob.
*/
_convertToImg: function HSA__convertToImg(aBlob) {
if (!aBlob)
return null;
// Return aBlob if it's still a canvas and not a compressed blob yet.
if (aBlob instanceof HTMLCanvasElement)
return aBlob;
let img = new Image();
let url = URL.createObjectURL(aBlob);
img.onload = function() {
URL.revokeObjectURL(url);
};
img.src = url;
return img;
},
/**
* Sets the snapshot of the current page to the snapshot passed as parameter,
* or to the one previously stored for the current index in history if the
* parameter is null.
*
* @param aCanvas
* The snapshot to set the current page to. If this parameter is null,
* the previously stored snapshot for this index (if any) will be used.
*/
_installCurrentPageSnapshot:
function HSA__installCurrentPageSnapshot(aCanvas) {
let currSnapshot = aCanvas;
if (!currSnapshot) {
let snapshots = gBrowser.selectedBrowser.snapshots || {};
let currIndex = this._historyIndex;
if (currIndex in snapshots)
currSnapshot = this._convertToImg(snapshots[currIndex]);
}
document.mozSetImageElement("historySwipeAnimationCurrentPageSnapshot",
currSnapshot);
},
/**
* Sets the snapshots of the previous and next pages to the snapshots
* previously stored for their respective indeces.
*/
_installPrevAndNextSnapshots:
function HSA__installPrevAndNextSnapshots() {
let snapshots = gBrowser.selectedBrowser.snapshots || [];
let currIndex = this._historyIndex;
let prevIndex = currIndex - 1;
let prevSnapshot = null;
if (prevIndex in snapshots)
prevSnapshot = this._convertToImg(snapshots[prevIndex]);
document.mozSetImageElement("historySwipeAnimationPreviousPageSnapshot",
prevSnapshot);
let nextIndex = currIndex + 1;
let nextSnapshot = null;
if (nextIndex in snapshots)
nextSnapshot = this._convertToImg(snapshots[nextIndex]);
document.mozSetImageElement("historySwipeAnimationNextPageSnapshot",
nextSnapshot);
},
};

View File

@ -366,6 +366,30 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
}
%endif
/* History Swipe Animation */
#historySwipeAnimationContainer {
overflow: hidden;
}
#historySwipeAnimationPreviousPage,
#historySwipeAnimationCurrentPage,
#historySwipeAnimationNextPage {
background: none top left no-repeat white;
}
#historySwipeAnimationPreviousPage {
background-image: -moz-element(#historySwipeAnimationPreviousPageSnapshot);
}
#historySwipeAnimationCurrentPage {
background-image: -moz-element(#historySwipeAnimationCurrentPageSnapshot);
}
#historySwipeAnimationNextPage {
background-image: -moz-element(#historySwipeAnimationNextPageSnapshot);
}
/* Identity UI */
#identity-popup-content-box.unknownIdentity > #identity-popup-connectedToLabel ,
#identity-popup-content-box.unknownIdentity > #identity-popup-runByLabel ,

View File

@ -156,6 +156,7 @@ let gInitialPages = [
#include browser-tabview.js
#include browser-thumbnails.js
#include browser-webrtcUI.js
#include browser-gestureSupport.js
#ifdef MOZ_DATA_REPORTING
#include browser-data-submission-info-bar.js
@ -747,7 +748,8 @@ let gGestureSupport = {
* True to add/init listeners and false to remove/uninit
*/
init: function GS_init(aAddListener) {
const gestureEvents = ["SwipeGesture",
const gestureEvents = ["SwipeGestureStart",
"SwipeGestureUpdate", "SwipeGestureEnd", "SwipeGesture",
"MagnifyGestureStart", "MagnifyGestureUpdate", "MagnifyGesture",
"RotateGestureStart", "RotateGestureUpdate", "RotateGesture",
"TapGesture", "PressTapGesture"];
@ -775,6 +777,18 @@ let gGestureSupport = {
({ threshold: aThreshold, latched: !!aLatched });
switch (aEvent.type) {
case "MozSwipeGestureStart":
aEvent.preventDefault();
this._setupSwipeGesture(aEvent);
break;
case "MozSwipeGestureUpdate":
aEvent.preventDefault();
this._doUpdate(aEvent);
break;
case "MozSwipeGestureEnd":
aEvent.preventDefault();
this._doEnd(aEvent);
break;
case "MozSwipeGesture":
aEvent.preventDefault();
this.onSwipe(aEvent);
@ -861,6 +875,56 @@ let gGestureSupport = {
this._doUpdate(aEvent);
},
/**
* Checks whether a swipe gesture event can navigate the browser history or
* not.
*
* @param aEvent
* The swipe gesture event.
* @return true if the swipe event may navigate the history, false othwerwise.
*/
_swipeNavigatesHistory: function GS__swipeNavigatesHistory(aEvent) {
return this._getCommand(aEvent, ["swipe", "left"])
== "Browser:BackOrBackDuplicate" &&
this._getCommand(aEvent, ["swipe", "right"])
== "Browser:ForwardOrForwardDuplicate";
},
/**
* Sets up the history swipe animations for a swipe gesture event, if enabled.
*
* @param aEvent
* The swipe gesture start event.
*/
_setupSwipeGesture: function GS__setupSwipeGesture(aEvent) {
if (!this._swipeNavigatesHistory(aEvent) || !gHistorySwipeAnimation.active)
return;
let canGoBack = gHistorySwipeAnimation.canGoBack();
let canGoForward = gHistorySwipeAnimation.canGoForward();
let isLTR = gHistorySwipeAnimation.isLTR;
if (canGoBack)
aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_LEFT :
aEvent.DIRECTION_RIGHT;
if (canGoForward)
aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_RIGHT :
aEvent.DIRECTION_LEFT;
gHistorySwipeAnimation.startAnimation();
this._doUpdate = function GS__doUpdate(aEvent) {
gHistorySwipeAnimation.updateAnimation(aEvent.delta);
};
this._doEnd = function GS__doEnd(aEvent) {
gHistorySwipeAnimation.swipeEndEventReceived();
this._doUpdate = function (aEvent) {};
this._doEnd = function (aEvent) {};
}
},
/**
* Generator producing the powerset of the input array where the first result
* is the complete set and the last result (before StopIteration) is empty.
@ -882,6 +946,22 @@ let gGestureSupport = {
}
},
/**
* Determine what action to do for the gesture based on which keys are
* pressed and which commands are set, and execute the command.
*
* @param aEvent
* The original gesture event to convert into a fake click event
* @param aGesture
* Array of gesture name parts (to be joined by periods)
* @return Name of the executed command. Returns null if no command is
* found.
*/
_doAction: function GS__doAction(aEvent, aGesture) {
let command = this._getCommand(aEvent, aGesture);
return command && this._doCommand(aEvent, command);
},
/**
* Determine what action to do for the gesture based on which keys are
* pressed and which commands are set
@ -891,7 +971,7 @@ let gGestureSupport = {
* @param aGesture
* Array of gesture name parts (to be joined by periods)
*/
_doAction: function GS__doAction(aEvent, aGesture) {
_getCommand: function GS__getCommand(aEvent, aGesture) {
// Create an array of pressed keys in a fixed order so that a command for
// "meta" is preferred over "ctrl" when both buttons are pressed (and a
// command for both don't exist)
@ -911,30 +991,40 @@ let gGestureSupport = {
command = this._getPref(aGesture.concat(subCombo).join("."));
} catch (e) {}
if (!command)
continue;
if (command)
return command;
}
return null;
},
let node = document.getElementById(command);
if (node) {
if (node.getAttribute("disabled") != "true") {
let cmdEvent = document.createEvent("xulcommandevent");
cmdEvent.initCommandEvent("command", true, true, window, 0,
aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
aEvent.metaKey, aEvent);
node.dispatchEvent(cmdEvent);
}
} else {
goDoCommand(command);
/**
* Execute the specified command.
*
* @param aEvent
* The original gesture event to convert into a fake click event
* @param aCommand
* Name of the command found for the event's keys and gesture.
*/
_doCommand: function GS__doCommand(aEvent, aCommand) {
let node = document.getElementById(aCommand);
if (node) {
if (node.getAttribute("disabled") != "true") {
let cmdEvent = document.createEvent("xulcommandevent");
cmdEvent.initCommandEvent("command", true, true, window, 0,
aEvent.ctrlKey, aEvent.altKey,
aEvent.shiftKey, aEvent.metaKey, null);
node.dispatchEvent(cmdEvent);
}
break;
}
else {
goDoCommand(aCommand);
}
},
/**
* Convert continual motion events into an action if it exceeds a threshold
* in a given direction. This function will be set by _setupGesture to
* capture state that needs to be shared across multiple gesture updates.
* Handle continual motion events. This function will be set by
* _setupGesture or _setupSwipe.
*
* @param aEvent
* The continual motion update event to handle
@ -942,7 +1032,15 @@ let gGestureSupport = {
_doUpdate: function(aEvent) {},
/**
* Convert the swipe gesture into a browser action based on the direction
* Handle gesture end events. This function will be set by _setupSwipe.
*
* @param aEvent
* The gesture end event to handle
*/
_doEnd: function(aEvent) {},
/**
* Convert the swipe gesture into a browser action based on the direction.
*
* @param aEvent
* The swipe event to handle
@ -951,12 +1049,46 @@ let gGestureSupport = {
// Figure out which one (and only one) direction was triggered
for (let dir of ["UP", "RIGHT", "DOWN", "LEFT"]) {
if (aEvent.direction == aEvent["DIRECTION_" + dir]) {
this._doAction(aEvent, ["swipe", dir.toLowerCase()]);
this._coordinateSwipeEventWithAnimation(aEvent, dir);
break;
}
}
},
/**
* Process a swipe event based on the given direction.
*
* @param aEvent
* The swipe event to handle
* @param aDir
* The direction for the swipe event
*/
processSwipeEvent: function GS_processSwipeEvent(aEvent, aDir) {
this._doAction(aEvent, ["swipe", aDir.toLowerCase()]);
},
/**
* Coordinates the swipe event with the swipe animation, if any.
* If an animation is currently running, the swipe event will be
* processed once the animation stops. This will guarantee a fluid
* motion of the animation.
*
* @param aEvent
* The swipe event to handle
* @param aDir
* The direction for the swipe event
*/
_coordinateSwipeEventWithAnimation:
function GS__coordinateSwipeEventWithAnimation(aEvent, aDir) {
if ((gHistorySwipeAnimation.isAnimationRunning()) &&
(aDir == "RIGHT" || aDir == "LEFT")) {
gHistorySwipeAnimation.processSwipeEvent(aEvent, aDir);
}
else {
this.processSwipeEvent(aEvent, aDir);
}
},
/**
* Get a gesture preference or use a default if it doesn't exist
*
@ -1196,6 +1328,9 @@ var gBrowserInit = {
// setup simple gestures support
gGestureSupport.init(true);
// setup history swipe animation
gHistorySwipeAnimation.init();
if (window.opener && !window.opener.closed) {
let openerSidebarBox = window.opener.document.getElementById("sidebar-box");
// If the opener had a sidebar, open the same sidebar in our window.
@ -1656,6 +1791,8 @@ var gBrowserInit = {
gGestureSupport.init(false);
gHistorySwipeAnimation.uninit();
FullScreen.cleanup();
Services.obs.removeObserver(gPluginHandler.pluginCrashed, "plugin-crashed");
@ -1872,7 +2009,6 @@ var nonBrowserWindowDelayedStartup = gBrowserInit.nonBrowserWindowDelayedStartup
var nonBrowserWindowShutdown = gBrowserInit.nonBrowserWindowShutdown.bind(gBrowserInit);
#endif
function HandleAppCommandEvent(evt) {
switch (evt.command) {
case "Back":

View File

@ -120,6 +120,14 @@ function test_TestEventListeners()
{
let e = test_helper1; // easier to type this name
// Swipe gesture animation events
e("MozSwipeGestureStart", 0, -0.7, 0);
e("MozSwipeGestureUpdate", 0, -0.4, 0);
e("MozSwipeGestureEnd", 0, 0, 0);
e("MozSwipeGestureStart", 0, 0.6, 0);
e("MozSwipeGestureUpdate", 0, 0.3, 0);
e("MozSwipeGestureEnd", 0, 1, 0);
// Swipe gesture event
e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_LEFT, 0.0, 0);
e("MozSwipeGesture", SimpleGestureEvent.DIRECTION_RIGHT, 0.0, 0);
@ -197,7 +205,7 @@ function test_helper2(type, direction, delta, altKey, ctrlKey, shiftKey, metaKey
10, 10, 10, 10,
ctrlKey, altKey, shiftKey, metaKey,
1, window,
direction, delta, 0);
0, direction, delta, 0);
successful = true;
}
catch (ex) {

View File

@ -2048,6 +2048,17 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
}
}
/* History Swipe Animation */
#historySwipeAnimationCurrentPage,
#historySwipeAnimationNextPage {
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6);
}
#historySwipeAnimationContainer {
background: url("chrome://browser/skin/linen-pattern.png") #B3B9C1;
}
/* ----- SIDEBAR ELEMENTS ----- */
#sidebar,

View File

@ -40,6 +40,7 @@ browser.jar:
skin/classic/browser/keyhole-circle.png
skin/classic/browser/KUI-background.png
skin/classic/browser/KUI-close.png
skin/classic/browser/linen-pattern.png
skin/classic/browser/menu-back.png
skin/classic/browser/menu-forward.png
skin/classic/browser/mixed-content-blocked-16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1727,6 +1727,9 @@ GK_ATOM(seconds, "seconds")
GK_ATOM(secondsFromDateTime, "seconds-from-dateTime")
// Simple gestures support
GK_ATOM(onMozSwipeGestureStart, "onMozSwipeGestureStart")
GK_ATOM(onMozSwipeGestureUpdate, "onMozSwipeGestureUpdate")
GK_ATOM(onMozSwipeGestureEnd, "onMozSwipeGestureEnd")
GK_ATOM(onMozSwipeGesture, "onMozSwipeGesture")
GK_ATOM(onMozMagnifyGestureStart, "onMozMagnifyGestureStart")
GK_ATOM(onMozMagnifyGestureUpdate, "onMozMagnifyGestureUpdate")

View File

@ -755,6 +755,18 @@ NON_IDL_EVENT(MozScrolledAreaChanged,
NS_SCROLLAREA_EVENT)
// Simple gesture events
NON_IDL_EVENT(MozSwipeGestureStart,
NS_SIMPLE_GESTURE_SWIPE_START,
EventNameType_None,
NS_SIMPLE_GESTURE_EVENT)
NON_IDL_EVENT(MozSwipeGestureUpdate,
NS_SIMPLE_GESTURE_SWIPE_UPDATE,
EventNameType_None,
NS_SIMPLE_GESTURE_EVENT)
NON_IDL_EVENT(MozSwipeGestureEnd,
NS_SIMPLE_GESTURE_SWIPE_END,
EventNameType_None,
NS_SIMPLE_GESTURE_EVENT)
NON_IDL_EVENT(MozSwipeGesture,
NS_SIMPLE_GESTURE_SWIPE,
EventNameType_None,

View File

@ -39,6 +39,22 @@ NS_INTERFACE_MAP_BEGIN(nsDOMSimpleGestureEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SimpleGestureEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMMouseEvent)
/* attribute unsigned long allowedDirections; */
NS_IMETHODIMP
nsDOMSimpleGestureEvent::GetAllowedDirections(PRUint32 *aAllowedDirections)
{
NS_ENSURE_ARG_POINTER(aAllowedDirections);
*aAllowedDirections = static_cast<nsSimpleGestureEvent*>(mEvent)->allowedDirections;
return NS_OK;
}
NS_IMETHODIMP
nsDOMSimpleGestureEvent::SetAllowedDirections(PRUint32 aAllowedDirections)
{
static_cast<nsSimpleGestureEvent*>(mEvent)->allowedDirections = aAllowedDirections;
return NS_OK;
}
/* readonly attribute unsigned long direction; */
NS_IMETHODIMP
nsDOMSimpleGestureEvent::GetDirection(uint32_t *aDirection)
@ -82,6 +98,7 @@ nsDOMSimpleGestureEvent::InitSimpleGestureEvent(const nsAString& aTypeArg,
bool aMetaKeyArg,
uint16_t aButton,
nsIDOMEventTarget* aRelatedTarget,
uint32_t aAllowedDirectionsArg,
uint32_t aDirectionArg,
double aDeltaArg,
uint32_t aClickCountArg)
@ -104,6 +121,7 @@ nsDOMSimpleGestureEvent::InitSimpleGestureEvent(const nsAString& aTypeArg,
NS_ENSURE_SUCCESS(rv, rv);
nsSimpleGestureEvent* simpleGestureEvent = static_cast<nsSimpleGestureEvent*>(mEvent);
simpleGestureEvent->allowedDirections = aAllowedDirectionsArg;
simpleGestureEvent->direction = aDirectionArg;
simpleGestureEvent->delta = aDeltaArg;
simpleGestureEvent->clickCount = aClickCountArg;

View File

@ -1167,7 +1167,13 @@ nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType,
return NS_ERROR_FAILURE;
int32_t msg;
if (aType.EqualsLiteral("MozSwipeGesture"))
if (aType.EqualsLiteral("MozSwipeGestureStart"))
msg = NS_SIMPLE_GESTURE_SWIPE_START;
else if (aType.EqualsLiteral("MozSwipeGestureUpdate"))
msg = NS_SIMPLE_GESTURE_SWIPE_UPDATE;
else if (aType.EqualsLiteral("MozSwipeGestureEnd"))
msg = NS_SIMPLE_GESTURE_SWIPE_END;
else if (aType.EqualsLiteral("MozSwipeGesture"))
msg = NS_SIMPLE_GESTURE_SWIPE;
else if (aType.EqualsLiteral("MozMagnifyGestureStart"))
msg = NS_SIMPLE_GESTURE_MAGNIFY_START;

View File

@ -539,7 +539,8 @@ interface nsIDOMWindowUtils : nsISupports {
[optional] in long aExtraForgetSkippableCalls);
/** Synthesize a simple gesture event for a window. The event types
* supported are: MozSwipeGesture, MozMagnifyGestureStart,
* supported are: MozSwipeGestureStart, MozSwipeGestureUpdate,
* MozSwipeGestureEnd, MozSwipeGesture, MozMagnifyGestureStart,
* MozMagnifyGestureUpdate, MozMagnifyGesture, MozRotateGestureStart,
* MozRotateGestureUpdate, MozRotateGesture, MozPressTapGesture,
* MozTapGesture, and MozEdgeUIGesture.

View File

@ -12,8 +12,38 @@
*
* The following events are generated:
*
* MozSwipeGesture - Generated when the user completes a swipe across
* across the input device.
* MozSwipeGestureStart - Generated when the user starts a horizontal
* swipe across the input device. This event not only acts as a signal,
* but also asks two questions: Should a swipe really be started, and
* in which directions should the user be able to swipe? The first
* question is answered by event listeners by calling or not calling
* preventDefault() on the event. Since a swipe swallows all scroll
* events, the default action of the swipe start event is *not* to
* start a swipe. Call preventDefault() if you want a swipe to be
* started.
* The second question (swipe-able directions) is answered in the
* allowedDirections field.
* If this event has preventDefault() called on it (and thus starts
* a swipe), it guarantees a future MozSwipeGestureEnd event that
* will signal the end of a swipe animation.
*
* MozSwipeGestureUpdate - Generated periodically while the user is
* continuing a horizontal swipe gesture. The "delta" value represents
* the current absolute gesture amount. This event may even be sent
* after a MozSwipeGesture event fired in order to allow for fluid
* completion of a swipe animation. The direction value is meaningless
* on swipe update events.
*
* MozSwipeGestureEnd - Generated when the swipe animation is completed.
*
* MozSwipeGesture - Generated when the user releases a swipe across
* across the input device. This event signals that the actual swipe
* operation is complete, even though the animation might not be finished
* yet. This event can be sent without accompanying start / update / end
* events, and it can also be handled on its own if the consumer doesn't
* want to handle swipe animation events.
* Only the direction value has any significance, the delta value is
* meaningless.
*
* MozMagnifyGestureStart - Generated when the user begins the magnify
* ("pinch") gesture. The "delta" value represents the initial
@ -77,11 +107,28 @@ interface nsIDOMSimpleGestureEvent : nsIDOMMouseEvent
const unsigned long DIRECTION_DOWN = 2;
const unsigned long DIRECTION_LEFT = 4;
const unsigned long DIRECTION_RIGHT = 8;
/* Rotational direction constants */
const unsigned long ROTATION_COUNTERCLOCKWISE = 1;
const unsigned long ROTATION_CLOCKWISE = 2;
/* Read-write value for swipe events.
*
* Reports the directions that can be swiped to; multiple directions
* should be OR'ed together.
*
* The allowedDirections field is designed to be set on SwipeGestureStart
* events by event listeners. Its value after event dispatch determines
* the behavior of the swipe animation that is about to begin.
* Specifically, if the user swipes in a direction that can't be swiped
* to, the animation will have a bounce effect.
* Future SwipeGestureUpdate, SwipeGesture and SwipeGestureEnd events
* will carry the allowDirections value that was set on the SwipeStart
* event. Changing this field on non-SwipeGestureStart events doesn't
* have any effect.
*/
attribute unsigned long allowedDirections;
/* Direction of a gesture. Diagonals are indicated by OR'ing the
* applicable constants together.
*
@ -94,8 +141,8 @@ interface nsIDOMSimpleGestureEvent : nsIDOMMouseEvent
*/
readonly attribute unsigned long direction;
/* Delta value for magnify and rotate gestures.
*
/* Delta value for magnify, rotate and swipe gestures.
*
* For rotation, the value is in degrees and is positive for
* clockwise rotation and negative for counterclockwise
* rotation.
@ -111,6 +158,14 @@ interface nsIDOMSimpleGestureEvent : nsIDOMMouseEvent
* 100.0, but it is only safe currently to rely on the delta being
* positive or negative.
*
* For swipe start, update and end events, the value is a fraction
* of one "page". If the resulting swipe will have DIRECTION_LEFT, the
* delta value will be positive; for DIRECTION_RIGHT, delta is negative.
* If this seems backwards to you, look at it this way: If the current
* page is pushed to the right during the animation (positive delta),
* the page left to the current page will be visible after the swipe
* (DIRECTION_LEFT).
*
* Units on Windows represent the difference between the initial
* and current/final width between the two touch points on the input
* device and are measured in pixels.
@ -135,6 +190,7 @@ interface nsIDOMSimpleGestureEvent : nsIDOMMouseEvent
in boolean metaKeyArg,
in unsigned short buttonArg,
in nsIDOMEventTarget relatedTargetArg,
in unsigned long allowedDirectionsArg,
in unsigned long directionArg,
in double deltaArg,
in unsigned long clickCount);

View File

@ -55,7 +55,7 @@ function onDebugKeyPress(aEvent) {
let evt = document.createEvent("SimpleGestureEvent");
evt.initSimpleGestureEvent("MozSwipeGesture", true, true, window, null,
0, 0, 0, 0, false, false, false, false, 0, null,
aDirection, 0, 0);
0, aDirection, 0, 0);
Browser.selectedTab.inputHandler.dispatchEvent(evt);
}
@ -79,7 +79,7 @@ function onDebugKeyPress(aEvent) {
function dispatchMagnifyEvent(aName, aDelta) {
let evt = document.createEvent("SimpleGestureEvent");
evt.initSimpleGestureEvent("MozMagnifyGesture" + aName, true, true, window, null,
0, 0, 0, 0, false, false, false, false, 0, null, 0, aDelta, 0);
0, 0, 0, 0, false, false, false, false, 0, null, 0, 0, aDelta, 0);
Browser.selectedTab.inputHandler.dispatchEvent(evt);
}
dispatchMagnifyEvent("Start", 0);

View File

@ -260,9 +260,9 @@ typedef NSInteger NSEventGestureAxis;
BOOL mDidForceRefreshOpenGL;
// Support for fluid swipe tracking.
#ifdef __LP64__
BOOL *mSwipeAnimationCancelled;
// Support for fluid swipe tracking.
void (^mCancelSwipeAnimation)();
#endif
// Whether this uses off-main-thread compositing.

View File

@ -2046,10 +2046,10 @@ NSEvent* gLastDragMouseDownEvent = nil;
[self setFocusRingType:NSFocusRingTypeNone];
#ifdef __LP64__
mSwipeAnimationCancelled = nil;
mCancelSwipeAnimation = nil;
#endif
}
// register for things we'll take from other applications
[ChildView registerViewForDraggedTypes:self];
@ -3029,6 +3029,45 @@ NSEvent* gLastDragMouseDownEvent = nil;
NS_OBJC_END_TRY_ABORT_BLOCK;
}
#ifdef __LP64__
- (bool)sendSwipeEvent:(NSEvent*)aEvent
withKind:(PRUint32)aMsg
allowedDirections:(PRUint32*)aAllowedDirections
direction:(PRUint32)aDirection
delta:(PRFloat64)aDelta
{
if (!mGeckoChild)
return false;
nsSimpleGestureEvent geckoEvent(true, aMsg, mGeckoChild, aDirection, aDelta);
geckoEvent.allowedDirections = *aAllowedDirections;
[self convertCocoaMouseEvent:aEvent toGeckoEvent:&geckoEvent];
bool eventCancelled = mGeckoChild->DispatchWindowEvent(geckoEvent);
*aAllowedDirections = geckoEvent.allowedDirections;
return eventCancelled; // event cancelled == swipe should start
}
- (void)cancelSwipeIfRunning
{
if (mCancelSwipeAnimation) {
mCancelSwipeAnimation();
[mCancelSwipeAnimation release];
mCancelSwipeAnimation = nil;
}
}
- (void)sendSwipeEndEvent:(NSEvent *)anEvent
allowedDirections:(PRUint32)aAllowedDirections
{
// Tear down animation overlay by sending a swipe end event.
PRUint32 allowedDirectionsCopy = aAllowedDirections;
[self sendSwipeEvent:anEvent
withKind:NS_SIMPLE_GESTURE_SWIPE_END
allowedDirections:&allowedDirectionsCopy
direction:0
delta:0.0];
}
// Support fluid swipe tracking on OS X 10.7 and higher. We must be careful
// to only invoke this support on a horizontal two-finger gesture that really
// is a swipe (and not a scroll) -- in other words, the app is responsible
@ -3039,7 +3078,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
// partly based on Apple sample code available at
// http://developer.apple.com/library/mac/#releasenotes/Cocoa/AppKit.html
// (under Fluid Swipe Tracking API).
#ifdef __LP64__
- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
scrollOverflow:(double)overflow
{
@ -3058,13 +3096,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
return;
}
// If a swipe is currently being tracked kill it -- it's been interrupted by
// another gesture or legacy scroll wheel event.
if (mSwipeAnimationCancelled && (*mSwipeAnimationCancelled == NO)) {
*mSwipeAnimationCancelled = YES;
mSwipeAnimationCancelled = nil;
}
// Only initiate tracking if the user has tried to scroll past the edge of
// the current page (as indicated by 'overflow' being non-zero). Gecko only
// sets nsMouseScrollEvent.scrollOverflow when it's processing
@ -3097,6 +3128,27 @@ NSEvent* gLastDragMouseDownEvent = nil;
return;
}
// If a swipe is currently being tracked kill it -- it's been interrupted by
// another gesture or legacy scroll wheel event.
[self cancelSwipeIfRunning];
// We're ready to start the animation. Tell Gecko about it, and at the same
// time ask it if it really wants to start an animation for this event.
// This event also reports back the directions that we can swipe in.
PRUint32 allowedDirections = 0;
bool shouldStartSwipe = [self sendSwipeEvent:anEvent
withKind:NS_SIMPLE_GESTURE_SWIPE_START
allowedDirections:&allowedDirections
direction:0
delta:0.0];
if (!shouldStartSwipe) {
return;
}
double min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ? -1 : 0;
double max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ? 1 : 0;
__block BOOL animationCancelled = NO;
__block BOOL geckoSwipeEventSent = NO;
// At this point, anEvent is the first scroll wheel event in a two-finger
@ -3114,9 +3166,9 @@ NSEvent* gLastDragMouseDownEvent = nil;
// the anEvent object because it's retained by the block, see bug 682445.
// The block will release it when the block goes away at the end of the
// animation, or when the animation is canceled.
[anEvent trackSwipeEventWithOptions:0
dampenAmountThresholdMin:-1
max:1
[anEvent trackSwipeEventWithOptions:NSEventSwipeTrackingLockDirection
dampenAmountThresholdMin:min
max:max
usingHandler:^(CGFloat gestureAmount, NSEventPhase phase, BOOL isComplete, BOOL *stop) {
// Since this tracking handler can be called asynchronously, mGeckoChild
// might have become NULL here (our child widget might have been
@ -3125,48 +3177,56 @@ NSEvent* gLastDragMouseDownEvent = nil;
*stop = YES;
return;
}
// gestureAmount is documented to be '-1', '0' or '1' when isComplete
// is TRUE, but the docs don't say anything about its value at other
// times. However, tests show that, when phase == NSEventPhaseEnded,
// gestureAmount is negative when it will be '-1' at isComplete, and
// positive when it will be '1'. And phase is never equal to
// NSEventPhaseEnded when gestureAmount will be '0' at isComplete.
// Not waiting until isComplete is TRUE substantially reduces the
// time it takes to change pages after a swipe, and helps resolve
// bug 678891.
PRUint32 allowedDirectionsCopy = allowedDirections;
// Update animation overlay to match gestureAmount.
[self sendSwipeEvent:anEvent
withKind:NS_SIMPLE_GESTURE_SWIPE_UPDATE
allowedDirections:&allowedDirectionsCopy
direction:0
delta:gestureAmount];
if (phase == NSEventPhaseEnded && !geckoSwipeEventSent) {
if (gestureAmount) {
nsSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_SWIPE, mGeckoChild, 0, 0.0);
[self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent];
if (gestureAmount > 0) {
geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
} else {
geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
}
// If DispatchWindowEvent() does something to trigger a modal dialog
// (which spins the event loop), the OS gets confused and makes
// several re-entrant calls to this handler, all of which have
// 'phase' set to NSEventPhaseEnded. Unless we do something about
// it, this results in an equal number of re-entrant calls to
// DispatchWindowEvent(), and to our modal-event handling code.
// Probably because of bug 478703, this really messes things up,
// and requires a force quit to get out of. We avoid this by
// avoiding re-entrant calls to DispatchWindowEvent(). See bug
// 770626.
geckoSwipeEventSent = YES;
mGeckoChild->DispatchWindowEvent(geckoEvent);
}
mSwipeAnimationCancelled = nil;
} else if (phase == NSEventPhaseCancelled) {
mSwipeAnimationCancelled = nil;
// The result of the swipe is now known, so the main event can be sent.
// The animation might continue even after this event was sent, so
// don't tear down the animation overlay yet.
// gestureAmount is documented to be '-1', '0' or '1' when isComplete
// is TRUE, but the docs don't say anything about its value at other
// times. However, tests show that, when phase == NSEventPhaseEnded,
// gestureAmount is negative when it will be '-1' at isComplete, and
// positive when it will be '1'. And phase is never equal to
// NSEventPhaseEnded when gestureAmount will be '0' at isComplete.
PRUint32 direction = gestureAmount > 0 ?
(PRUint32)nsIDOMSimpleGestureEvent::DIRECTION_LEFT :
(PRUint32)nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
// If DispatchWindowEvent() does something to trigger a modal dialog
// (which spins the event loop), the OS gets confused and makes
// several re-entrant calls to this handler, all of which have
// 'phase' set to NSEventPhaseEnded. Unless we do something about
// it, this results in an equal number of re-entrant calls to
// DispatchWindowEvent(), and to our modal-event handling code.
// Probably because of bug 478703, this really messes things up,
// and requires a force quit to get out of. We avoid this by
// avoiding re-entrant calls to DispatchWindowEvent(). See bug
// 770626.
geckoSwipeEventSent = YES;
[self sendSwipeEvent:anEvent
withKind:NS_SIMPLE_GESTURE_SWIPE
allowedDirections:&allowedDirectionsCopy
direction:direction
delta:0.0];
}
if (isComplete) {
[self cancelSwipeIfRunning];
[self sendSwipeEndEvent:anEvent allowedDirections:allowedDirections];
}
}];
// We keep a pointer to the __block variable (animationCanceled) so we
// can cancel our block handler at any time. Note: We must assign
// &animationCanceled after our block creation and copy -- its address
// isn't resolved until then!
mSwipeAnimationCancelled = &animationCancelled;
mCancelSwipeAnimation = [^{
animationCancelled = YES;
} copy];
}
#endif // #ifdef __LP64__

View File

@ -337,16 +337,19 @@ enum nsEventStructType {
// Simple gesture events
#define NS_SIMPLE_GESTURE_EVENT_START 3500
#define NS_SIMPLE_GESTURE_SWIPE (NS_SIMPLE_GESTURE_EVENT_START)
#define NS_SIMPLE_GESTURE_MAGNIFY_START (NS_SIMPLE_GESTURE_EVENT_START+1)
#define NS_SIMPLE_GESTURE_MAGNIFY_UPDATE (NS_SIMPLE_GESTURE_EVENT_START+2)
#define NS_SIMPLE_GESTURE_MAGNIFY (NS_SIMPLE_GESTURE_EVENT_START+3)
#define NS_SIMPLE_GESTURE_ROTATE_START (NS_SIMPLE_GESTURE_EVENT_START+4)
#define NS_SIMPLE_GESTURE_ROTATE_UPDATE (NS_SIMPLE_GESTURE_EVENT_START+5)
#define NS_SIMPLE_GESTURE_ROTATE (NS_SIMPLE_GESTURE_EVENT_START+6)
#define NS_SIMPLE_GESTURE_TAP (NS_SIMPLE_GESTURE_EVENT_START+7)
#define NS_SIMPLE_GESTURE_PRESSTAP (NS_SIMPLE_GESTURE_EVENT_START+8)
#define NS_SIMPLE_GESTURE_EDGEUI (NS_SIMPLE_GESTURE_EVENT_START+9)
#define NS_SIMPLE_GESTURE_SWIPE_START (NS_SIMPLE_GESTURE_EVENT_START)
#define NS_SIMPLE_GESTURE_SWIPE_UPDATE (NS_SIMPLE_GESTURE_EVENT_START+1)
#define NS_SIMPLE_GESTURE_SWIPE_END (NS_SIMPLE_GESTURE_EVENT_START+2)
#define NS_SIMPLE_GESTURE_SWIPE (NS_SIMPLE_GESTURE_EVENT_START+3)
#define NS_SIMPLE_GESTURE_MAGNIFY_START (NS_SIMPLE_GESTURE_EVENT_START+4)
#define NS_SIMPLE_GESTURE_MAGNIFY_UPDATE (NS_SIMPLE_GESTURE_EVENT_START+5)
#define NS_SIMPLE_GESTURE_MAGNIFY (NS_SIMPLE_GESTURE_EVENT_START+6)
#define NS_SIMPLE_GESTURE_ROTATE_START (NS_SIMPLE_GESTURE_EVENT_START+7)
#define NS_SIMPLE_GESTURE_ROTATE_UPDATE (NS_SIMPLE_GESTURE_EVENT_START+8)
#define NS_SIMPLE_GESTURE_ROTATE (NS_SIMPLE_GESTURE_EVENT_START+9)
#define NS_SIMPLE_GESTURE_TAP (NS_SIMPLE_GESTURE_EVENT_START+10)
#define NS_SIMPLE_GESTURE_PRESSTAP (NS_SIMPLE_GESTURE_EVENT_START+11)
#define NS_SIMPLE_GESTURE_EDGEUI (NS_SIMPLE_GESTURE_EVENT_START+12)
// These are used to send native events to plugins.
#define NS_PLUGIN_EVENT_START 3600
@ -1673,20 +1676,22 @@ public:
nsSimpleGestureEvent(bool isTrusted, uint32_t msg, nsIWidget* w,
uint32_t directionArg, double deltaArg)
: nsMouseEvent_base(isTrusted, msg, w, NS_SIMPLE_GESTURE_EVENT),
direction(directionArg), delta(deltaArg), clickCount(0)
allowedDirections(0), direction(directionArg), delta(deltaArg),
clickCount(0)
{
}
nsSimpleGestureEvent(const nsSimpleGestureEvent& other)
: nsMouseEvent_base(other.mFlags.mIsTrusted,
other.message, other.widget, NS_SIMPLE_GESTURE_EVENT),
direction(other.direction), delta(other.delta), clickCount(0)
allowedDirections(other.allowedDirections), direction(other.direction),
delta(other.delta), clickCount(0)
{
}
uint32_t direction; // See nsIDOMSimpleGestureEvent for values
double delta; // Delta for magnify and rotate events
uint32_t clickCount; // The number of taps for tap events
uint32_t allowedDirections; // See nsIDOMSimpleGestureEvent for values
uint32_t direction; // See nsIDOMSimpleGestureEvent for values
double delta; // Delta for magnify and rotate events
uint32_t clickCount; // The number of taps for tap events
};
class nsTransitionEvent : public nsEvent