| Index: chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
|
| diff --git a/chrome/browser/ui/cocoa/browser_window_enter_fullscreen_transition.mm b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
|
| similarity index 62%
|
| rename from chrome/browser/ui/cocoa/browser_window_enter_fullscreen_transition.mm
|
| rename to chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
|
| index 7eca5ec2087b2c953a1e2a21254a7a57f1700c26..eebd7b70d6e637e5c01309a3a2055d1b69dba645 100644
|
| --- a/chrome/browser/ui/cocoa/browser_window_enter_fullscreen_transition.mm
|
| +++ b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
|
| @@ -2,32 +2,39 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#import "chrome/browser/ui/cocoa/browser_window_enter_fullscreen_transition.h"
|
| +#import "chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h"
|
|
|
| #include <QuartzCore/QuartzCore.h>
|
|
|
| #include "base/mac/scoped_cftyperef.h"
|
| #include "base/mac/scoped_nsobject.h"
|
| #include "base/mac/sdk_forward_declarations.h"
|
| +#import "chrome/browser/ui/cocoa/framed_browser_window.h"
|
| +#import "chrome/browser/ui/cocoa/full_size_content_window.h"
|
|
|
| namespace {
|
|
|
| -NSString* const kPrimaryWindowAnimationID = @"PrimaryWindowAnimationID";
|
| -NSString* const kSnapshotWindowAnimationID = @"SnapshotWindowAnimationID";
|
| -NSString* const kAnimationIDKey = @"AnimationIDKey";
|
| + NSString* const kPrimaryWindowAnimationID = @"PrimaryWindowAnimationID";
|
| + NSString* const kSnapshotWindowAnimationID = @"SnapshotWindowAnimationID";
|
| + NSString* const kAnimationIDKey = @"AnimationIDKey";
|
|
|
| -// This class has two simultaneous animations to resize and reposition layers.
|
| -// These animations must use the same timing function, otherwise there will be
|
| -// visual discordance.
|
| -NSString* TransformAnimationTimingFunction() {
|
| - return kCAMediaTimingFunctionEaseInEaseOut;
|
| -}
|
| + // This class has two simultaneous animations to resize and reposition layers.
|
| + // These animations must use the same timing function, otherwise there will be
|
| + // visual discordance.
|
| + NSString* TransformAnimationTimingFunction() {
|
| + return kCAMediaTimingFunctionEaseInEaseOut;
|
| + }
|
|
|
| } // namespace
|
|
|
| -@interface BrowserWindowEnterFullscreenTransition () {
|
| +
|
| +@interface BrowserWindowFullscreenTransition () {
|
| +
|
| + // Flag to keep track of whether we are entering or exiting full screen
|
| + BOOL isEnteringFullscreen;
|
| +
|
| // The window which is undergoing the fullscreen transition.
|
| - base::scoped_nsobject<NSWindow> primaryWindow_;
|
| + base::scoped_nsobject<FramedBrowserWindow> primaryWindow_;
|
|
|
| // A layer that holds a snapshot of the original state of |primaryWindow_|.
|
| base::scoped_nsobject<CALayer> snapshotLayer_;
|
| @@ -35,9 +42,6 @@ NSString* TransformAnimationTimingFunction() {
|
| // A temporary window that holds |snapshotLayer_|.
|
| base::scoped_nsobject<NSWindow> snapshotWindow_;
|
|
|
| - // The frame of the |primaryWindow_| before the transition began.
|
| - NSRect primaryWindowInitialFrame_;
|
| -
|
| // The background color of |primaryWindow_| before the transition began.
|
| base::scoped_nsobject<NSColor> primaryWindowInitialBackgroundColor_;
|
|
|
| @@ -48,9 +52,16 @@ NSString* TransformAnimationTimingFunction() {
|
| // |primaryWindow_|.
|
| BOOL changingPrimaryWindowSize_;
|
|
|
| + // The frame of the |primaryWindow_| before it starts the transition.
|
| + NSRect initialFrame_;
|
| +
|
| + // The frame of the |primaryWindow_| before it starts the transition
|
| + // relative the the coordinates of its current screen
|
| + NSRect initialFrameRelativeToScreen_;
|
| +
|
| // The frame that |primaryWindow_| is expected to have after the transition
|
| // is finished.
|
| - NSRect primaryWindowFinalFrame_;
|
| + NSRect finalFrame_;
|
| }
|
|
|
| // Takes a snapshot of |primaryWindow_| and puts it in |snapshotLayer_|.
|
| @@ -62,29 +73,34 @@ NSString* TransformAnimationTimingFunction() {
|
| // This method has several effects on |primaryWindow_|:
|
| // - Saves current state.
|
| // - Makes window transparent, with clear background.
|
| -// - Adds NSFullScreenWindowMask style mask.
|
| -// - Sets the size to the screen's size.
|
| +// - If we are entering full screen, it will also:
|
| +// - Adds NSFullScreenWindowMask style mask.
|
| +// - Sets the size to the screen's size.
|
| - (void)preparePrimaryWindowForAnimation;
|
|
|
| +// Returns the windows to be used in the custom transition.
|
| +// - Takes a snapshot of the current window.
|
| +// - Makes a new snapshot window which shows the snapshot in the same
|
| +// location as the current window.
|
| +// - Adds the style mask NSFullScreenWindowMask to the current window.
|
| +// - Makes the current window transparent, and resizes the current window to
|
| +// be the same size as the screen.
|
| +- (NSArray*)customWindowsForFullScreenTransition;
|
| +
|
| // Applies the fullscreen animation to |snapshotLayer_|.
|
| - (void)animateSnapshotWindowWithDuration:(CGFloat)duration;
|
|
|
| -// Applies the fullscreen animation to the root layer of |primaryWindow_|.
|
| -- (void)animatePrimaryWindowWithDuration:(CGFloat)duration;
|
| +- (void)setPrimaryWindowToFinalFrame;
|
|
|
| -// Override of CAAnimation delegate method.
|
| -- (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)flag;
|
| -
|
| -// Returns the layer of the root view of |window|.
|
| - (CALayer*)rootLayerOfWindow:(NSWindow*)window;
|
|
|
| @end
|
|
|
| -@implementation BrowserWindowEnterFullscreenTransition
|
| +@implementation BrowserWindowFullscreenTransition
|
|
|
| // -------------------------Public Methods----------------------------
|
|
|
| -- (instancetype)initWithWindow:(NSWindow*)window {
|
| +- (instancetype)initWithWindow:(FramedBrowserWindow*)window {
|
| DCHECK(window);
|
| DCHECK([self rootLayerOfWindow:window]);
|
| if ((self = [super init])) {
|
| @@ -93,17 +109,48 @@ NSString* TransformAnimationTimingFunction() {
|
| return self;
|
| }
|
|
|
| -- (NSArray*)customWindowsToEnterFullScreen {
|
| - [self takeSnapshot];
|
| - [self makeAndPrepareSnapshotWindow];
|
| - [self preparePrimaryWindowForAnimation];
|
| - return @[ primaryWindow_.get(), snapshotWindow_.get() ];
|
| +- (NSArray*)customWindowsToEnterFullScreenTransition {
|
| + isEnteringFullscreen = YES;
|
| + initialFrame_ = [primaryWindow_ frame];
|
| + finalFrame_ = [[primaryWindow_ screen] frame];
|
| +
|
| + return [self customWindowsForFullScreenTransition];
|
| }
|
|
|
| -- (void)startCustomAnimationToEnterFullScreenWithDuration:
|
| +- (NSArray*)customWindowsToExitFullScreenTransition {
|
| + isEnteringFullscreen = NO;
|
| + finalFrame_ = initialFrame_;
|
| + initialFrame_ = [[primaryWindow_ screen] frame];
|
| +
|
| + // Calculate the inital frame that is relative to coordinates of the
|
| + // screen which it's on
|
| + initialFrameRelativeToScreen_ = finalFrame_;
|
| + CGFloat screenOriginX = finalFrame_.origin.x - initialFrame_.origin.x;
|
| + CGFloat screenOriginY = finalFrame_.origin.y - initialFrame_.origin.y;
|
| + initialFrameRelativeToScreen_.origin =
|
| + CGPointMake(screenOriginX, screenOriginY);
|
| +
|
| + return [self customWindowsForFullScreenTransition];
|
| +}
|
| +
|
| +// Right before the animation begins, change the content view size
|
| +// and lock the primary window so that OSX can't make changes to it
|
| +// before we finish the animation
|
| +- (void)startCustomExitFullScreenAnimationWithDuration:
|
| (NSTimeInterval)duration {
|
| + FullSizeContentView* content =
|
| + (FullSizeContentView*)[primaryWindow_ contentView];
|
| + [content forceFrameSize:finalFrame_.size];
|
| + [primaryWindow_ setFrameAndStyleLock:YES];
|
| +
|
| + [self animatePrimaryWindowWithDuration:duration];
|
| [self animateSnapshotWindowWithDuration:duration];
|
| +}
|
| +
|
| +- (void)startCustomEnterFullScreenAnimationWithDuration:
|
| + (NSTimeInterval)duration {
|
| [self animatePrimaryWindowWithDuration:duration];
|
| + [self animateSnapshotWindowWithDuration:duration];
|
| }
|
|
|
| - (BOOL)shouldWindowBeUnconstrained {
|
| @@ -148,47 +195,27 @@ NSString* TransformAnimationTimingFunction() {
|
| [snapshotLayer_ setFrame:snapshotLayerFrame];
|
| }
|
|
|
| -- (void)preparePrimaryWindowForAnimation {
|
| - // Save initial state of |primaryWindow_|.
|
| - primaryWindowInitialFrame_ = [primaryWindow_ frame];
|
| - primaryWindowInitialBackgroundColor_.reset(
|
| - [[primaryWindow_ backgroundColor] copy]);
|
| - primaryWindowInitialOpaque_ = [primaryWindow_ isOpaque];
|
| -
|
| - primaryWindowFinalFrame_ = [[primaryWindow_ screen] frame];
|
| -
|
| - // Make |primaryWindow_| invisible. This must happen before the window is
|
| - // resized, since resizing the window will call drawRect: and cause content
|
| - // to flash over the entire screen.
|
| - [primaryWindow_ setOpaque:NO];
|
| - [primaryWindow_ setBackgroundColor:[NSColor clearColor]];
|
| - CALayer* rootLayer = [self rootLayerOfWindow:primaryWindow_];
|
| - rootLayer.opacity = 0;
|
| -
|
| - // As soon as the style mask includes the flag NSFullScreenWindowMask, the
|
| - // window is expected to receive fullscreen layout. This must be set before
|
| - // the window is resized, as that causes a relayout.
|
| - [primaryWindow_
|
| - setStyleMask:[primaryWindow_ styleMask] | NSFullScreenWindowMask];
|
| -
|
| - // Resize |primaryWindow_|.
|
| - changingPrimaryWindowSize_ = YES;
|
| - [primaryWindow_ setFrame:primaryWindowFinalFrame_ display:YES];
|
| - changingPrimaryWindowSize_ = NO;
|
| +- (NSArray*)customWindowsForFullScreenTransition {
|
| + [self takeSnapshot];
|
| + [self makeAndPrepareSnapshotWindow];
|
| + [self preparePrimaryWindowForAnimation];
|
| + return @[ primaryWindow_.get(), snapshotWindow_.get() ];
|
| }
|
|
|
| - (void)animateSnapshotWindowWithDuration:(CGFloat)duration {
|
| - // Move the snapshot layer until it's bottom-left corner is at the
|
| - // bottom-left corner of the screen.
|
| + [snapshotWindow_ orderFront:nil];
|
| + NSRect finalScreenFrame = [snapshotWindow_ convertRectFromScreen:finalFrame_];
|
| +
|
| CABasicAnimation* positionAnimation =
|
| [CABasicAnimation animationWithKeyPath:@"position"];
|
| - positionAnimation.toValue = [NSValue valueWithPoint:NSZeroPoint];
|
| + positionAnimation.toValue = [NSValue valueWithPoint:finalScreenFrame.origin];
|
| positionAnimation.timingFunction = [CAMediaTimingFunction
|
| functionWithName:TransformAnimationTimingFunction()];
|
|
|
| - // Expand the bounds until it covers the screen.
|
| - NSRect finalBounds = NSMakeRect(0, 0, NSWidth(primaryWindowFinalFrame_),
|
| - NSHeight(primaryWindowFinalFrame_));
|
| + // Resize the bounds until it reaches the expected size at the end of the
|
| + // animation.
|
| + NSRect finalBounds = NSMakeRect(0, 0, NSWidth(finalFrame_),
|
| + NSHeight(finalFrame_));
|
| CABasicAnimation* boundsAnimation =
|
| [CABasicAnimation animationWithKeyPath:@"bounds"];
|
| boundsAnimation.toValue = [NSValue valueWithRect:finalBounds];
|
| @@ -216,6 +243,7 @@ NSString* TransformAnimationTimingFunction() {
|
| }
|
|
|
| - (void)animatePrimaryWindowWithDuration:(CGFloat)duration {
|
| +
|
| // As soon as the window's root layer is scaled down, the opacity should be
|
| // set back to 1. There are a couple of ways to do this. The easiest is to
|
| // just have a dummy animation as part of the same animation group.
|
| @@ -223,12 +251,13 @@ NSString* TransformAnimationTimingFunction() {
|
| [CABasicAnimation animationWithKeyPath:@"opacity"];
|
| opacityAnimation.fromValue = @(1.0);
|
| opacityAnimation.toValue = @(1.0);
|
| + opacityAnimation.duration = duration;
|
|
|
| // The root layer's size should start scaled down to the initial size of
|
| // |primaryWindow_|. The animation increases the size until the root layer
|
| // fills the screen.
|
| - NSRect initialFrame = primaryWindowInitialFrame_;
|
| - NSRect endFrame = primaryWindowFinalFrame_;
|
| + NSRect initialFrame = initialFrame_;
|
| + NSRect endFrame = finalFrame_;
|
| CGFloat xScale = NSWidth(initialFrame) / NSWidth(endFrame);
|
| CGFloat yScale = NSHeight(initialFrame) / NSHeight(endFrame);
|
| CATransform3D initial = CATransform3DMakeScale(xScale, yScale, 1);
|
| @@ -236,10 +265,9 @@ NSString* TransformAnimationTimingFunction() {
|
| [CABasicAnimation animationWithKeyPath:@"transform"];
|
| transformAnimation.fromValue = [NSValue valueWithCATransform3D:initial];
|
|
|
| - CALayer* root = [self rootLayerOfWindow:primaryWindow_];
|
| -
|
| // Calculate the initial position of the root layer. This calculation is
|
| - // agnostic of the anchorPoint.
|
| + // agnostic of the anchorPoint.
|
| + CALayer* root = [self rootLayerOfWindow:primaryWindow_];
|
| CGFloat layerStartPositionDeltaX = NSMidX(initialFrame) - NSMidX(endFrame);
|
| CGFloat layerStartPositionDeltaY = NSMidY(initialFrame) - NSMidY(endFrame);
|
| NSPoint layerStartPosition =
|
| @@ -255,7 +283,7 @@ NSString* TransformAnimationTimingFunction() {
|
| group.removedOnCompletion = NO;
|
| group.fillMode = kCAFillModeForwards;
|
| group.animations =
|
| - @[ transformAnimation, opacityAnimation, positionAnimation ];
|
| + @[ opacityAnimation, positionAnimation, transformAnimation];
|
| group.timingFunction = [CAMediaTimingFunction
|
| functionWithName:TransformAnimationTimingFunction()];
|
| group.duration = duration;
|
| @@ -265,8 +293,37 @@ NSString* TransformAnimationTimingFunction() {
|
| [root addAnimation:group forKey:kPrimaryWindowAnimationID];
|
| }
|
|
|
| +- (void)preparePrimaryWindowForAnimation {
|
| + // Save the initial state of the primary window
|
| + primaryWindowInitialBackgroundColor_.reset(
|
| + [[primaryWindow_ backgroundColor] copy]);
|
| + primaryWindowInitialOpaque_ = [primaryWindow_ isOpaque];
|
| +
|
| + [primaryWindow_ setOpaque:NO];
|
| +
|
| + CALayer* root = [self rootLayerOfWindow:primaryWindow_];
|
| + root.opacity = 0;
|
| + root.frame = initialFrameRelativeToScreen_;
|
| +
|
| + if (isEnteringFullscreen) {
|
| + [primaryWindow_
|
| + setStyleMask:[primaryWindow_ styleMask] | NSFullScreenWindowMask];
|
| + [self setPrimaryWindowToFinalFrame];
|
| + }
|
| +
|
| +}
|
| +
|
| +- (void)setPrimaryWindowToFinalFrame {
|
| + changingPrimaryWindowSize_ = YES;
|
| + [primaryWindow_ setFrame:finalFrame_ display:NO];
|
| + changingPrimaryWindowSize_ = NO;
|
| +}
|
| +
|
| +
|
| - (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)flag {
|
| NSString* animationID = [theAnimation valueForKey:kAnimationIDKey];
|
| +
|
| + // Remove the snapshot window
|
| if ([animationID isEqual:kSnapshotWindowAnimationID]) {
|
| [snapshotWindow_ orderOut:nil];
|
| snapshotWindow_.reset();
|
| @@ -275,11 +332,24 @@ NSString* TransformAnimationTimingFunction() {
|
| }
|
|
|
| if ([animationID isEqual:kPrimaryWindowAnimationID]) {
|
| - [primaryWindow_ setOpaque:YES];
|
| + // If we're exiting full screen, we want to set the primary window
|
| + // size to the expected frame at the end
|
| + // We will also need to unlock the frame
|
| + if (!isEnteringFullscreen) {
|
| + [primaryWindow_ setFrameAndStyleLock:NO];
|
| + [primaryWindow_
|
| + setStyleMask:[primaryWindow_ styleMask] & ~NSFullScreenWindowMask];
|
| + [self setPrimaryWindowToFinalFrame];
|
| + }
|
| +
|
| + // Restore the state of the primary window and make it visible again
|
| + [primaryWindow_ setOpaque:primaryWindowInitialOpaque_];
|
| [primaryWindow_ setBackgroundColor:primaryWindowInitialBackgroundColor_];
|
| +
|
| CALayer* root = [self rootLayerOfWindow:primaryWindow_];
|
| - root.opacity = 1;
|
| [root removeAnimationForKey:kPrimaryWindowAnimationID];
|
| + root.opacity = 1;
|
| +
|
| }
|
| }
|
|
|
|
|