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

Unified Diff: content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm

Issue 314393003: mac: Add overscroll animator slider (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 6 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: content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm
diff --git a/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm b/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..ebd3c2aaea016e08cc61bf7d8e9a823285a92fd2
--- /dev/null
+++ b/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm
@@ -0,0 +1,259 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.h"
+
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/web_contents_observer.h"
+#import <QuartzCore/QuartzCore.h>
Avi (use Gerrit) 2014/06/06 23:09:45 This import gets its own section.
erikchen 2014/06/07 00:34:04 Done.
+
+namespace {
+// The minimum possible progress of an overscroll animation.
+CGFloat kMinProgress = 0;
+// The maximum possible progress of an overscroll animation.
+CGFloat kMaxProgress = 2.0;
+// The maximum duration of the completion or cancellation animations. The
+// effective maximum is half of this value, since the longest animation is from
+// progress_ = 1 to progress = 2.0;
Avi (use Gerrit) 2014/06/06 23:09:45 either progress_ or progress.
erikchen 2014/06/07 00:34:04 I switched to "progress" for both.
+CGFloat kMaxAnimationDuration = 0.2;
+}
+
+// OverscrollAnimatorSliderView Private Category -------------------------------
+
+@interface OverscrollAnimatorSliderView ()
+// Callback from WebContentsPaintObserver.
+- (void)webContentsFinishedNonEmptyPaint;
+
+// Resets overscroll animation state.
+- (void)reset;
+
+// Given a |progress| from 0 to 2, the expected frame origin of the -movingView.
+- (NSPoint)frameOriginWithProgress:(CGFloat)progress;
+
+// The NSView that is moving during the overscroll animation.
+- (NSView*)movingView;
+
+// The expected duration of an animation from progress_ to |progress|
+- (CGFloat)animationDurationForProgress:(CGFloat)progress;
+
+// NSView override. During an overscroll animation, the cursor may no longer
+// rest on the RenderWidgetHost's NativeView, which prevents wheel events from
+// reaching the NativeView. The overscroll animation is driven by wheel events
+// so they must be explicitly forwarded to the NativeView.
+- (void)scrollWheel:(NSEvent*)event;
+@end
+
+// Helper Class (ResizingView) -------------------------------------------------
+
+// This NSView subclass is intended to be the RenderWidgetHost's NativeView's
+// parent NSView. It is possible for the RenderWidgetHost's NativeView's size to
+// become out of sync with its parent NSView. The override of
+// -resizeSubviewsWithOldSize: ensures that the sizes will eventually become
+// consistent.
+// http://crbug.com/264207)
Avi (use Gerrit) 2014/06/06 23:09:45 unbalanced parenthesis.
erikchen 2014/06/07 00:34:04 removed.
+@interface ResizingView : NSView
+@end
+
+@implementation ResizingView
+- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
+ for (NSView* subview in self.subviews)
+ [subview setFrame:self.bounds];
+}
+@end
+
+// Helper Class (WebContentsPaintObserver) -------------------------------------
+
+namespace content {
Avi (use Gerrit) 2014/06/06 23:09:45 put this in an anon namespace
erikchen 2014/06/07 00:34:04 that's doesn't work, as this class has a forward d
+class WebContentsPaintObserver : public WebContentsObserver {
+ public:
+ WebContentsPaintObserver(WebContents* web_contents,
+ OverscrollAnimatorSliderView* slider_view)
+ : WebContentsObserver(web_contents), slider_view_(slider_view) {}
+
+ virtual void DidFirstVisuallyNonEmptyPaint() OVERRIDE {
+ [slider_view_ webContentsFinishedNonEmptyPaint];
+ }
+
+ private:
+ OverscrollAnimatorSliderView* slider_view_; // Weak reference.
+};
+}
+
+// OverscrollAnimatorSliderView Implementation ---------------------------------
+
+@implementation OverscrollAnimatorSliderView
+
+- (instancetype)initWithFrame:(NSRect)frame {
+ self = [super initWithFrame:frame];
+ if (self) {
+ bottomView_.reset([[NSImageView alloc] initWithFrame:self.bounds]);
+ bottomView_.get().imageScaling = NSImageScaleNone;
+ bottomView_.get().autoresizingMask =
+ NSViewWidthSizable | NSViewHeightSizable;
+ bottomView_.get().imageAlignment = NSImageAlignTop;
+ [self addSubview:bottomView_];
+ middleView_.reset([[ResizingView alloc] initWithFrame:self.bounds]);
+ middleView_.get().autoresizingMask =
+ NSViewWidthSizable | NSViewHeightSizable;
+ [self addSubview:middleView_];
+ topView_.reset([[NSImageView alloc] initWithFrame:self.bounds]);
+ topView_.get().autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
+ topView_.get().imageScaling = NSImageScaleNone;
+ topView_.get().imageAlignment = NSImageAlignTop;
+ [self addSubview:topView_];
+
+ [self reset];
+ }
+ return self;
+}
+
+- (void)webContentsFinishedNonEmptyPaint {
+ observer_.reset();
+ [self reset];
+}
+
+- (void)reset {
+ DCHECK(!animating_);
+ inOverscroll_ = NO;
+ progress_ = kMinProgress;
+
+ [CATransaction begin];
+ [CATransaction setDisableActions:YES];
+ bottomView_.get().hidden = YES;
+ middleView_.get().hidden = NO;
+ topView_.get().hidden = YES;
+
+ [bottomView_ setFrameOrigin:NSMakePoint(0, 0)];
+ [middleView_ setFrameOrigin:NSMakePoint(0, 0)];
+ [topView_ setFrameOrigin:NSMakePoint(0, 0)];
+ [CATransaction commit];
+}
+
+- (NSPoint)frameOriginWithProgress:(CGFloat)progress {
+ if (slidingLeft_)
+ return NSMakePoint(progress / kMaxProgress * self.bounds.size.width, 0);
+ return NSMakePoint((1 - progress / kMaxProgress) * self.bounds.size.width, 0);
+}
+
+- (NSView*)movingView {
+ if (slidingLeft_)
+ return middleView_;
+ return topView_;
+}
+
+- (CGFloat)animationDurationForProgress:(CGFloat)progress {
+ CGFloat progressPercentage =
+ fabs(progress_ - progress) / (kMaxProgress - kMinProgress);
+ return progressPercentage * kMaxAnimationDuration;
+}
+
+- (void)scrollWheel:(NSEvent*)event {
+ NSView* latestRenderWidgetHostView = [[middleView_ subviews] lastObject];
+ [latestRenderWidgetHostView scrollWheel:event];
+}
+
+// WebContentsOverscrollAnimator Implementation --------------------------------
+
+- (void)beginOverscrollLeft:(BOOL)left {
+ if (animating_ || inOverscroll_)
+ return;
+
+ inOverscroll_ = YES;
+ slidingLeft_ = left;
+ if (left) {
+ // The middleView_ will slide to the right, revealing bottomView_.
+ bottomView_.get().hidden = NO;
+ } else {
+ // The topView_ will slide in from the right, concealing middleView_.
+ topView_.get().hidden = NO;
+ [topView_ setFrameOrigin:NSMakePoint(self.bounds.size.width, 0)];
+ }
+
+ [self updateOverscrollProgress:kMinProgress];
+}
+
+- (BOOL)needsNavigationSnapshot {
+ return YES;
+}
+
+- (void)supplyNavigationSnapshot:(NSImage*)image {
+ if (slidingLeft_)
+ [bottomView_ setImage:image];
+ else
+ [topView_ setImage:image];
+}
+
+- (void)addRenderWidgetHostNativeView:(NSView*)view {
+ [middleView_ addSubview:view];
+}
+
+- (void)updateOverscrollProgress:(CGFloat)progress {
+ if (animating_)
+ return;
+ DCHECK_LT(progress, kMaxProgress + 0.00001);
+ DCHECK_GT(progress, kMinProgress - 0.00001);
Avi (use Gerrit) 2014/06/06 23:09:45 Why not DCHECK_LE and DCHECK_GE?
erikchen 2014/06/07 00:34:04 Equality comparisons aren't particularly useful fo
Avi (use Gerrit) 2014/06/07 02:57:32 They are. Your values, kMax|MinProgress are 0 and
+ progress_ = progress;
+ [[self movingView] setFrameOrigin:[self frameOriginWithProgress:progress]];
+}
+
+- (void)completeOverscroll:(content::WebContentsImpl*)webContents {
+ if (animating_ || !inOverscroll_)
+ return;
+
+ animating_ = YES;
+
+ NSView* view = [self movingView];
+ [NSAnimationContext beginGrouping];
+ [NSAnimationContext currentContext].duration =
+ [self animationDurationForProgress:kMaxProgress];
+ [[NSAnimationContext currentContext] setCompletionHandler:^{
erikchen 2014/06/06 22:44:56 This API is only available in 10.7+, but the relev
Avi (use Gerrit) 2014/06/06 23:09:45 If you're guaranteed that you never will come thro
erikchen 2014/06/07 00:34:04 Done.
+ animating_ = NO;
+
+ // Animation is complete. Now perform page load.
+ if (slidingLeft_)
+ webContents->GetController().GoBack();
+ else
+ webContents->GetController().GoForward();
+
+ // Reset the position of the middleView_, but wait for the page to paint
+ // before showing it.
+ middleView_.get().hidden = YES;
+ [middleView_ setFrameOrigin:NSMakePoint(0, 0)];
+ observer_.reset(new content::WebContentsPaintObserver(webContents, self));
+ }];
+
+ // Animate the moving view to its final position.
+ [[view animator] setFrameOrigin:[self frameOriginWithProgress:kMaxProgress]];
+
+ [NSAnimationContext endGrouping];
+}
+
+- (void)cancelOverscroll {
+ if (animating_)
+ return;
+
+ if (!inOverscroll_) {
+ [self reset];
+ return;
+ }
+
+ animating_ = YES;
+
+ NSView* view = [self movingView];
+ [NSAnimationContext beginGrouping];
erikchen 2014/06/06 22:44:56 Everything but the block can be shared with -compl
Avi (use Gerrit) 2014/06/06 23:09:45 Yes, there's duplication, but I don't see a ton of
+ [NSAnimationContext currentContext].duration =
+ [self animationDurationForProgress:kMinProgress];
+ [[NSAnimationContext currentContext] setCompletionHandler:^{
+ // Animation is complete. Reset the state.
+ animating_ = NO;
+ [self reset];
+ }];
+
+ // Animate the moving view to its initial position.
+ [[view animator] setFrameOrigin:[self frameOriginWithProgress:kMinProgress]];
+
+ [NSAnimationContext endGrouping];
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698