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

Unified Diff: chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm

Issue 1408033010: Fix for Exit Fullscreen Animation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updated comment Created 5 years, 1 month 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
Index: chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
diff --git a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
index e0ac0bc88d7aa6254f2535d24186fdf02d481c20..e3f0291a65c365183ebae1af3daea7f65f07ce35 100644
--- a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
+++ b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
@@ -12,6 +12,7 @@
#import "base/mac/sdk_forward_declarations.h"
#include "base/memory/scoped_ptr.h"
#import "chrome/browser/ui/cocoa/framed_browser_window.h"
+#import "chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h"
namespace {
@@ -19,6 +20,10 @@ NSString* const kPrimaryWindowAnimationID = @"PrimaryWindowAnimationID";
NSString* const kSnapshotWindowAnimationID = @"SnapshotWindowAnimationID";
NSString* const kAnimationIDKey = @"AnimationIDKey";
+// The fraction of the duration from AppKit's startCustomAnimation methods
+// that we want our animation to run in.
+CGFloat const kAnimationDurationFraction = 0.5;
+
// 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.
@@ -34,7 +39,7 @@ class FrameAndStyleLock {
~FrameAndStyleLock() { set_lock(NO); }
- void set_lock(bool lock) { [window_ setFrameAndStyleMaskLock:lock]; }
+ void set_lock(bool lock) { [window_ setStyleMaskLock:lock]; }
private:
FramedBrowserWindow* window_; // weak
@@ -44,6 +49,40 @@ class FrameAndStyleLock {
} // namespace
+// This view draws a dummy toolbar over the resized content view during
+// the exit fullscreen animation. It is removed at the end of the animation.
+@interface FullscreenTabStripBackgroundView : NSView {
+ base::scoped_nsobject<NSColor> windowBackgroundColor_;
+}
+
+- (instancetype)initWithFrame:(NSRect)frame background:(NSColor*)color;
+
+@end
+
+@implementation FullscreenTabStripBackgroundView
+
+- (instancetype)initWithFrame:(NSRect)frame background:(NSColor*)color {
+ if ((self = [super initWithFrame:frame])) {
+ windowBackgroundColor_.reset([color copy]);
+ }
+ return self;
+}
+
+// Override this method so that we can paint the toolbar in this view.
+// This method first fill itself with the toolbar's background. After that,
+// it will paint the window's theme if applicable.
+- (void)drawRect:(NSRect)frame {
+ [windowBackgroundColor_ set];
+ NSRectFillUsingOperation(frame, NSCompositeDestinationOver);
+
+ [FramedBrowserWindow drawWindowThemeInDirtyRect:frame
+ forView:self
+ bounds:[self bounds]
+ forceBlackBackground:NO];
+}
+
+@end
+
@interface BrowserWindowFullscreenTransition () {
// Flag to keep track of whether we are entering or exiting fullscreen.
BOOL isEnteringFullscreen_;
@@ -57,12 +96,26 @@ class FrameAndStyleLock {
// A temporary window that holds |snapshotLayer_|.
base::scoped_nsobject<NSWindow> snapshotWindow_;
+ // The tabstrip background view in the window. During the exit fullscreen
+ // animation, this view be hidden while a dummy tabstrip background will be
+ // drawn over the content view.
+ base::scoped_nsobject<NSView> tabStripBackgroundView_;
+
// The background color of |primaryWindow_| before the transition began.
base::scoped_nsobject<NSColor> primaryWindowInitialBackgroundColor_;
// Whether |primaryWindow_| was opaque before the transition began.
BOOL primaryWindowInitialOpaque_;
+ // The initial anchor point of the root layer.
+ CGPoint initialRootAnchorPoint_;
+
+ // The initial origin of the content view.
+ NSPoint initialContentViewOrigin_;
+
+ // The initial value of the content view's autoresizeSubviews property.
+ BOOL initialContentViewAutoresizesSubviews_;
+
// Whether the instance is in the process of changing the size of
// |primaryWindow_|.
BOOL changingPrimaryWindowSize_;
@@ -74,6 +127,10 @@ class FrameAndStyleLock {
// is finished.
NSRect finalFrame_;
+ // This view draws the tabstrip background during the exit animation.
+ base::scoped_nsobject<FullscreenTabStripBackgroundView>
+ fullscreenTabStripBackgroundView_;
+
// Locks and unlocks the FullSizeContentWindow.
scoped_ptr<FrameAndStyleLock> lock_;
}
@@ -139,12 +196,13 @@ class FrameAndStyleLock {
}
- (instancetype)initExitWithWindow:(FramedBrowserWindow*)window
- frame:(NSRect)frame {
+ frame:(NSRect)frame
+ tabStripBackgroundView:(NSView*)view {
DCHECK(window);
DCHECK([self rootLayerOfWindow:window]);
if ((self = [super init])) {
primaryWindow_.reset([window retain]);
-
+ tabStripBackgroundView_.reset([view retain]);
isEnteringFullscreen_ = NO;
finalFrame_ = frame;
initialFrame_ = [[primaryWindow_ screen] frame];
@@ -161,9 +219,10 @@ class FrameAndStyleLock {
}
- (void)startCustomFullScreenAnimationWithDuration:(NSTimeInterval)duration {
+ CGFloat animationDuration = duration * kAnimationDurationFraction;
[self preparePrimaryWindowForAnimation];
- [self animatePrimaryWindowWithDuration:duration];
- [self animateSnapshotWindowWithDuration:duration];
+ [self animatePrimaryWindowWithDuration:animationDuration];
+ [self animateSnapshotWindowWithDuration:animationDuration];
}
- (BOOL)shouldWindowBeUnconstrained {
@@ -210,6 +269,12 @@ class FrameAndStyleLock {
NSRect snapshotLayerFrame =
[snapshotWindow_ convertRectFromScreen:[primaryWindow_ frame]];
[snapshotLayer_ setFrame:snapshotLayerFrame];
+
+ // If the primary window is in fullscreen mode, we can't move the snapshot
+ // window in front of it. As a result, at the beginning of the transition to
+ // exit fullscreen, we should order the snapshot window to the front ASAP.
+ if (isEnteringFullscreen_)
+ [snapshotWindow_ orderFront:nil];
}
- (void)preparePrimaryWindowForAnimation {
@@ -222,35 +287,81 @@ class FrameAndStyleLock {
// resized, since resizing the window will call drawRect: and cause content
// to flash over the entire screen.
[primaryWindow_ setOpaque:NO];
- CALayer* root = [self rootLayerOfWindow:primaryWindow_];
- root.opacity = 0;
if (isEnteringFullscreen_) {
// 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.
+
+ CALayer* root = [self rootLayerOfWindow:primaryWindow_];
+ root.opacity = 0;
+
[primaryWindow_
setStyleMask:[primaryWindow_ styleMask] | NSFullScreenWindowMask];
[self changePrimaryWindowToFinalFrame];
} else {
- // Set the size of the root layer to the size of the final frame. The root
- // layer is placed at position (0, 0) because the animation will take care
- // of the layer's start and end position.
- root.frame =
- NSMakeRect(0, 0, finalFrame_.size.width, finalFrame_.size.height);
+ [snapshotWindow_ orderFront:nil];
+
+ NSView* contentView = [primaryWindow_ contentView];
+ NSView* rootView = [contentView superview];
+
+ // Since only the content view is resized, the window's background
+ // must be transparent. This is a hack that forces the layer to remove
+ // the textured background and replace it with clearColor.
+ [rootView setWantsLayer:NO];
+ [primaryWindow_ setBackgroundColor:[NSColor clearColor]];
+ [primaryWindow_ setStyleMask:[primaryWindow_ styleMask] &
+ ~NSTexturedBackgroundWindowMask];
+ [rootView setWantsLayer:YES];
+
+ CALayer* root = [self rootLayerOfWindow:primaryWindow_];
+ root.opacity = 0;
// Right before the animation begins, change the contentView size to the
// expected size at the end of the animation. Afterwards, lock the
// |primaryWindow_| so that AppKit will not be able to make unwanted
// changes to it during the animation.
- [primaryWindow_ forceContentViewSize:finalFrame_.size];
+ initialContentViewOrigin_ = [[primaryWindow_ contentView] frame].origin;
+ initialRootAnchorPoint_ = root.anchorPoint;
+
+ NSPoint contentViewOrigin =
+ [self pointRelativeToCurrentScreen:finalFrame_.origin];
+ NSRect relativeContentFinalFrame =
+ NSMakeRect(contentViewOrigin.x, contentViewOrigin.y,
+ finalFrame_.size.width, finalFrame_.size.height);
+ [primaryWindow_ forceContentViewFrame:relativeContentFinalFrame];
+
+ // In OSX 10.11, when the NSFullScreenWindowMask is added or removed,
+ // the window's frame and layer changes slightly which causes a janky
+ // movement. As a result, we should disable the content view's autoresize
+ // at the beginning of the animation and set it back to its original value
+ // at the end of the animation.
+ initialContentViewAutoresizesSubviews_ = [contentView autoresizesSubviews];
+ [contentView setAutoresizesSubviews:NO];
+
+ fullscreenTabStripBackgroundView_.reset(
+ [[FullscreenTabStripBackgroundView alloc]
+ initWithFrame:finalFrame_
+ background:primaryWindowInitialBackgroundColor_]);
+ [fullscreenTabStripBackgroundView_ setFrameOrigin:NSZeroPoint];
+ [contentView addSubview:fullscreenTabStripBackgroundView_.get()
+ positioned:NSWindowBelow
+ relativeTo:nil];
+
+ [tabStripBackgroundView_ setHidden:YES];
+
+ // Set anchor point to be the center of the content view
+ CGFloat anchorPointX =
+ NSMidX(relativeContentFinalFrame) / NSWidth(initialFrame_);
+ CGFloat anchorPointY =
+ NSMidY(relativeContentFinalFrame) / NSHeight(initialFrame_);
+ root.anchorPoint = CGPointMake(anchorPointX, anchorPointY);
+
lock_->set_lock(YES);
}
}
- (void)animateSnapshotWindowWithDuration:(CGFloat)duration {
- [snapshotWindow_ orderFront:nil];
-
// Calculate the frame so that it's relative to the screen.
NSRect finalFrameRelativeToScreen =
[snapshotWindow_ convertRectFromScreen:finalFrame_];
@@ -325,15 +436,10 @@ class FrameAndStyleLock {
[self pointRelativeToCurrentScreen:centerOfInitialFrame];
positionAnimation.fromValue = [NSValue valueWithPoint:startingLayerPoint];
- // Since the root layer's frame is different from the window, AppKit might
- // animate it to a different position if we have multiple windows in
- // fullscreen. This ensures that the animation moves to the correct position.
- CGFloat anchorPointX = NSWidth(endFrame) / 2;
- CGFloat anchorPointY = NSHeight(endFrame) / 2;
- NSPoint endLayerPoint = [self pointRelativeToCurrentScreen:endFrame.origin];
- positionAnimation.toValue =
- [NSValue valueWithPoint:NSMakePoint(endLayerPoint.x + anchorPointX,
- endLayerPoint.y + anchorPointY)];
+ NSPoint endingLayerPoint =
+ [self pointRelativeToCurrentScreen:NSMakePoint(NSMidX(endFrame),
+ NSMidY(endFrame))];
+ positionAnimation.toValue = [NSValue valueWithPoint:endingLayerPoint];
CAAnimationGroup* group = [CAAnimationGroup animation];
group.removedOnCompletion = NO;
@@ -373,9 +479,22 @@ class FrameAndStyleLock {
// lock must also be released.
if (!isEnteringFullscreen_) {
lock_->set_lock(NO);
- [primaryWindow_
- setStyleMask:[primaryWindow_ styleMask] & ~NSFullScreenWindowMask];
+
+ CALayer* root = [self rootLayerOfWindow:primaryWindow_];
+ root.anchorPoint = initialRootAnchorPoint_;
+
+ NSUInteger styleMask =
+ ([primaryWindow_ styleMask] & ~NSFullScreenWindowMask) |
+ NSTexturedBackgroundWindowMask;
+ [primaryWindow_ setStyleMask:styleMask];
+
+ NSView* content = [primaryWindow_ contentView];
+ [content setFrameOrigin:initialContentViewOrigin_];
[self changePrimaryWindowToFinalFrame];
+ [content setAutoresizesSubviews:initialContentViewAutoresizesSubviews_];
+
+ [tabStripBackgroundView_ setHidden:NO];
+ [fullscreenTabStripBackgroundView_ removeFromSuperview];
}
// Checks if the contentView size is correct.
« no previous file with comments | « chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h ('k') | chrome/browser/ui/cocoa/framed_browser_window.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698