| Index: chrome/browser/cocoa/download_started_animation_mac.mm
|
| diff --git a/chrome/browser/cocoa/download_started_animation_mac.mm b/chrome/browser/cocoa/download_started_animation_mac.mm
|
| index 42c5c85bd42616e9f0d847cfa34db4ad0945b94f..f004469d3a6fb32da3c16b5881af20f5f826904e 100644
|
| --- a/chrome/browser/cocoa/download_started_animation_mac.mm
|
| +++ b/chrome/browser/cocoa/download_started_animation_mac.mm
|
| @@ -15,6 +15,7 @@
|
| #include "base/scoped_cftyperef.h"
|
| #include "chrome/browser/tab_contents/tab_contents.h"
|
| #include "chrome/browser/tab_contents/tab_contents_view_mac.h"
|
| +#import "chrome/browser/cocoa/animatable_image.h"
|
| #include "chrome/common/notification_registrar.h"
|
| #include "chrome/common/notification_service.h"
|
| #include "grit/theme_resources.h"
|
| @@ -25,11 +26,12 @@ class DownloadAnimationTabObserver;
|
|
|
| // A class for managing the Core Animation download animation.
|
| // Should be instantiated using +startAnimationWithTabContents:.
|
| -@interface DownloadStartedAnimationMac : NSWindow {
|
| +@interface DownloadStartedAnimationMac : NSObject {
|
| @private
|
| // The observer for the TabContents we are drawing on.
|
| scoped_ptr<DownloadAnimationTabObserver> observer_;
|
| CGFloat imageWidth_;
|
| + AnimatableImage* animation_;
|
| };
|
|
|
| + (void)startAnimationWithTabContents:(TabContents*)tabContents;
|
| @@ -41,7 +43,7 @@ class DownloadAnimationTabObserver;
|
| // A helper class to monitor tab hidden and closed notifications. If we receive
|
| // such a notification, we stop the animation.
|
| class DownloadAnimationTabObserver : public NotificationObserver {
|
| -public:
|
| + public:
|
| DownloadAnimationTabObserver(DownloadStartedAnimationMac* owner,
|
| TabContents* tab_contents)
|
| : owner_(owner),
|
| @@ -59,16 +61,11 @@ public:
|
| void Observe(NotificationType type,
|
| const NotificationSource& source,
|
| const NotificationDetails& details) {
|
| - registrar_.Remove(this,
|
| - NotificationType::TAB_CONTENTS_HIDDEN,
|
| - Source<TabContents>(tab_contents_));
|
| - registrar_.Remove(this,
|
| - NotificationType::TAB_CONTENTS_DESTROYED,
|
| - Source<TabContents>(tab_contents_));
|
| + // This ends up deleting us.
|
| [owner_ animationComplete];
|
| }
|
|
|
| -private:
|
| + private:
|
| // The object we need to inform when we get a notification. Weak.
|
| DownloadStartedAnimationMac* owner_;
|
|
|
| @@ -84,51 +81,56 @@ private:
|
| @implementation DownloadStartedAnimationMac
|
|
|
| - (id)initWithTabContents:(TabContents*)tabContents {
|
| - // Load the image of the download arrow.
|
| - ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
|
| - SkBitmap* imageBitmap = bundle.GetBitmapNamed(IDR_DOWNLOAD_ANIMATION_BEGIN);
|
| - scoped_cftyperef<CGImageRef> image(SkCreateCGImageRef(*imageBitmap));
|
| -
|
| - // Figure out the positioning in the current tab. Try to position the layer
|
| - // against the left edge, and three times the download image's height from the
|
| - // bottom of the tab, assuming there is enough room. If there isn't enough,
|
| - // don't show the animation and let the shelf speak for itself.
|
| - gfx::Rect bounds;
|
| - tabContents->GetContainerBounds(&bounds);
|
| - imageWidth_ = CGImageGetWidth(image);
|
| - CGFloat imageHeight = CGImageGetHeight(image);
|
| -
|
| - // Sanity check the size in case there's no room to display the animation.
|
| - if (bounds.height() < imageHeight) {
|
| - [self release];
|
| - return nil;
|
| - }
|
| -
|
| - NSView* tabContentsView = tabContents->GetNativeView();
|
| - NSWindow* parentWindow = [tabContentsView window];
|
| - if (!parentWindow) {
|
| - // The tab is no longer frontmost.
|
| - [self release];
|
| - return nil;
|
| - }
|
| -
|
| - NSPoint origin = [tabContentsView frame].origin;
|
| - origin = [tabContentsView convertPoint:origin toView:nil];
|
| - origin = [parentWindow convertBaseToScreen:origin];
|
| -
|
| - // Create a window to host a layer that animates the sliding and fading.
|
| - CGFloat animationHeight = MIN(bounds.height(), 4 * imageHeight);
|
| - NSRect frame = NSMakeRect(origin.x, origin.y, imageWidth_, animationHeight);
|
| - if ((self = [super initWithContentRect:frame
|
| - styleMask:NSBorderlessWindowMask
|
| - backing:NSBackingStoreBuffered
|
| - defer:NO])) {
|
| - [self setOpaque:NO];
|
| - [self setBackgroundColor:[NSColor clearColor]];
|
| - [self setIgnoresMouseEvents:YES];
|
| + if ((self = [super init])) {
|
| + // Load the image of the download arrow.
|
| + ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
|
| + SkBitmap* imageBitmap = bundle.GetBitmapNamed(IDR_DOWNLOAD_ANIMATION_BEGIN);
|
| + scoped_cftyperef<CGImageRef> image(SkCreateCGImageRef(*imageBitmap));
|
| +
|
| + // Figure out the positioning in the current tab. Try to position the layer
|
| + // against the left edge, and three times the download image's height from
|
| + // the bottom of the tab, assuming there is enough room. If there isn't
|
| + // enough, don't show the animation and let the shelf speak for itself.
|
| + gfx::Rect bounds;
|
| + tabContents->GetContainerBounds(&bounds);
|
| + imageWidth_ = CGImageGetWidth(image);
|
| + CGFloat imageHeight = CGImageGetHeight(image);
|
| +
|
| + // Sanity check the size in case there's no room to display the animation.
|
| + if (bounds.height() < imageHeight) {
|
| + [self release];
|
| + return nil;
|
| + }
|
| +
|
| + NSView* tabContentsView = tabContents->GetNativeView();
|
| + NSWindow* parentWindow = [tabContentsView window];
|
| + if (!parentWindow) {
|
| + // The tab is no longer frontmost.
|
| + [self release];
|
| + return nil;
|
| + }
|
| +
|
| + NSPoint origin = [tabContentsView frame].origin;
|
| + origin = [tabContentsView convertPoint:origin toView:nil];
|
| + origin = [parentWindow convertBaseToScreen:origin];
|
| +
|
| + // Create the animation object to assist in animating and fading.
|
| + CGFloat animationHeight = MIN(bounds.height(), 4 * imageHeight);
|
| + NSRect frame = NSMakeRect(origin.x, origin.y, imageWidth_, animationHeight);
|
| + animation_ = [[AnimatableImage alloc] initWithImage:(id)image.get()
|
| + animationFrame:frame];
|
| + [parentWindow addChildWindow:animation_ ordered:NSWindowAbove];
|
| +
|
| + animationHeight = MIN(bounds.height(), 3 * imageHeight);
|
| + [animation_ setStartFrame:CGRectMake(0, animationHeight,
|
| + imageWidth_, imageHeight)];
|
| + [animation_ setEndFrame:CGRectMake(0, imageHeight,
|
| + imageWidth_, imageHeight)];
|
| + [animation_ setStartOpacity:1.0];
|
| + [animation_ setEndOpacity:0.4];
|
| + [animation_ setDuration:0.6];
|
|
|
| - // Must be set or else self will be leaked.
|
| - [self setReleasedWhenClosed:YES];
|
| + observer_.reset(new DownloadAnimationTabObserver(self, tabContents));
|
|
|
| // Set up to get notified about resize events on the parent window.
|
| NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
|
| @@ -136,62 +138,12 @@ private:
|
| selector:@selector(parentWindowChanged:)
|
| name:NSWindowDidResizeNotification
|
| object:parentWindow];
|
| - [parentWindow addChildWindow:self ordered:NSWindowAbove];
|
| -
|
| - // Set up the root layer. By calling -setLayer: followed by -setWantsLayer:
|
| - // the view becomes a layer hosting view as opposed to a layer backed view.
|
| - NSView* view = [self contentView];
|
| - CALayer* rootLayer = [CALayer layer];
|
| - [view setLayer:rootLayer];
|
| - [view setWantsLayer:YES];
|
| -
|
| - // Create the layer that will be animated.
|
| - CALayer* layer = [CALayer layer];
|
| - [layer setContents:(id)image.get()];
|
| - [layer setAnchorPoint:CGPointMake(0, 1)];
|
| - [layer setFrame:CGRectMake(0, 0, imageWidth_, imageHeight)];
|
| - [layer setNeedsDisplayOnBoundsChange:YES];
|
| - [rootLayer addSublayer:layer];
|
| -
|
| - // Common timing function for all animations.
|
| - CAMediaTimingFunction* mediaFunction =
|
| - [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
|
| -
|
| - // Positional animation.
|
| - CABasicAnimation* positionAnimation =
|
| - [CABasicAnimation animationWithKeyPath:@"position"];
|
| - CGFloat animationHeight = MIN(bounds.height(), 3 * imageHeight);
|
| - NSPoint start = NSMakePoint(0, animationHeight);
|
| - NSPoint stop = NSMakePoint(0, imageHeight);
|
| - [positionAnimation setFromValue:[NSValue valueWithPoint:start]];
|
| - [positionAnimation setToValue:[NSValue valueWithPoint:stop]];
|
| - [positionAnimation gtm_setDuration:0.6
|
| - eventMask:NSLeftMouseUpMask];
|
| - [positionAnimation setTimingFunction:mediaFunction];
|
| -
|
| - // Opacity animation.
|
| - CABasicAnimation* opacityAnimation =
|
| - [CABasicAnimation animationWithKeyPath:@"opacity"];
|
| - [opacityAnimation setFromValue:[NSNumber numberWithFloat:1.0]];
|
| - [opacityAnimation setToValue:[NSNumber numberWithFloat:0.4]];
|
| - [opacityAnimation gtm_setDuration:0.6
|
| - eventMask:NSLeftMouseUpMask];
|
| - [opacityAnimation setTimingFunction:mediaFunction];
|
| -
|
| - // Group the animations together.
|
| - CAAnimationGroup* animationGroup = [CAAnimationGroup animation];
|
| - NSArray* animations =
|
| - [NSArray arrayWithObjects:positionAnimation, opacityAnimation, nil];
|
| - [animationGroup setAnimations:animations];
|
| -
|
| - // Set self as delegate so self receives -animationDidStop:finished:;
|
| - [animationGroup setDelegate:self];
|
| - [animationGroup setTimingFunction:mediaFunction];
|
| - [animationGroup gtm_setDuration:0.6
|
| - eventMask:NSLeftMouseUpMask];
|
| - [layer addAnimation:animationGroup forKey:@"downloadOpacityAndPosition"];
|
| -
|
| - observer_.reset(new DownloadAnimationTabObserver(self, tabContents));
|
| + // When the animation window closes, it needs to be removed from the
|
| + // parent window.
|
| + [center addObserver:self
|
| + selector:@selector(windowWillClose:)
|
| + name:NSWindowWillCloseNotification
|
| + object:animation_];
|
| }
|
| return self;
|
| }
|
| @@ -203,28 +155,30 @@ private:
|
|
|
| // Called when the parent window is resized.
|
| - (void)parentWindowChanged:(NSNotification*)notification {
|
| - NSWindow* parentWindow = [self parentWindow];
|
| + NSWindow* parentWindow = [animation_ parentWindow];
|
| DCHECK([[notification object] isEqual:parentWindow]);
|
| NSRect parentFrame = [parentWindow frame];
|
| NSRect frame = parentFrame;
|
| frame.size.width = MIN(imageWidth_, NSWidth(parentFrame));
|
| - [self setFrame:frame display:YES];
|
| + [animation_ setFrame:frame display:YES];
|
| }
|
|
|
| -// CAAnimation delegate method called when the animation is complete.
|
| -- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
|
| +- (void)windowWillClose:(NSNotification*)notification {
|
| + DCHECK([[notification object] isEqual:animation_]);
|
| [self animationComplete];
|
| }
|
|
|
| -// Common clean up code.
|
| - (void)animationComplete {
|
| - [[self parentWindow] removeChildWindow:self];
|
| - [self close];
|
| + [[animation_ parentWindow] removeChildWindow:animation_];
|
| + [self release];
|
| }
|
|
|
| + (void)startAnimationWithTabContents:(TabContents*)contents {
|
| // Will be deleted when the animation is complete in -animationComplete.
|
| - [[self alloc] initWithTabContents:contents];
|
| + DownloadStartedAnimationMac* controller =
|
| + [[self alloc] initWithTabContents:contents];
|
| + // The |animation_| releaes itself when done.
|
| + [controller->animation_ startAnimation];
|
| }
|
|
|
| @end
|
|
|