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

Unified Diff: chrome/browser/cocoa/animatable_image.mm

Issue 3014005: [Mac] Display a quick animation when a popup is blocked so the user notices it in the Omnibox. (Closed) Base URL: http://src.chromium.org/git/chromium.git
Patch Set: CGImage Created 10 years, 5 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
« no previous file with comments | « chrome/browser/cocoa/animatable_image.h ('k') | chrome/browser/cocoa/animatable_image_unittest.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/cocoa/animatable_image.mm
diff --git a/chrome/browser/cocoa/animatable_image.mm b/chrome/browser/cocoa/animatable_image.mm
new file mode 100644
index 0000000000000000000000000000000000000000..2a3a72fa00903146b38ee3ecef2d538bc9667383
--- /dev/null
+++ b/chrome/browser/cocoa/animatable_image.mm
@@ -0,0 +1,164 @@
+// Copyright (c) 2010 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.
+
+#import "chrome/browser/cocoa/animatable_image.h"
+
+#include "base/logging.h"
+#include "base/scoped_cftyperef.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
+
+@interface AnimatableImage (Private)
+- (void)setLayerContents:(CALayer*)layer;
+@end
+
+@implementation AnimatableImage
+
+@synthesize startFrame = startFrame_;
+@synthesize endFrame = endFrame_;
+@synthesize startOpacity = startOpacity_;
+@synthesize endOpacity = endOpacity_;
+@synthesize duration = duration_;
+
+- (id)initWithImage:(NSImage*)image
+ animationFrame:(NSRect)animationFrame {
+ if ((self = [super initWithContentRect:animationFrame
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO])) {
+ DCHECK(image);
+ image_.reset([image retain]);
+ duration_ = 1.0;
+ startOpacity_ = 1.0;
+ endOpacity_ = 1.0;
+
+ [self setOpaque:NO];
+ [self setBackgroundColor:[NSColor clearColor]];
+ [self setIgnoresMouseEvents:YES];
+
+ // Must be set or else self will be leaked.
+ [self setReleasedWhenClosed:YES];
+ }
+ return self;
+}
+
+- (void)startAnimation {
+ // 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];
+ [self setLayerContents:layer];
+ [layer setAnchorPoint:CGPointMake(0, 1)];
+ [layer setFrame:[self startFrame]];
+ [layer setNeedsDisplayOnBoundsChange:YES];
+ [rootLayer addSublayer:layer];
+
+ // Common timing function for all animations.
+ CAMediaTimingFunction* mediaFunction =
+ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
+
+ // Animate the bounds only if the image is resized.
+ CABasicAnimation* boundsAnimation = nil;
+ if (CGRectGetWidth([self startFrame]) != CGRectGetWidth([self endFrame]) ||
+ CGRectGetHeight([self startFrame]) != CGRectGetHeight([self endFrame])) {
+ boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
+ NSRect startRect = NSMakeRect(0, 0,
+ CGRectGetWidth([self startFrame]),
+ CGRectGetHeight([self startFrame]));
+ [boundsAnimation setFromValue:[NSValue valueWithRect:startRect]];
+ NSRect endRect = NSMakeRect(0, 0,
+ CGRectGetWidth([self endFrame]),
+ CGRectGetHeight([self endFrame]));
+ [boundsAnimation setToValue:[NSValue valueWithRect:endRect]];
+ [boundsAnimation gtm_setDuration:[self duration]
+ eventMask:NSLeftMouseUpMask];
+ [boundsAnimation setTimingFunction:mediaFunction];
+ }
+
+ // Positional animation.
+ CABasicAnimation* positionAnimation =
+ [CABasicAnimation animationWithKeyPath:@"position"];
+ [positionAnimation setFromValue:
+ [NSValue valueWithPoint:NSPointFromCGPoint([self startFrame].origin)]];
+ [positionAnimation setToValue:
+ [NSValue valueWithPoint:NSPointFromCGPoint([self endFrame].origin)]];
+ [positionAnimation gtm_setDuration:[self duration]
+ eventMask:NSLeftMouseUpMask];
+ [positionAnimation setTimingFunction:mediaFunction];
+
+ // Opacity animation.
+ CABasicAnimation* opacityAnimation =
+ [CABasicAnimation animationWithKeyPath:@"opacity"];
+ [opacityAnimation setFromValue:
+ [NSNumber numberWithFloat:[self startOpacity]]];
+ [opacityAnimation setToValue:[NSNumber numberWithFloat:[self endOpacity]]];
+ [opacityAnimation gtm_setDuration:[self duration]
+ eventMask:NSLeftMouseUpMask];
+ [opacityAnimation setTimingFunction:mediaFunction];
+ // Set the delegate just for one of the animations so that this window can
+ // be closed upon completion.
+ [opacityAnimation setDelegate:self];
+
+ // The CAAnimations only affect the presentational value of a layer, not the
+ // model value. This means that after the animation is done, it can flicker
+ // back to the original values. To avoid this, create an implicit animation of
+ // the values, which are then overridden with the CABasicAnimations.
+ [layer setPosition:[self endFrame].origin];
+ [layer setOpacity:[self endOpacity]];
+
+ // Start the animations.
+ [CATransaction begin];
+ [CATransaction setValue:[NSNumber numberWithFloat:[self duration]]
+ forKey:kCATransactionAnimationDuration];
+ if (boundsAnimation) {
+ [layer addAnimation:boundsAnimation forKey:@"bounds"];
+ }
+ [layer addAnimation:positionAnimation forKey:@"position"];
+ [layer addAnimation:opacityAnimation forKey:@"opacity"];
+ [CATransaction commit];
+}
+
+// CALayer expects a CGImageRef contents. If the image is a PDF, 10.5 CGImage
+// cannot handle the conversion to bitmap. To get it to work, rasterize the
+// image into a bitmap CGImageRef. This is based loosely on
+// http://www.cocoadev.com/index.pl?CGImageRef.
+- (void)setLayerContents:(CALayer*)layer {
+ NSSize size = [image_ size];
+ CGContextRef context =
+ CGBitmapContextCreate(NULL, // Allow CG to allocate memory.
+ size.width,
+ size.height,
+ 8, // bitsPerComponent
+ 0, // bytesPerRow - CG will calculate by default.
+ [[NSColorSpace genericRGBColorSpace] CGColorSpace],
+ kCGBitmapByteOrder32Host |
+ kCGImageAlphaPremultipliedFirst);
+
+ [NSGraphicsContext saveGraphicsState];
+ [NSGraphicsContext setCurrentContext:
+ [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]];
+ [image_ drawInRect:NSMakeRect(0,0, size.width, size.height)
+ fromRect:NSZeroRect
+ operation:NSCompositeCopy
+ fraction:1.0];
+ [NSGraphicsContext restoreGraphicsState];
Nico 2010/07/19 23:00:35 Please put this into a utility function somewhere
+
+ scoped_cftyperef<CGImageRef> cgImage(CGBitmapContextCreateImage(context));
+ CGContextRelease(context);
+
+ // Create the layer that will be animated.
+ [layer setContents:(id)cgImage.get()];
+}
+
+// CAAnimation delegate method called when the animation is complete.
+- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag {
+ // Close the window, releasing self.
+ [self close];
+}
+
+@end
« no previous file with comments | « chrome/browser/cocoa/animatable_image.h ('k') | chrome/browser/cocoa/animatable_image_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698