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

Side by Side Diff: chrome/browser/cocoa/download_started_animation_mac.mm

Issue 385053: Moves the animation for the download_started into an overlay window to get... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // This file contains the Mac implementation the download animation, displayed 5 // This file contains the Mac implementation the download animation, displayed
6 // at the start of a download. The animation produces an arrow pointing 6 // at the start of a download. The animation produces an arrow pointing
7 // downwards and animates towards the bottom of the window where the new 7 // downwards and animates towards the bottom of the window where the new
8 // download appears in the download shelf. 8 // download appears in the download shelf.
9 9
10 #include "chrome/browser/download/download_started_animation.h" 10 #include "chrome/browser/download/download_started_animation.h"
11 11
12 #import <QuartzCore/QuartzCore.h> 12 #import <QuartzCore/QuartzCore.h>
13 13
14 #include "app/resource_bundle.h" 14 #include "app/resource_bundle.h"
15 #include "base/scoped_cftyperef.h" 15 #include "base/scoped_cftyperef.h"
16 #include "base/scoped_nsobject.h"
17 #include "chrome/browser/tab_contents/tab_contents.h" 16 #include "chrome/browser/tab_contents/tab_contents.h"
18 #include "chrome/browser/tab_contents/tab_contents_view_mac.h" 17 #include "chrome/browser/tab_contents/tab_contents_view_mac.h"
19 #include "chrome/common/notification_registrar.h" 18 #include "chrome/common/notification_registrar.h"
20 #include "chrome/common/notification_service.h" 19 #include "chrome/common/notification_service.h"
21 #include "grit/theme_resources.h" 20 #include "grit/theme_resources.h"
22 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h" 21 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
23 #include "third_party/skia/include/utils/mac/SkCGUtils.h" 22 #include "third_party/skia/include/utils/mac/SkCGUtils.h"
24 23
25 class DownloadAnimationTabObserver; 24 class DownloadAnimationTabObserver;
26 25
27 // A class for managing the Core Animation download animation. 26 // A class for managing the Core Animation download animation.
28 @interface DownloadStartedAnimationMac : NSObject { 27 // Should be instantiated using +startAnimationWithTabContents:.
29 // The download arrow image which we are responsible for freeing. 28 @interface DownloadStartedAnimationMac : NSWindow {
30 scoped_cftyperef<CGImageRef> image_; 29 @private
31
32 // The TabContents we will animate in (weak).
33 TabContents* tabContents_;
34
35 // The cocoa view object for our TabContents (weak).
36 NSView* view_;
37
38 // The observer for the TabContents we are drawing on. 30 // The observer for the TabContents we are drawing on.
39 scoped_ptr<DownloadAnimationTabObserver> observer_; 31 scoped_ptr<DownloadAnimationTabObserver> observer_;
40 32 CGFloat imageWidth_;
41 // Our animation layer.
42 scoped_nsobject<CALayer> layer_;
43
44 // Set once the animation is complete, either by interrupting (via window
45 // close) or through normal a end of the animation.
46 BOOL isComplete_;
47 }; 33 };
48 34
35 + (void)startAnimationWithTabContents:(TabContents*)tabContents;
49 // Called by our DownloadAnimationTabObserver if the tab is hidden or closed. 36 // Called by our DownloadAnimationTabObserver if the tab is hidden or closed.
50 - (void)animationComplete; 37 - (void)animationComplete;
51 38
52 @end // interface DownloadStartedAnimationMac. 39 @end
53
54 40
55 // A helper class to monitor tab hidden and closed notifications. If we receive 41 // A helper class to monitor tab hidden and closed notifications. If we receive
56 // such a notification, we stop the animation. 42 // such a notification, we stop the animation.
57 class DownloadAnimationTabObserver : public NotificationObserver { 43 class DownloadAnimationTabObserver : public NotificationObserver {
58 public: 44 public:
59 DownloadAnimationTabObserver(DownloadStartedAnimationMac* owner, 45 DownloadAnimationTabObserver(DownloadStartedAnimationMac* owner,
60 TabContents* tab_contents) 46 TabContents* tab_contents)
61 : owner_(owner), 47 : owner_(owner),
62 tab_contents_(tab_contents) { 48 tab_contents_(tab_contents) {
63 registrar_.Add(this, 49 registrar_.Add(this,
(...skipping 24 matching lines...) Expand all
88 74
89 // The tab we are observing. Weak. 75 // The tab we are observing. Weak.
90 TabContents* tab_contents_; 76 TabContents* tab_contents_;
91 77
92 // Used for registering to receive notifications and automatic clean up. 78 // Used for registering to receive notifications and automatic clean up.
93 NotificationRegistrar registrar_; 79 NotificationRegistrar registrar_;
94 80
95 DISALLOW_COPY_AND_ASSIGN(DownloadAnimationTabObserver); 81 DISALLOW_COPY_AND_ASSIGN(DownloadAnimationTabObserver);
96 }; 82 };
97 83
98
99 @implementation DownloadStartedAnimationMac 84 @implementation DownloadStartedAnimationMac
100 85
101 // Load the image of the download arrow.
102 - (id)initWithTabContents:(TabContents*)tabContents { 86 - (id)initWithTabContents:(TabContents*)tabContents {
103 if ((self = [super init])) { 87 // Load the image of the download arrow.
104 SkBitmap* image_bitmap = 88 ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
105 ResourceBundle::GetSharedInstance().GetBitmapNamed( 89 SkBitmap* imageBitmap = bundle.GetBitmapNamed(IDR_DOWNLOAD_ANIMATION_BEGIN);
106 IDR_DOWNLOAD_ANIMATION_BEGIN); 90 scoped_cftyperef<CGImageRef> image(SkCreateCGImageRef(*imageBitmap));
107 image_.reset(SkCreateCGImageRef(*image_bitmap)); 91
108 tabContents_ = tabContents; 92 // Figure out the positioning in the current tab. Try to position the layer
109 view_ = tabContents_->GetContentNativeView(); 93 // against the left edge, and three times the download image's height from the
94 // bottom of the tab, assuming there is enough room. If there isn't enough,
95 // don't show the animation and let the shelf speak for itself.
96 gfx::Rect bounds;
97 tabContents->GetContainerBounds(&bounds);
98 imageWidth_ = CGImageGetWidth(image);
99 CGFloat imageHeight = CGImageGetHeight(image);
100 CGRect imageBounds = CGRectMake(0, 0, imageWidth_, imageHeight);
101
102 // Sanity check the size in case there's no room to display the animation.
103 if (bounds.height() < imageHeight) {
104 [self release];
105 return nil;
106 }
107
108 NSView* tabContentsView = tabContents->GetNativeView();
109 NSWindow* parentWindow = [tabContentsView window];
110 if (!parentWindow) {
111 // The tab is no longer frontmost.
112 [self release];
113 return nil;
114 }
115
116 NSPoint origin = [tabContentsView frame].origin;
117 origin = [tabContentsView convertPointToBase:origin];
118 origin = [parentWindow convertBaseToScreen:origin];
119
120 // Create a window to host a layer that animates the sliding and fading.
121 CGFloat animationHeight = MIN(bounds.height(), 4 * imageHeight);
122 NSRect frame = NSMakeRect(origin.x, origin.y, imageWidth_, animationHeight);
123 if ((self = [super initWithContentRect:frame
124 styleMask:NSBorderlessWindowMask
125 backing:NSBackingStoreBuffered
126 defer:NO])) {
127 [self setOpaque:NO];
128 [self setBackgroundColor:[NSColor clearColor]];
129 [self setIgnoresMouseEvents:YES];
130
131 // Must be set or else self will be leaked.
132 [self setReleasedWhenClosed:YES];
133
134 // Set up to get notified about resize events on the parent window.
135 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
136 [center addObserver:self
137 selector:@selector(parentWindowChanged:)
138 name:NSWindowDidResizeNotification
139 object:parentWindow];
140 [parentWindow addChildWindow:self ordered:NSWindowAbove];
141
142 // Set up the root layer. By calling -setLayer: followed by -setWantsLayer:
143 // the view becomes a layer hosting view as opposed to a layer backed view.
144 NSView* view = [self contentView];
145 CALayer* rootLayer = [CALayer layer];
146 [view setLayer:rootLayer];
147 [view setWantsLayer:YES];
148
149 // Create the layer that will be animated.
150 CALayer* layer = [CALayer layer];
151 [layer setContents:(id)image.get()];
152 [layer setAnchorPoint:CGPointMake(0, 1)];
153 [layer setFrame:CGRectMake(0, 0, imageWidth_, imageHeight)];
154 [layer setNeedsDisplayOnBoundsChange:YES];
155 [rootLayer addSublayer:layer];
156
157 // Common timing function for all animations.
158 CAMediaTimingFunction* mediaFunction =
159 [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
160
161 // Positional animation.
162 CABasicAnimation* positionAnimation =
163 [CABasicAnimation animationWithKeyPath:@"position"];
164 CGFloat animationHeight = MIN(bounds.height(), 3 * imageHeight);
165 NSPoint start = NSMakePoint(0, animationHeight);
166 NSPoint stop = NSMakePoint(0, imageHeight);
167 [positionAnimation setFromValue:[NSValue valueWithPoint:start]];
168 [positionAnimation setToValue:[NSValue valueWithPoint:stop]];
169 [positionAnimation gtm_setDuration:0.6];
170 [positionAnimation setTimingFunction:mediaFunction];
171
172 // Opacity animation.
173 CABasicAnimation* opacityAnimation =
174 [CABasicAnimation animationWithKeyPath:@"opacity"];
175 [opacityAnimation setFromValue:[NSNumber numberWithFloat:1.0]];
176 [opacityAnimation setToValue:[NSNumber numberWithFloat:0.4]];
177 [opacityAnimation gtm_setDuration:0.6];
178 [opacityAnimation setTimingFunction:mediaFunction];
179
180 // Group the animations together.
181 CAAnimationGroup* animationGroup = [CAAnimationGroup animation];
182 NSArray* animations =
183 [NSArray arrayWithObjects:positionAnimation, opacityAnimation, nil];
184 [animationGroup setAnimations:animations];
185
186 // Set self as delegate so self receives -animationDidStop:finished:;
187 [animationGroup setDelegate:self];
188 [animationGroup setTimingFunction:mediaFunction];
189 [animationGroup gtm_setDuration:0.6];
190 [layer addAnimation:animationGroup forKey:@"downloadOpacityAndPosition"];
191
110 observer_.reset(new DownloadAnimationTabObserver(self, tabContents)); 192 observer_.reset(new DownloadAnimationTabObserver(self, tabContents));
111 isComplete_ = NO;
112 } 193 }
113 return self; 194 return self;
114 } 195 }
115 196
116 // Common clean up code. 197 - (void)dealloc {
117 - (void)animationComplete { 198 [[NSNotificationCenter defaultCenter] removeObserver:self];
118 if (isComplete_) 199 [super dealloc];
119 return;
120 isComplete_ = YES;
121 [view_ setWantsLayer:NO];
122 [layer_ removeAllAnimations];
123 [layer_ removeFromSuperlayer];
124 } 200 }
125 201
126 // Set up the animation and let Core Animation do all the hard work. 202 // Called when the parent window is resized.
127 - (void)animate { 203 - (void)parentWindowChanged:(NSNotification*)notification {
128 // Figure out the positioning in the current tab. We try to position ourselves 204 NSWindow* parentWindow = [self parentWindow];
129 // against the left edge, and three times the download image's height from the 205 DCHECK([[notification object] isEqual:parentWindow]);
130 // bottom of the tab, assuming there is enough room. If there isn't enough, we 206 NSRect parentFrame = [parentWindow frame];
131 // won't show the animation and let the shelf speak for itself. 207 NSRect frame = parentFrame;
132 gfx::Rect bounds; 208 frame.size.width = MIN(imageWidth_, NSWidth(parentFrame));
133 tabContents_->GetContainerBounds(&bounds); 209 [self setFrame:frame display:YES];
134 int imageWidth = CGImageGetWidth(image_);
135 int imageHeight = CGImageGetHeight(image_);
136 CGRect imageBounds = CGRectMake(0, 0, imageWidth, imageHeight);
137
138 // Sanity check the size in case there's no room to display the animation.
139 if (bounds.height() < imageHeight) {
140 [self release];
141 return;
142 }
143
144 int animationHeight = std::min(bounds.height(), 3 * imageHeight);
145 NSPoint start = NSMakePoint(0, animationHeight);
146 NSPoint stop = NSMakePoint(0, 0); // Bottom of the tab.
147
148 // Set for the duration of the animation, or we won't see our layer. We reset
149 // this in the completion callback. Layers by default scale their content to
150 // fit, but we need them to clip their content instead, or else renderer
151 // resizes will look janky.
152 [view_ setWantsLayer:YES];
153 [[view_ layer] setContentsGravity:kCAGravityTopLeft];
154
155 // CALayer initalization.
156 layer_.reset([[CALayer layer] retain]);
157 [layer_ setNeedsDisplay];
158 [layer_ setContents:(id)image_.get()];
159 [layer_ setAnchorPoint:CGPointMake(0, 0)];
160 [layer_ setFrame:imageBounds];
161 [[view_ layer] addSublayer:layer_];
162
163 // Positional animation.
164 CABasicAnimation *animation =
165 [CABasicAnimation animationWithKeyPath:@"position"];
166 [animation setFromValue:[NSValue valueWithPoint:start]];
167 [animation setToValue:[NSValue valueWithPoint:stop]];
168 [animation gtm_setDuration:0.6];
169 CAMediaTimingFunction* mediaFunction =
170 [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
171 [animation setTimingFunction:mediaFunction];
172 [animation setDelegate:self];
173 [layer_ addAnimation:animation forKey:@"downloadPosition"];
174
175 // Opacity animation.
176 animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
177 [animation setFromValue:[NSNumber numberWithFloat:1.0]];
178 [animation setToValue:[NSNumber numberWithFloat:0.0]];
179 [animation gtm_setDuration:1.5]; // Longer, so it doesn't fade too much.
180 mediaFunction =
181 [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
182 [animation setTimingFunction:mediaFunction];
183 [layer_ addAnimation:animation forKey:@"downloadOpacity"];
184 } 210 }
185 211
186 // CAAnimation delegate method called when the animation is complete. 212 // CAAnimation delegate method called when the animation is complete.
187 - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag { 213 - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
188 [self animationComplete]; 214 [self animationComplete];
189 [self release];
190 } 215 }
191 216
192 @end // implementation DownloadStartedAnimationMac 217 // Common clean up code.
218 - (void)animationComplete {
219 [[self parentWindow] removeChildWindow:self];
220 [self close];
221 }
193 222
223 + (void)startAnimationWithTabContents:(TabContents*)contents {
224 // Will be deleted when the animation is complete in -animationComplete.
225 [[self alloc] initWithTabContents:contents];
226 }
194 227
195 // static 228 @end
229
196 void DownloadStartedAnimation::Show(TabContents* tab_contents) { 230 void DownloadStartedAnimation::Show(TabContents* tab_contents) {
197 DCHECK(tab_contents); 231 DCHECK(tab_contents);
198 232
199 // Will be deleted when the animation is complete. 233 // Will be deleted when the animation is complete.
200 DownloadStartedAnimationMac* downloadArrow = 234 [DownloadStartedAnimationMac startAnimationWithTabContents:tab_contents];
201 [[DownloadStartedAnimationMac alloc] initWithTabContents:tab_contents];
202
203 // Go!
204 [downloadArrow animate];
205 } 235 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698