Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(522)

Unified Diff: chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm

Issue 300863002: mac: History swiping doesn't work right with iframes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix unit tests. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm
index 47f795edf3d55dcf6cecc0e88c1599affdcd062e..f147bd5542d7a75ddc21926f9b766de58a8849e1 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm
@@ -4,18 +4,46 @@
#import "chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.h"
+#import "base/mac/sdk_forward_declarations.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
-
-#import "base/mac/sdk_forward_declarations.h"
#import "chrome/browser/ui/cocoa/history_overlay_controller.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
// Once we call `[NSEvent trackSwipeEventWithOptions:]`, we cannot reliably
// expect NSTouch callbacks. We set this variable to YES and ignore NSTouch
// callbacks.
static BOOL forceMagicMouse = NO;
Avi (use Gerrit) 2014/05/29 15:02:01 Move this inside the anon namespace below and drop
erikchen 2014/05/29 20:42:38 Done.
+namespace {
+// The horizontal distance required to cause the browser to perform a history
+// navigation.
+const CGFloat kHistorySwipeThreshold = 0.08;
+// The horizontal distance required for this class to start consuming events,
+// which stops the events from reaching the renderer.
+const CGFloat kConsumeEventThreshold = 0.01;
+// If there has been sufficient vertical motion, the gesture can't be intended
+// for history swiping.
+const CGFloat kCancelEventVerticalThreshold = 0.24;
+// If there has been sufficient vertical motion, and more vertical than
+// horizontal motion, the gesture can't be intended for history swiping.
+const CGFloat kCancelEventVerticalLowerThreshold = 0.01;
+} // namespace
Avi (use Gerrit) 2014/05/29 15:02:01 CrOS has a history swipe, and I'm curious as to ho
erikchen 2014/05/29 20:42:38 Not really. :( Though the infrastructure is genera
Avi (use Gerrit) 2014/05/29 20:48:56 Gotcha. Good to hear that you're going to be unif
+
+@interface HistorySwiper ()
+// Given a touch event, returns the average touch position.
+- (NSPoint)averagePositionInEvent:(NSEvent*)event;
+// Updates internal state with the location information from the touch event.
+- (void)updateGestureCurrentPointFromEvent:(NSEvent*)event;
+// Updates the state machine with the given touch event.
+// Returns NO if no further processing of the event should happen.
+- (BOOL)processTouchEventForHistorySwiping:(NSEvent*)event;
+// Returns whether the wheel event should be consumed, and not passed to the
+// renderer.
+- (BOOL)shouldConsumeWheelEvent:(NSEvent*)event;
+@end
Avi (use Gerrit) 2014/05/29 15:02:01 For this and the anon namespace above, put blank l
erikchen 2014/05/29 20:42:38 Done.
+
@implementation HistorySwiper
@synthesize delegate = delegate_;
@@ -43,17 +71,11 @@ static BOOL forceMagicMouse = NO;
return NO;
}
-- (void)gotUnhandledWheelEvent {
- gotUnhandledWheelEvent_ = YES;
-}
-
-- (void)scrollOffsetPinnedToLeft:(BOOL)left toRight:(BOOL)right {
- isPinnedLeft_ = left;
- isPinnedRight_ = right;
-}
-
-- (void)setHasHorizontalScrollbar:(BOOL)hasHorizontalScrollbar {
- hasHorizontalScrollbar_ = hasHorizontalScrollbar;
+- (void)rendererHandledWheelEvent:(const blink::WebMouseWheelEvent&)event
+ consumed:(BOOL)consumed {
+ if (event.phase != NSEventPhaseBegan)
+ return;
+ beganEventUnconsumed_ = !consumed;
}
- (BOOL)canRubberbandLeft:(NSView*)view {
@@ -66,7 +88,7 @@ static BOOL forceMagicMouse = NO;
// History swiping is possible. By default, disallow rubberbanding. If the
// user has both started, and then cancelled history swiping for this
// gesture, allow rubberbanding.
- return inGesture_ && historySwipeCancelled_;
+ return inGesture_ && recognitionState_ == history_swiper::kCancelled;
}
- (BOOL)canRubberbandRight:(NSView*)view {
@@ -79,7 +101,7 @@ static BOOL forceMagicMouse = NO;
// History swiping is possible. By default, disallow rubberbanding. If the
// user has both started, and then cancelled history swiping for this
// gesture, allow rubberbanding.
- return inGesture_ && historySwipeCancelled_;
+ return inGesture_ && recognitionState_ == history_swiper::kCancelled;
}
// Is is theoretically possible for multiple simultaneous gestures to occur, if
@@ -91,11 +113,11 @@ static BOOL forceMagicMouse = NO;
inGesture_ = YES;
++currentGestureId_;
// Reset state pertaining to previous gestures.
- historySwipeCancelled_ = NO;
gestureStartPointValid_ = NO;
- gotUnhandledWheelEvent_ = NO;
receivedTouch_ = NO;
mouseScrollDelta_ = NSZeroSize;
+ beganEventUnconsumed_ = NO;
+ recognitionState_ = history_swiper::kPending;
}
- (void)endGestureWithEvent:(NSEvent*)event {
@@ -147,75 +169,104 @@ static BOOL forceMagicMouse = NO;
}
- (void)touchesMovedWithEvent:(NSEvent*)event {
- receivedTouch_ = YES;
- if (![self shouldProcessEventForHistorySwiping:event])
- return;
-
- [self updateGestureCurrentPointFromEvent:event];
-
- if (historyOverlay_) {
- // Consider cancelling the history swipe gesture.
- if ([self shouldCancelHorizontalSwipeWithCurrentPoint:gestureCurrentPoint_
- startPoint:gestureStartPoint_]) {
- [self cancelHistorySwipe];
- return;
- }
-
- [self updateProgressBar];
- }
+ [self processTouchEventForHistorySwiping:event];
}
+
- (void)touchesCancelledWithEvent:(NSEvent*)event {
- receivedTouch_ = YES;
- if (![self shouldProcessEventForHistorySwiping:event])
+ if (![self processTouchEventForHistorySwiping:event])
return;
- if (historyOverlay_)
- [self cancelHistorySwipe];
+ [self cancelHistorySwipe];
}
+
- (void)touchesEndedWithEvent:(NSEvent*)event {
- receivedTouch_ = YES;
- if (![self shouldProcessEventForHistorySwiping:event])
+ if (![self processTouchEventForHistorySwiping:event])
return;
- [self updateGestureCurrentPointFromEvent:event];
if (historyOverlay_) {
BOOL finished = [self updateProgressBar];
// If the gesture was completed, perform a navigation.
- if (finished) {
+ if (finished)
[self navigateBrowserInDirection:historySwipeDirection_];
- }
// Remove the history overlay.
[self endHistorySwipe];
+ // The gesture was completed.
+ recognitionState_ = history_swiper::kCompleted;
}
}
-- (BOOL)shouldProcessEventForHistorySwiping:(NSEvent*)event {
- // TODO(erikchen): what is the point of NSEventTypeSwipe and NSScrollWheel?
+- (BOOL)processTouchEventForHistorySwiping:(NSEvent*)event {
+ receivedTouch_ = YES;
+
NSEventType type = [event type];
- return type == NSEventTypeBeginGesture || type == NSEventTypeEndGesture ||
- type == NSEventTypeGesture;
+ if (type != NSEventTypeBeginGesture && type != NSEventTypeEndGesture &&
+ type != NSEventTypeGesture) {
+ return NO;
+ }
+
+ switch (recognitionState_) {
+ case history_swiper::kCancelled:
+ case history_swiper::kCompleted:
+ return NO;
+ case history_swiper::kPending:
+ [self updateGestureCurrentPointFromEvent:event];
+ return NO;
+ case history_swiper::kPotential:
+ case history_swiper::kTracking:
+ break;
+ }
+
+ [self updateGestureCurrentPointFromEvent:event];
+
+ // Consider cancelling the history swipe gesture.
+ if ([self shouldCancelHorizontalSwipeWithCurrentPoint:gestureCurrentPoint_
+ startPoint:gestureStartPoint_]) {
+ [self cancelHistorySwipe];
+ return NO;
+ }
+
+ if (recognitionState_ == history_swiper::kPotential) {
+ // The user is in the process of doing history swiping. If the history
+ // swipe has progressed sufficiently far, stop sending events to the
+ // renderer.
+ BOOL sufficientlyFar = fabs(gestureCurrentPoint_.x - gestureStartPoint_.x) >
+ kConsumeEventThreshold;
+ if (sufficientlyFar)
+ recognitionState_ = history_swiper::kTracking;
+ }
+
+ if (historyOverlay_)
+ [self updateProgressBar];
+ return YES;
}
// Consider cancelling the horizontal swipe if the user was intending a
// vertical swipe.
- (BOOL)shouldCancelHorizontalSwipeWithCurrentPoint:(NSPoint)currentPoint
startPoint:(NSPoint)startPoint {
- // There's been more vertical distance than horizontal distance.
CGFloat yDelta = fabs(currentPoint.y - startPoint.y);
CGFloat xDelta = fabs(currentPoint.x - startPoint.x);
- BOOL moreVertThanHoriz = yDelta > xDelta && yDelta > 0.1;
+
+ // The gesture is pretty clearly more vertical than horizontal.
+ if (yDelta > 2 * xDelta)
+ return YES;
+
+ // There's been more vertical distance than horizontal distance.
+ if (yDelta * 1.3 > xDelta && yDelta > kCancelEventVerticalLowerThreshold)
+ return YES;
// There's been a lot of vertical distance.
- BOOL muchVert = yDelta > 0.32;
+ if (yDelta > kCancelEventVerticalThreshold)
+ return YES;
- return moreVertThanHoriz || muchVert;
+ return NO;
}
- (void)cancelHistorySwipe {
[self endHistorySwipe];
- historySwipeCancelled_ = YES;
+ recognitionState_ = history_swiper::kCancelled;
}
- (void)endHistorySwipe {
@@ -232,9 +283,7 @@ static BOOL forceMagicMouse = NO;
float progress = 0;
BOOL finished = NO;
- // This value was determined by experimentation.
- CGFloat requiredSwipeDistance = 0.08;
- progress = (currentPoint.x - startPoint.x) / requiredSwipeDistance;
+ progress = (currentPoint.x - startPoint.x) / kHistorySwipeThreshold;
// If the swipe is a backwards gesture, we need to invert progress.
if (historySwipeDirection_ == history_swiper::kBackwards)
progress *= -1;
@@ -343,14 +392,6 @@ static BOOL forceMagicMouse = NO;
if (!browserCanMove)
return NO;
- if (isRightScroll) {
- if (hasHorizontalScrollbar_ && !isPinnedRight_)
- return NO;
- } else {
- if (hasHorizontalScrollbar_ && !isPinnedLeft_)
- return NO;
- }
-
[self initiateMagicMouseHistorySwipe:isRightScroll event:theEvent];
return YES;
}
@@ -456,30 +497,24 @@ static BOOL forceMagicMouse = NO;
if (![theEvent respondsToSelector:@selector(phase)])
return NO;
- // Check for regular mouse wheel scroll events.
- if ([theEvent phase] == NSEventPhaseNone &&
- [theEvent momentumPhase] == NSEventPhaseNone) {
+ // The only events that this class consumes have type NSEventPhaseChanged.
+ // This simultaneously weeds our regular mouse wheel scroll events, and
+ // gesture events with incorrect phase.
+ if ([theEvent phase] != NSEventPhaseChanged &&
+ [theEvent momentumPhase] != NSEventPhaseChanged) {
return NO;
}
// We've already processed this gesture.
- if (lastProcessedGestureId_ == currentGestureId_) {
- // A new event may come in before it's recognized as a gesture.
- // We have not yet reset the state from the last gesture.
- // Let it pass through.
- if ([theEvent phase] == NSEventPhaseBegan ||
- [theEvent phase] == NSEventPhaseMayBegin) {
- return NO;
- }
-
- // The user cancelled the history swiper. Ignore all events.
- if (historySwipeCancelled_)
- return NO;
-
- // The user completed the history swiper. Swallow all events.
- return YES;
+ if (lastProcessedGestureId_ == currentGestureId_ &&
+ recognitionState_ != history_swiper::kPending) {
+ return [self shouldConsumeWheelEvent:theEvent];
}
+ // Don't allow momentum events to start history swiping.
+ if ([theEvent momentumPhase] != NSEventPhaseNone)
+ return NO;
+
BOOL systemSettingsValid = [self systemSettingsAllowHistorySwiping:theEvent];
if (!systemSettingsValid)
return NO;
@@ -487,52 +522,24 @@ static BOOL forceMagicMouse = NO;
if (![delegate_ shouldAllowHistorySwiping])
return NO;
- // Don't even consider enabling history swiping until blink has decided it is
- // not going to handle the event.
- if (!gotUnhandledWheelEvent_)
- return NO;
-
- // If the window has a horizontal scroll bar, sometimes Cocoa gets confused
- // and sends us momentum scroll wheel events instead of gesture scroll events
- // (even though the user is still actively swiping).
- if ([theEvent phase] != NSEventPhaseChanged &&
- [theEvent momentumPhase] != NSEventPhaseChanged) {
+ // Don't enable history swiping until the renderer has decided to not consume
+ // the event with phase NSEventPhaseBegan.
+ if (!beganEventUnconsumed_)
return NO;
- }
if (!inGesture_)
return NO;
- if (!receivedTouch_ || forceMagicMouse) {
+ if (!receivedTouch_ || forceMagicMouse)
return [self maybeHandleMagicMouseHistorySwiping:theEvent];
- }
- CGFloat yDelta = gestureCurrentPoint_.y - gestureStartPoint_.y;
CGFloat xDelta = gestureCurrentPoint_.x - gestureStartPoint_.x;
- // Require the user's gesture to have moved more than a minimal amount.
- if (fabs(xDelta) < 0.01)
- return NO;
-
- // Require the user's gesture to be slightly more horizontal than vertical.
- BOOL isHorizontalGesture = fabs(xDelta) > 1.3 * fabs(yDelta);
-
- if (!isHorizontalGesture)
- return NO;
-
BOOL isRightScroll = xDelta > 0;
BOOL inverted = [self isEventDirectionInverted:theEvent];
if (inverted)
isRightScroll = !isRightScroll;
- if (isRightScroll) {
- if (hasHorizontalScrollbar_ && !isPinnedRight_)
- return NO;
- } else {
- if (hasHorizontalScrollbar_ && !isPinnedLeft_)
- return NO;
- }
-
history_swiper::NavigationDirection direction =
isRightScroll ? history_swiper::kForwards : history_swiper::kBackwards;
BOOL browserCanMove =
@@ -542,7 +549,24 @@ static BOOL forceMagicMouse = NO;
lastProcessedGestureId_ = currentGestureId_;
[self beginHistorySwipeInDirection:direction event:theEvent];
- return YES;
+ recognitionState_ = history_swiper::kPotential;
+ return [self shouldConsumeWheelEvent:theEvent];
+}
+
+- (BOOL)shouldConsumeWheelEvent:(NSEvent*)event {
+ switch (recognitionState_) {
+ case history_swiper::kPending:
+ case history_swiper::kCancelled:
+ return NO;
+ case history_swiper::kTracking:
+ case history_swiper::kCompleted:
+ return YES;
+ case history_swiper::kPotential:
+ // It is unclear whether the user is attempting to perform history
+ // swiping. If the event has a vertical component, send it on to the
+ // renderer.
+ return event.scrollingDeltaY == 0;
+ }
}
@end

Powered by Google App Engine
This is Rietveld 408576698