Skip to content

Commit

Permalink
Bug 673875 - Reproduce bounce behaviour when reaching top and bottom …
Browse files Browse the repository at this point in the history
…of documents. r=smichaud, r=felipc
  • Loading branch information
Stephen Pohl committed Apr 13, 2013
1 parent b0284bc commit 6d01aff
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 151 deletions.
125 changes: 92 additions & 33 deletions browser/base/content/browser-gestureSupport.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,19 @@ let gGestureSupport = {
aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_RIGHT :
aEvent.DIRECTION_LEFT;

gHistorySwipeAnimation.startAnimation();
let isVerticalSwipe = false;
if (aEvent.direction == aEvent.DIRECTION_UP) {
isVerticalSwipe = true;
// Force a synchronous scroll to the top of the page.
content.scrollTo(content.scrollX, 0);
}
else if (aEvent.direction == aEvent.DIRECTION_DOWN) {
isVerticalSwipe = true;
// Force a synchronous scroll to the bottom of the page.
content.scrollTo(content.scrollX, content.scrollMaxY);
}

gHistorySwipeAnimation.startAnimation(isVerticalSwipe);

this._doUpdate = function GS__doUpdate(aEvent) {
gHistorySwipeAnimation.updateAnimation(aEvent.delta);
Expand Down Expand Up @@ -541,10 +553,13 @@ let gHistorySwipeAnimation = {
this.isLTR = document.documentElement.mozMatchesSelector(
":-moz-locale-dir(ltr)");
this._trackedSnapshots = [];
this._startingIndex = -1;
this._historyIndex = -1;
this._boxWidth = -1;
this._boxHeight = -1;
this._maxSnapshots = this._getMaxSnapshots();
this._lastSwipeDir = "";
this._isVerticalSwipe = false;

// We only want to activate history swipe animations if we store snapshots.
// If we don't store any, we handle horizontal swipes without animations.
Expand All @@ -553,6 +568,7 @@ let gHistorySwipeAnimation = {
gBrowser.addEventListener("pagehide", this, false);
gBrowser.addEventListener("pageshow", this, false);
gBrowser.addEventListener("popstate", this, false);
gBrowser.addEventListener("DOMModalDialogClosed", this, false);
gBrowser.tabContainer.addEventListener("TabClose", this, false);
}
},
Expand All @@ -564,6 +580,7 @@ let gHistorySwipeAnimation = {
gBrowser.removeEventListener("pagehide", this, false);
gBrowser.removeEventListener("pageshow", this, false);
gBrowser.removeEventListener("popstate", this, false);
gBrowser.removeEventListener("DOMModalDialogClosed", this, false);
gBrowser.tabContainer.removeEventListener("TabClose", this, false);

this.active = false;
Expand All @@ -573,17 +590,32 @@ let gHistorySwipeAnimation = {
/**
* Starts the swipe animation and handles fast swiping (i.e. a swipe animation
* is already in progress when a new one is initiated).
*
* @param aIsVerticalSwipe
* Whether we're dealing with a vertical swipe or not.
*/
startAnimation: function HSA_startAnimation() {
startAnimation: function HSA_startAnimation(aIsVerticalSwipe) {
this._isVerticalSwipe = aIsVerticalSwipe;

if (this.isAnimationRunning()) {
gBrowser.stop();
this._lastSwipeDir = "RELOAD"; // just ensure that != ""
this._canGoBack = this.canGoBack();
this._canGoForward = this.canGoForward();
this._handleFastSwiping();
// If this is a horizontal scroll, or if this is a vertical scroll that
// was started while a horizontal scroll was still running, handle it as
// as a fast swipe. In the case of the latter scenario, this allows us to
// start the vertical animation without first loading the final page, or
// taking another snapshot. If vertical scrolls are initiated repeatedly
// without prior horizontal scroll we skip this and restart the animation
// from 0.
if (!this._isVerticalSwipe || this._lastSwipeDir != "") {
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._startingIndex = gBrowser.webNavigation.sessionHistory.index;
this._historyIndex = this._startingIndex;
this._canGoBack = this.canGoBack();
this._canGoForward = this.canGoForward();
if (this.active) {
Expand Down Expand Up @@ -614,20 +646,29 @@ let gHistorySwipeAnimation = {
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.

// We use the following value to decrease the bounce effect when scrolling
// to the top or bottom of the page, or when swiping back/forward past the
// browsing history. This value was determined experimentally.
let dampValue = 4;
if (this._isVerticalSwipe) {
this._prevBox.collapsed = true;
this._nextBox.collapsed = true;
this._positionBox(this._curBox, -1 * aVal / dampValue);
}
else if ((aVal >= 0 && this.isLTR) ||
(aVal <= 0 && !this.isLTR)) {
let tempDampValue = 1;
if (this._canGoBack)
this._prevBox.collapsed = false;
else
else {
tempDampValue = dampValue;
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);
this._positionBox(this._curBox, aVal / tempDampValue);

// The forward page should be pushed offscreen all the way to the right.
this._positionBox(this._nextBox, 1);
Expand All @@ -643,13 +684,14 @@ let gHistorySwipeAnimation = {
// For the backdrop to be visible in that case, the previous page needs
// to be hidden (if it exists).
if (this._canGoForward) {
this._nextBox.collapsed = false;
let offset = this.isLTR ? 1 : -1;
this._positionBox(this._curBox, 0);
this._positionBox(this._nextBox, offset + aVal); // aVal is negative
this._positionBox(this._nextBox, offset + aVal);
}
else {
this._prevBox.collapsed = true;
this._positionBox(this._curBox, aVal);
this._positionBox(this._curBox, aVal / dampValue);
}
}
},
Expand All @@ -666,13 +708,14 @@ let gHistorySwipeAnimation = {
let browser = gBrowser.getBrowserForTab(aEvent.target);
this._removeTrackedSnapshot(-1, browser);
break;
case "DOMModalDialogClosed":
this.stopAnimation();
break;
case "pageshow":
case "popstate":
if (this.isAnimationRunning()) {
if (aEvent.target != gBrowser.selectedBrowser.contentDocument)
break;
this.stopAnimation();
}
if (aEvent.target != gBrowser.selectedBrowser.contentDocument)
break;
this.stopAnimation();
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
break;
case "pagehide":
Expand Down Expand Up @@ -740,7 +783,7 @@ let gHistorySwipeAnimation = {
* any. This will also result in the animation overlay to be torn down.
*/
swipeEndEventReceived: function HSA_swipeEndEventReceived() {
if (this._lastSwipeDir != "")
if (this._lastSwipeDir != "" && this._historyIndex != this._startingIndex)
this._navigateToHistoryIndex();
else
this.stopAnimation();
Expand Down Expand Up @@ -768,9 +811,10 @@ let gHistorySwipeAnimation = {
* |this|.
*/
_navigateToHistoryIndex: function HSA__navigateToHistoryIndex() {
if (this._doesIndexExistInHistory(this._historyIndex)) {
if (this._doesIndexExistInHistory(this._historyIndex))
gBrowser.webNavigation.gotoIndex(this._historyIndex);
}
else
this.stopAnimation();
},

/**
Expand Down Expand Up @@ -816,7 +860,9 @@ let gHistorySwipeAnimation = {
"box");
this._container.appendChild(this._nextBox);

this._boxWidth = this._curBox.getBoundingClientRect().width; // cache width
// Cache width and height.
this._boxWidth = this._curBox.getBoundingClientRect().width;
this._boxHeight = this._curBox.getBoundingClientRect().height;
},

/**
Expand All @@ -830,6 +876,7 @@ let gHistorySwipeAnimation = {
this._container.parentNode.removeChild(this._container);
this._container = null;
this._boxWidth = -1;
this._boxHeight = -1;
},

/**
Expand Down Expand Up @@ -857,7 +904,14 @@ let gHistorySwipeAnimation = {
* 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)";
let transform = "";

if (this._isVerticalSwipe)
transform = "translateY(" + this._boxHeight * aPosition + "px)";
else
transform = "translateX(" + this._boxWidth * aPosition + "px)";

aBox.style.transform = transform;
},

/**
Expand Down Expand Up @@ -996,12 +1050,17 @@ let gHistorySwipeAnimation = {
return aBlob;

let img = new Image();
let url = URL.createObjectURL(aBlob);
img.onload = function() {
URL.revokeObjectURL(url);
};
img.src = url;
return img;
let url = "";
try {
url = URL.createObjectURL(aBlob);
img.onload = function() {
URL.revokeObjectURL(url);
};
}
finally {
img.src = url;
return img;
}
},

/**
Expand Down
15 changes: 14 additions & 1 deletion content/events/src/nsEventStateManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2668,6 +2668,12 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
nsIScrollableFrame* frameToScroll =
lastScrollFrame->GetScrollTargetFrame();
if (frameToScroll) {
nsIFrame* activeRootFrame = nsLayoutUtils::GetActiveScrolledRootFor(
lastScrollFrame, nullptr);
if (!nsLayoutUtils::GetCrossDocParentFrame(activeRootFrame)) {
// Record the fact that the scroll occurred on the top-level page.
aEvent->viewPortIsScrollTargetParent = true;
}
return frameToScroll;
}
}
Expand Down Expand Up @@ -2733,7 +2739,14 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
aOptions =
static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
return newFrame ? ComputeScrollTarget(newFrame, aEvent, aOptions) : nullptr;
if (newFrame) {
return ComputeScrollTarget(newFrame, aEvent, aOptions);
}

// Record the fact that the scroll occurred past the bounds of the top-level
// page.
aEvent->viewPortIsScrollTargetParent = true;
return nullptr;
}

nsSize
Expand Down
6 changes: 4 additions & 2 deletions widget/cocoa/nsChildView.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,8 @@ typedef NSInteger NSEventGestureAxis;

#ifdef __LP64__
// Support for fluid swipe tracking.
void (^mCancelSwipeAnimation)();
BOOL* mCancelSwipeAnimation;
PRUint32 mCurrentSwipeDir;
#endif

// Whether this uses off-main-thread compositing.
Expand Down Expand Up @@ -340,7 +341,8 @@ typedef NSInteger NSEventGestureAxis;
// Support for fluid swipe tracking.
#ifdef __LP64__
- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
scrollOverflow:(double)overflow;
scrollOverflowX:(double)overflowX
scrollOverflowY:(double)overflowY;
#endif

- (void)setUsingOMTCompositor:(BOOL)aUseOMTC;
Expand Down
Loading

0 comments on commit 6d01aff

Please sign in to comment.