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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/web_contents/web_contents_view_overscroll_animator_sli der_mac.h"
6
7 #include "content/browser/web_contents/web_contents_impl.h"
8 #include "content/public/browser/web_contents_observer.h"
9 #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.
10
11 namespace {
12 // The minimum possible progress of an overscroll animation.
13 CGFloat kMinProgress = 0;
14 // The maximum possible progress of an overscroll animation.
15 CGFloat kMaxProgress = 2.0;
16 // The maximum duration of the completion or cancellation animations. The
17 // effective maximum is half of this value, since the longest animation is from
18 // 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.
19 CGFloat kMaxAnimationDuration = 0.2;
20 }
21
22 // OverscrollAnimatorSliderView Private Category -------------------------------
23
24 @interface OverscrollAnimatorSliderView ()
25 // Callback from WebContentsPaintObserver.
26 - (void)webContentsFinishedNonEmptyPaint;
27
28 // Resets overscroll animation state.
29 - (void)reset;
30
31 // Given a |progress| from 0 to 2, the expected frame origin of the -movingView.
32 - (NSPoint)frameOriginWithProgress:(CGFloat)progress;
33
34 // The NSView that is moving during the overscroll animation.
35 - (NSView*)movingView;
36
37 // The expected duration of an animation from progress_ to |progress|
38 - (CGFloat)animationDurationForProgress:(CGFloat)progress;
39
40 // NSView override. During an overscroll animation, the cursor may no longer
41 // rest on the RenderWidgetHost's NativeView, which prevents wheel events from
42 // reaching the NativeView. The overscroll animation is driven by wheel events
43 // so they must be explicitly forwarded to the NativeView.
44 - (void)scrollWheel:(NSEvent*)event;
45 @end
46
47 // Helper Class (ResizingView) -------------------------------------------------
48
49 // This NSView subclass is intended to be the RenderWidgetHost's NativeView's
50 // parent NSView. It is possible for the RenderWidgetHost's NativeView's size to
51 // become out of sync with its parent NSView. The override of
52 // -resizeSubviewsWithOldSize: ensures that the sizes will eventually become
53 // consistent.
54 // http://crbug.com/264207)
Avi (use Gerrit) 2014/06/06 23:09:45 unbalanced parenthesis.
erikchen 2014/06/07 00:34:04 removed.
55 @interface ResizingView : NSView
56 @end
57
58 @implementation ResizingView
59 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
60 for (NSView* subview in self.subviews)
61 [subview setFrame:self.bounds];
62 }
63 @end
64
65 // Helper Class (WebContentsPaintObserver) -------------------------------------
66
67 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
68 class WebContentsPaintObserver : public WebContentsObserver {
69 public:
70 WebContentsPaintObserver(WebContents* web_contents,
71 OverscrollAnimatorSliderView* slider_view)
72 : WebContentsObserver(web_contents), slider_view_(slider_view) {}
73
74 virtual void DidFirstVisuallyNonEmptyPaint() OVERRIDE {
75 [slider_view_ webContentsFinishedNonEmptyPaint];
76 }
77
78 private:
79 OverscrollAnimatorSliderView* slider_view_; // Weak reference.
80 };
81 }
82
83 // OverscrollAnimatorSliderView Implementation ---------------------------------
84
85 @implementation OverscrollAnimatorSliderView
86
87 - (instancetype)initWithFrame:(NSRect)frame {
88 self = [super initWithFrame:frame];
89 if (self) {
90 bottomView_.reset([[NSImageView alloc] initWithFrame:self.bounds]);
91 bottomView_.get().imageScaling = NSImageScaleNone;
92 bottomView_.get().autoresizingMask =
93 NSViewWidthSizable | NSViewHeightSizable;
94 bottomView_.get().imageAlignment = NSImageAlignTop;
95 [self addSubview:bottomView_];
96 middleView_.reset([[ResizingView alloc] initWithFrame:self.bounds]);
97 middleView_.get().autoresizingMask =
98 NSViewWidthSizable | NSViewHeightSizable;
99 [self addSubview:middleView_];
100 topView_.reset([[NSImageView alloc] initWithFrame:self.bounds]);
101 topView_.get().autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
102 topView_.get().imageScaling = NSImageScaleNone;
103 topView_.get().imageAlignment = NSImageAlignTop;
104 [self addSubview:topView_];
105
106 [self reset];
107 }
108 return self;
109 }
110
111 - (void)webContentsFinishedNonEmptyPaint {
112 observer_.reset();
113 [self reset];
114 }
115
116 - (void)reset {
117 DCHECK(!animating_);
118 inOverscroll_ = NO;
119 progress_ = kMinProgress;
120
121 [CATransaction begin];
122 [CATransaction setDisableActions:YES];
123 bottomView_.get().hidden = YES;
124 middleView_.get().hidden = NO;
125 topView_.get().hidden = YES;
126
127 [bottomView_ setFrameOrigin:NSMakePoint(0, 0)];
128 [middleView_ setFrameOrigin:NSMakePoint(0, 0)];
129 [topView_ setFrameOrigin:NSMakePoint(0, 0)];
130 [CATransaction commit];
131 }
132
133 - (NSPoint)frameOriginWithProgress:(CGFloat)progress {
134 if (slidingLeft_)
135 return NSMakePoint(progress / kMaxProgress * self.bounds.size.width, 0);
136 return NSMakePoint((1 - progress / kMaxProgress) * self.bounds.size.width, 0);
137 }
138
139 - (NSView*)movingView {
140 if (slidingLeft_)
141 return middleView_;
142 return topView_;
143 }
144
145 - (CGFloat)animationDurationForProgress:(CGFloat)progress {
146 CGFloat progressPercentage =
147 fabs(progress_ - progress) / (kMaxProgress - kMinProgress);
148 return progressPercentage * kMaxAnimationDuration;
149 }
150
151 - (void)scrollWheel:(NSEvent*)event {
152 NSView* latestRenderWidgetHostView = [[middleView_ subviews] lastObject];
153 [latestRenderWidgetHostView scrollWheel:event];
154 }
155
156 // WebContentsOverscrollAnimator Implementation --------------------------------
157
158 - (void)beginOverscrollLeft:(BOOL)left {
159 if (animating_ || inOverscroll_)
160 return;
161
162 inOverscroll_ = YES;
163 slidingLeft_ = left;
164 if (left) {
165 // The middleView_ will slide to the right, revealing bottomView_.
166 bottomView_.get().hidden = NO;
167 } else {
168 // The topView_ will slide in from the right, concealing middleView_.
169 topView_.get().hidden = NO;
170 [topView_ setFrameOrigin:NSMakePoint(self.bounds.size.width, 0)];
171 }
172
173 [self updateOverscrollProgress:kMinProgress];
174 }
175
176 - (BOOL)needsNavigationSnapshot {
177 return YES;
178 }
179
180 - (void)supplyNavigationSnapshot:(NSImage*)image {
181 if (slidingLeft_)
182 [bottomView_ setImage:image];
183 else
184 [topView_ setImage:image];
185 }
186
187 - (void)addRenderWidgetHostNativeView:(NSView*)view {
188 [middleView_ addSubview:view];
189 }
190
191 - (void)updateOverscrollProgress:(CGFloat)progress {
192 if (animating_)
193 return;
194 DCHECK_LT(progress, kMaxProgress + 0.00001);
195 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
196 progress_ = progress;
197 [[self movingView] setFrameOrigin:[self frameOriginWithProgress:progress]];
198 }
199
200 - (void)completeOverscroll:(content::WebContentsImpl*)webContents {
201 if (animating_ || !inOverscroll_)
202 return;
203
204 animating_ = YES;
205
206 NSView* view = [self movingView];
207 [NSAnimationContext beginGrouping];
208 [NSAnimationContext currentContext].duration =
209 [self animationDurationForProgress:kMaxProgress];
210 [[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.
211 animating_ = NO;
212
213 // Animation is complete. Now perform page load.
214 if (slidingLeft_)
215 webContents->GetController().GoBack();
216 else
217 webContents->GetController().GoForward();
218
219 // Reset the position of the middleView_, but wait for the page to paint
220 // before showing it.
221 middleView_.get().hidden = YES;
222 [middleView_ setFrameOrigin:NSMakePoint(0, 0)];
223 observer_.reset(new content::WebContentsPaintObserver(webContents, self));
224 }];
225
226 // Animate the moving view to its final position.
227 [[view animator] setFrameOrigin:[self frameOriginWithProgress:kMaxProgress]];
228
229 [NSAnimationContext endGrouping];
230 }
231
232 - (void)cancelOverscroll {
233 if (animating_)
234 return;
235
236 if (!inOverscroll_) {
237 [self reset];
238 return;
239 }
240
241 animating_ = YES;
242
243 NSView* view = [self movingView];
244 [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
245 [NSAnimationContext currentContext].duration =
246 [self animationDurationForProgress:kMinProgress];
247 [[NSAnimationContext currentContext] setCompletionHandler:^{
248 // Animation is complete. Reset the state.
249 animating_ = NO;
250 [self reset];
251 }];
252
253 // Animate the moving view to its initial position.
254 [[view animator] setFrameOrigin:[self frameOriginWithProgress:kMinProgress]];
255
256 [NSAnimationContext endGrouping];
257 }
258
259 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698