1 // Copyright (c) 2012 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.
5 // This file contains the Mac implementation the download animation, displayed
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
8 // download appears in the download shelf.
10 #include "chrome/browser/download/download_started_animation.h"
12 #import <QuartzCore/QuartzCore.h>
14 #include "base/logging.h"
15 #import "chrome/browser/ui/cocoa/animatable_image.h"
16 #include "content/public/browser/web_contents.h"
17 #include "grit/theme_resources.h"
18 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h"
19 #include "third_party/skia/include/utils/mac/SkCGUtils.h"
20 #include "ui/base/resource/resource_bundle.h"
21 #include "ui/gfx/geometry/rect.h"
22 #include "ui/gfx/image/image.h"
24 class DownloadAnimationWebObserver;
26 // A class for managing the Core Animation download animation.
27 // Should be instantiated using +startAnimationWithWebContents:.
28 @interface DownloadStartedAnimationMac : NSObject {
31 AnimatableImage* animation_;
34 + (void)startAnimationWithWebContents:(content::WebContents*)webContents;
38 @implementation DownloadStartedAnimationMac
40 - (id)initWithWebContents:(content::WebContents*)webContents {
41 if ((self = [super init])) {
42 // Load the image of the download arrow.
43 ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
45 bundle.GetNativeImageNamed(IDR_DOWNLOAD_ANIMATION_BEGIN).ToNSImage();
47 // Figure out the positioning in the current tab. Try to position the layer
48 // against the left edge, and three times the download image's height from
49 // the bottom of the tab, assuming there is enough room. If there isn't
50 // enough, don't show the animation and let the shelf speak for itself.
51 gfx::Rect bounds = webContents->GetContainerBounds();
52 imageWidth_ = [image size].width;
53 CGFloat imageHeight = [image size].height;
55 // Sanity check the size in case there's no room to display the animation.
56 if (bounds.height() < imageHeight) {
61 NSView* tabContentsView = webContents->GetNativeView();
62 NSWindow* parentWindow = [tabContentsView window];
64 // The tab is no longer frontmost.
69 NSPoint origin = [tabContentsView frame].origin;
70 origin = [tabContentsView convertPoint:origin toView:nil];
71 origin = [parentWindow convertBaseToScreen:origin];
73 // Create the animation object to assist in animating and fading.
74 CGFloat animationHeight = MIN(bounds.height(), 4 * imageHeight);
75 NSRect frame = NSMakeRect(origin.x, origin.y, imageWidth_, animationHeight);
76 animation_ = [[AnimatableImage alloc] initWithImage:image
77 animationFrame:frame];
78 [parentWindow addChildWindow:animation_ ordered:NSWindowAbove];
80 animationHeight = MIN(bounds.height(), 3 * imageHeight);
81 [animation_ setStartFrame:CGRectMake(0, animationHeight,
82 imageWidth_, imageHeight)];
83 [animation_ setEndFrame:CGRectMake(0, imageHeight,
84 imageWidth_, imageHeight)];
85 [animation_ setStartOpacity:1.0];
86 [animation_ setEndOpacity:0.4];
87 [animation_ setDuration:0.6];
89 // Set up to get notified about resize events on the parent window.
90 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
91 [center addObserver:self
92 selector:@selector(parentWindowDidResize:)
93 name:NSWindowDidResizeNotification
95 // When the animation window closes, it needs to be removed from the
97 [center addObserver:self
98 selector:@selector(windowWillClose:)
99 name:NSWindowWillCloseNotification
101 // If the parent window closes, shut everything down too.
102 [center addObserver:self
103 selector:@selector(windowWillClose:)
104 name:NSWindowWillCloseNotification
105 object:parentWindow];
111 [[NSNotificationCenter defaultCenter] removeObserver:self];
115 // Called when the parent window is resized.
116 - (void)parentWindowDidResize:(NSNotification*)notification {
117 NSWindow* parentWindow = [animation_ parentWindow];
118 DCHECK([[notification object] isEqual:parentWindow]);
119 NSRect parentFrame = [parentWindow frame];
120 NSRect frame = parentFrame;
121 frame.size.width = MIN(imageWidth_, NSWidth(parentFrame));
122 [animation_ setFrame:frame display:YES];
125 // When the animation closes, release self.
126 - (void)windowWillClose:(NSNotification*)notification {
127 [[animation_ parentWindow] removeChildWindow:animation_];
131 + (void)startAnimationWithWebContents:(content::WebContents*)contents {
132 // Will be deleted when the animation window closes.
133 DownloadStartedAnimationMac* controller =
134 [[self alloc] initWithWebContents:contents];
135 // The initializer can return nil.
139 // The |controller| releases itself when done.
140 [controller->animation_ startAnimation];
145 void DownloadStartedAnimation::Show(content::WebContents* web_contents) {
146 DCHECK(web_contents);
148 // Will be deleted when the animation is complete.
149 [DownloadStartedAnimationMac startAnimationWithWebContents:web_contents];