Bug 673875 - Reproduce bounce behaviour when reaching top and bottom of documents. r=smichaud, r=felipc

This commit is contained in:
Stephen Pohl 2013-04-12 23:04:52 -04:00
parent c84ddabfa5
commit 6328038298
5 changed files with 273 additions and 149 deletions

View File

@ -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);
@ -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.
@ -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);
}
},
@ -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;
@ -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) {
@ -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);
@ -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);
}
}
},
@ -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":
@ -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();
@ -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();
},
/**
@ -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;
},
/**
@ -830,6 +876,7 @@ let gHistorySwipeAnimation = {
this._container.parentNode.removeChild(this._container);
this._container = null;
this._boxWidth = -1;
this._boxHeight = -1;
},
/**
@ -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;
},
/**
@ -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;
}
},
/**

View File

@ -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;
}
}
@ -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

View File

@ -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.
@ -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;

View File

@ -2217,6 +2217,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
#ifdef __LP64__
mCancelSwipeAnimation = nil;
mCurrentSwipeDir = 0;
#endif
}
@ -3403,18 +3404,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
return eventCancelled; // event cancelled == swipe should start
}
- (void)cancelSwipeIfRunning
{
// Clear gesture state.
mGestureState = eGestureState_None;
if (mCancelSwipeAnimation) {
mCancelSwipeAnimation();
[mCancelSwipeAnimation release];
mCancelSwipeAnimation = nil;
}
}
- (void)sendSwipeEndEvent:(NSEvent *)anEvent
allowedDirections:(PRUint32)aAllowedDirections
{
@ -3427,22 +3416,24 @@ NSEvent* gLastDragMouseDownEvent = nil;
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
// Support fluid swipe tracking on OS X 10.7 and higher. We must be careful
// to only invoke this support on a two-finger gesture that really
// is a swipe (and not a scroll) -- in other words, the app is responsible
// for deciding which is which. But once the decision is made, the OS tracks
// for deciding which is which. But once the decision is made, the OS tracks
// the swipe until it has finished, and decides whether or not it succeeded.
// A swipe has the same functionality as the Back and Forward buttons. For
// now swipe animation is unsupported (e.g. no bounces). This method is
// partly based on Apple sample code available at
// http://developer.apple.com/library/mac/#releasenotes/Cocoa/AppKit.html
// A horizontal swipe has the same functionality as the Back and Forward
// buttons.
// This method is partly based on Apple sample code available at
// developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html
// (under Fluid Swipe Tracking API).
- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
scrollOverflow:(double)overflow
scrollOverflowX:(double)overflowX
scrollOverflowY:(double)overflowY
{
if (!nsCocoaFeatures::OnLionOrLater()) {
return;
}
// This method checks whether the AppleEnableSwipeNavigateWithScrolls global
// preference is set. If it isn't, fluid swipe tracking is disabled, and a
// horizontal two-finger gesture is always a scroll (even in Safari). This
@ -3451,65 +3442,111 @@ NSEvent* gLastDragMouseDownEvent = nil;
if (![NSEvent isSwipeTrackingFromScrollEventsEnabled]) {
return;
}
if ([anEvent type] != NSScrollWheel) {
// Verify that this is a scroll wheel event with proper phase to be tracked
// by the OS.
if ([anEvent type] != NSScrollWheel || [anEvent phase] == NSEventPhaseNone) {
return;
}
// 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
// NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events).
// nsMouseScrollEvent.scrollOverflow only indicates left or right overflow
// for horizontal NS_MOUSE_PIXEL_SCROLL events.
if (!overflow) {
return;
}
// Only initiate tracking for gestures that have just begun -- otherwise a
// scroll to one side of the page can have a swipe tacked on to it.
if ([anEvent phase] != NSEventPhaseBegan) {
// the current page (as indicated by 'overflowX' or 'overflowY' being
// non-zero). Gecko only sets nsMouseScrollEvent.scrollOverflow when it's
// processing NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events).
if (overflowX == 0.0 && overflowY == 0.0) {
return;
}
CGFloat deltaX, deltaY;
if ([anEvent hasPreciseScrollingDeltas]) {
deltaX = [anEvent scrollingDeltaX];
deltaY = [anEvent scrollingDeltaY];
} else {
deltaX = [anEvent deltaX];
deltaY = [anEvent deltaY];
}
// Only initiate tracking for events whose horizontal element is at least
// eight times larger than its vertical element. This minimizes performance
// problems with vertical scrolls (by minimizing the possibility that they'll
// be misinterpreted as horizontal swipes), while still tolerating a small
// vertical element to a true horizontal swipe. The number '8' was arrived
// at by trial and error.
if ((deltaX == 0) || (fabs(deltaX) <= fabs(deltaY) * 8)) {
else {
return;
}
// If a swipe is currently being tracked kill it -- it's been interrupted by
// another gesture or legacy scroll wheel event.
[self cancelSwipeIfRunning];
PRUint32 vDirs = (PRUint32)nsIDOMSimpleGestureEvent::DIRECTION_DOWN |
(PRUint32)nsIDOMSimpleGestureEvent::DIRECTION_UP;
PRUint32 direction = 0;
// Only initiate horizontal tracking for events whose horizontal element is
// at least eight times larger than its vertical element. This minimizes
// performance problems with vertical scrolls (by minimizing the possibility
// that they'll be misinterpreted as horizontal swipes), while still
// tolerating a small vertical element to a true horizontal swipe. The number
// '8' was arrived at by trial and error.
if (overflowX != 0.0 && deltaX != 0.0 &&
fabsf(deltaX) > fabsf(deltaY) * 8) {
// Only initiate horizontal tracking for gestures that have just begun --
// otherwise a scroll to one side of the page can have a swipe tacked on
// to it.
if ([anEvent phase] != NSEventPhaseBegan)
return;
if (deltaX < 0.0)
direction = (PRUint32)nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
else
direction = (PRUint32)nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
}
// Only initiate vertical tracking for events whose vertical element is
// at least two times larger than its horizontal element. This minimizes
// performance problems. The number '2' was arrived at by trial and error.
else if (overflowY != 0.0 && deltaY != 0.0 &&
fabsf(deltaY) > fabsf(deltaX) * 2) {
if (deltaY < 0.0)
direction = (PRUint32)nsIDOMSimpleGestureEvent::DIRECTION_DOWN;
else
direction = (PRUint32)nsIDOMSimpleGestureEvent::DIRECTION_UP;
if ((mCurrentSwipeDir & vDirs) && (mCurrentSwipeDir != direction)) {
// If a swipe is currently being tracked kill it -- it's been interrupted
// by another gesture event.
if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
*mCancelSwipeAnimation = YES;
mCancelSwipeAnimation = nil;
[self sendSwipeEndEvent:anEvent allowedDirections:0];
}
return;
}
}
else {
return;
}
// Track the direction we're going in.
mCurrentSwipeDir = direction;
// If a swipe is currently being tracked kill it -- it's been interrupted
// by another gesture event.
if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
*mCancelSwipeAnimation = YES;
mCancelSwipeAnimation = nil;
}
PRUint32 allowedDirections = 0;
// 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];
withKind:NS_SIMPLE_GESTURE_SWIPE_START
allowedDirections:&allowedDirections
direction:direction
delta:0.0];
if (!shouldStartSwipe) {
return;
}
double min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ? -1 : 0;
double max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ? 1 : 0;
CGFloat min = 0.0;
CGFloat max = 0.0;
if (!(direction & vDirs)) {
min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ?
-1.0 : 0.0;
max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ?
1.0 : 0.0;
}
__block BOOL animationCancelled = NO;
__block BOOL geckoSwipeEventSent = NO;
__block BOOL animationCanceled = NO;
// At this point, anEvent is the first scroll wheel event in a two-finger
// horizontal gesture that we've decided to treat as a swipe. When we call
// [NSEvent trackSwipeEventWithOptions:...], the OS interprets all
@ -3525,67 +3562,72 @@ 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:NSEventSwipeTrackingLockDirection
[anEvent trackSwipeEventWithOptions:NSEventSwipeTrackingLockDirection |
NSEventSwipeTrackingClampGestureAmount
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
// destroyed).
if (animationCancelled || !mGeckoChild) {
*stop = YES;
return;
usingHandler:^(CGFloat gestureAmount,
NSEventPhase phase,
BOOL isComplete,
BOOL *stop) {
PRUint32 allowedDirectionsCopy = allowedDirections;
// Since this tracking handler can be called asynchronously, mGeckoChild
// might have become NULL here (our child widget might have been
// destroyed).
// Checking for gestureAmount == 0.0 also works around bug 770626, which
// happens when DispatchWindowEvent() triggers a modal dialog, which spins
// the event loop and confuses the OS. This results in several re-entrant
// calls to this handler.
if (animationCanceled || !mGeckoChild || gestureAmount == 0.0) {
*stop = YES;
animationCanceled = YES;
if (gestureAmount == 0.0 ||
((direction & vDirs) && (direction != mCurrentSwipeDir))) {
if (mCancelSwipeAnimation)
*mCancelSwipeAnimation = YES;
mCancelSwipeAnimation = nil;
[self sendSwipeEndEvent:anEvent
allowedDirections:allowedDirectionsCopy];
}
mCurrentSwipeDir = 0;
return;
}
PRUint32 allowedDirectionsCopy = allowedDirections;
// Update animation overlay to match gestureAmount.
[self sendSwipeEvent:anEvent
withKind:NS_SIMPLE_GESTURE_SWIPE_UPDATE
allowedDirections:&allowedDirectionsCopy
direction:0.0
delta:gestureAmount];
// Update animation overlay to match gestureAmount.
if (phase == NSEventPhaseEnded) {
// 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.
PRUint32 directionCopy = direction;
// 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.
[self sendSwipeEvent:anEvent
withKind:NS_SIMPLE_GESTURE_SWIPE_UPDATE
withKind:NS_SIMPLE_GESTURE_SWIPE
allowedDirections:&allowedDirectionsCopy
direction:0
delta:gestureAmount];
direction:directionCopy
delta:0.0];
}
if (phase == NSEventPhaseEnded && !geckoSwipeEventSent) {
// 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 sendSwipeEndEvent:anEvent allowedDirections:allowedDirectionsCopy];
mCurrentSwipeDir = 0;
mCancelSwipeAnimation = nil;
}
}];
if (isComplete) {
[self cancelSwipeIfRunning];
[self sendSwipeEndEvent:anEvent allowedDirections:allowedDirections];
}
}];
mCancelSwipeAnimation = [^{
animationCancelled = YES;
} copy];
mCancelSwipeAnimation = &animationCanceled;
}
#endif // #ifdef __LP64__
@ -3712,7 +3754,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
nsAutoRetainCocoaObject kungFuDeathGrip(self);
NPCocoaEvent cocoaEvent;
nsMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_UP, mGeckoChild, nsMouseEvent::eReal);
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
if ([theEvent modifierFlags] & NSControlKeyMask)
@ -4148,12 +4190,14 @@ static int32_t RoundUp(double aDouble)
}
#ifdef __LP64__
// overflowDeltaX tells us when the user has tried to scroll past the edge
// of a page to the left or the right (in those cases it's non-zero).
if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL &&
wheelEvent.deltaX != 0.0) {
// overflowDeltaX and overflowDeltaY tell us when the user has tried to
// scroll past the edge of a page (in those cases it's non-zero).
if ((wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) &&
(wheelEvent.viewPortIsScrollTargetParent) &&
(wheelEvent.deltaX != 0.0 || wheelEvent.deltaY != 0.0)) {
[self maybeTrackScrollEventAsSwipe:theEvent
scrollOverflow:wheelEvent.overflowDeltaX];
scrollOverflowX:wheelEvent.overflowDeltaX
scrollOverflowY:wheelEvent.overflowDeltaY];
}
#endif // #ifdef __LP64__

View File

@ -1306,7 +1306,8 @@ public:
deltaMode(nsIDOMWheelEvent::DOM_DELTA_PIXEL),
customizedByUserPrefs(false), isMomentum(false), isPixelOnlyDevice(false),
lineOrPageDeltaX(0), lineOrPageDeltaY(0), scrollType(SCROLL_DEFAULT),
overflowDeltaX(0.0), overflowDeltaY(0.0)
overflowDeltaX(0.0), overflowDeltaY(0.0),
viewPortIsScrollTargetParent(false)
{
}
@ -1385,6 +1386,11 @@ public:
// it would need to check the deltaX and deltaY.
double overflowDeltaX;
double overflowDeltaY;
// Whether or not the parent of the currently scrolled frame is the ViewPort.
// This is false in situations when an element on the page is being scrolled
// (such as a text field), but true when the 'page' is being scrolled.
bool viewPortIsScrollTargetParent;
};
} // namespace widget