Index: ui/base/cocoa/window_animator.mm |
diff --git a/ui/base/cocoa/window_animator.mm b/ui/base/cocoa/window_animator.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ee390f7610db1448dea83c2a346999d60f99f81f |
--- /dev/null |
+++ b/ui/base/cocoa/window_animator.mm |
@@ -0,0 +1,92 @@ |
+// Copyright 2015 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 "ui/base/cocoa/window_animator.h" |
+ |
+// Duration of show and hide animations. |
+const NSTimeInterval kDefaultAnimationDuration = 0.2; |
+ |
+@implementation WindowAnimationController |
+ |
+@synthesize orderInDuration = orderInDuration_; |
+@synthesize orderOutDuration = orderOutDuration_; |
+ |
+- (id)init { |
+ if ((self = [super init])) { |
+ orderInDuration_ = kDefaultAnimationDuration; |
+ orderOutDuration_ = kDefaultAnimationDuration; |
+ } |
+ return self; |
+} |
+ |
+- (BOOL)isClosing { |
+ return !!window_; |
+} |
+ |
+- (void)animateWindow:(NSWindow*)window |
+ targetOrigin:(NSPoint)targetOrigin |
+ closing:(BOOL)closing |
+ callback:(const base::Closure&)callback { |
+ // First, stop the existing animation, if there is one. |
+ [animation_ stopAnimation]; |
+ |
+ callback_ = callback; |
+ |
+ NSRect targetFrame = [window frame]; |
+ targetFrame.origin = targetOrigin; |
+ |
+ // NSViewAnimation has a quirk when setting the curve to NSAnimationEaseOut |
+ // where it attempts to auto-reverse the animation. FadeOut becomes FadeIn |
+ // (good), but FrameKey is also switched (bad). So |targetFrame| needs to be |
+ // put on the StartFrameKey when using NSAnimationEaseOut for showing. |
+ NSArray* animationArray = @[ |
+ @{ |
+ NSViewAnimationTargetKey : window, |
+ NSViewAnimationEffectKey : NSViewAnimationFadeOutEffect, |
+ (closing ? NSViewAnimationEndFrameKey : NSViewAnimationStartFrameKey) : |
+ [NSValue valueWithRect:targetFrame] |
+ } |
+ ]; |
+ animation_.reset( |
+ [[NSViewAnimation alloc] initWithViewAnimations:animationArray]); |
+ [animation_ setDelegate:self]; |
+ |
+ if (closing) { |
+ [animation_ setDuration:orderOutDuration_]; |
+ [animation_ setAnimationCurve:NSAnimationEaseIn]; |
+ window_.reset([window retain]); |
+ } else { |
+ [animation_ setDuration:orderInDuration_]; |
+ [window setAlphaValue:0.0f]; |
+ [animation_ setAnimationCurve:NSAnimationEaseOut]; |
+ window_.reset(); |
+ } |
+ // This once used a threaded animation, but AppKit would too often ignore |
+ // -[NSView canDrawConcurrently:] and just redraw whole view hierarchies on |
+ // the animation thread anyway, creating a minefield of race conditions. |
+ // Non-threaded means the animation isn't as smooth and doesn't begin unless |
+ // the UI runloop has spun up (after profile loading). |
+ [animation_ setAnimationBlockingMode:NSAnimationNonblocking]; |
+ |
+ [animation_ startAnimation]; |
+} |
+ |
+- (void)cancelAnimationWithCallback { |
+ // Note: |animation_| can be nil, and this all turns into a no-op. |
+ [animation_ stopAnimation]; |
+ [self animationDidEnd:animation_]; |
+} |
+ |
+- (void)animationDidEnd:(NSAnimation*)animation { |
+ [window_ close]; |
+ window_.reset(); |
+ animation_.reset(); |
+ |
+ if (!callback_.is_null()) { |
+ callback_.Run(); |
+ callback_.Reset(); |
+ } |
+} |
+ |
+@end |