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

Side by Side Diff: chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm

Issue 1276383004: Implemented fullscreen exit animation with AppKit (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Made some changes according to missed comments on Patch Created 5 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/ui/cocoa/browser_window_enter_fullscreen_transition.h" 5 #import "chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h"
6 6
7 #include <QuartzCore/QuartzCore.h> 7 #include <QuartzCore/QuartzCore.h>
8 8
9 #include "base/mac/scoped_cftyperef.h" 9 #include "base/mac/bind_objc_block.h"
10 #include "base/mac/scoped_nsobject.h" 10 #include "base/mac/foundation_util.h"
11 #include "base/mac/sdk_forward_declarations.h" 11 #include "base/mac/mac_util.h"
12 #import "base/mac/scoped_nsobject.h"
13 #import "base/mac/sdk_forward_declarations.h"
14 #include "base/memory/scoped_ptr.h"
15 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
16 #import "chrome/browser/ui/cocoa/full_size_content_window.h"
12 17
13 namespace { 18 namespace {
14 19
15 NSString* const kPrimaryWindowAnimationID = @"PrimaryWindowAnimationID"; 20 NSString* const kPrimaryWindowAnimationID = @"PrimaryWindowAnimationID";
16 NSString* const kSnapshotWindowAnimationID = @"SnapshotWindowAnimationID"; 21 NSString* const kSnapshotWindowAnimationID = @"SnapshotWindowAnimationID";
17 NSString* const kAnimationIDKey = @"AnimationIDKey"; 22 NSString* const kAnimationIDKey = @"AnimationIDKey";
18 23
19 // This class has two simultaneous animations to resize and reposition layers. 24 // This class has two simultaneous animations to resize and reposition layers.
20 // These animations must use the same timing function, otherwise there will be 25 // These animations must use the same timing function, otherwise there will be
21 // visual discordance. 26 // visual discordance.
22 NSString* TransformAnimationTimingFunction() { 27 NSString* TransformAnimationTimingFunction() {
23 return kCAMediaTimingFunctionEaseInEaseOut; 28 return kCAMediaTimingFunctionEaseInEaseOut;
24 } 29 }
25 30
31 // This class locks and unlocks the FrameBrowserWindow. Its destructor
32 // ensures that the lock gets released.
33 class FrameAndStyleLock {
34 public:
35 FrameAndStyleLock(FramedBrowserWindow* window) {
36 window_.reset([window retain]);
37 }
38
39 void setLock(bool lock) { [window_ setFrameAndStyleMaskLock:lock]; }
40
41 ~FrameAndStyleLock() { setLock(NO); }
42
43 private:
44 base::scoped_nsobject<FramedBrowserWindow> window_;
45 };
46
26 } // namespace 47 } // namespace
27 48
28 @interface BrowserWindowEnterFullscreenTransition () { 49 @interface BrowserWindowFullscreenTransition () {
50 // Flag to keep track of whether we are entering or exiting full screen
51 BOOL isEnteringFullscreen_;
52
29 // The window which is undergoing the fullscreen transition. 53 // The window which is undergoing the fullscreen transition.
30 base::scoped_nsobject<NSWindow> primaryWindow_; 54 base::scoped_nsobject<FramedBrowserWindow> primaryWindow_;
31 55
32 // A layer that holds a snapshot of the original state of |primaryWindow_|. 56 // A layer that holds a snapshot of the original state of |primaryWindow_|.
33 base::scoped_nsobject<CALayer> snapshotLayer_; 57 base::scoped_nsobject<CALayer> snapshotLayer_;
34 58
35 // A temporary window that holds |snapshotLayer_|. 59 // A temporary window that holds |snapshotLayer_|.
36 base::scoped_nsobject<NSWindow> snapshotWindow_; 60 base::scoped_nsobject<NSWindow> snapshotWindow_;
37 61
38 // The frame of the |primaryWindow_| before the transition began.
39 NSRect primaryWindowInitialFrame_;
40
41 // The background color of |primaryWindow_| before the transition began. 62 // The background color of |primaryWindow_| before the transition began.
42 base::scoped_nsobject<NSColor> primaryWindowInitialBackgroundColor_; 63 base::scoped_nsobject<NSColor> primaryWindowInitialBackgroundColor_;
43 64
44 // Whether |primaryWindow_| was opaque before the transition began. 65 // Whether |primaryWindow_| was opaque before the transition began.
45 BOOL primaryWindowInitialOpaque_; 66 BOOL primaryWindowInitialOpaque_;
46 67
47 // Whether the instance is in the process of changing the size of 68 // Whether the instance is in the process of changing the size of
48 // |primaryWindow_|. 69 // |primaryWindow_|.
49 BOOL changingPrimaryWindowSize_; 70 BOOL changingPrimaryWindowSize_;
50 71
72 // The frame of the |primaryWindow_| before it starts the transition.
73 NSRect initialFrame_;
74
75 // A frame that represents the value of the |initialFrame_| that's relative
76 // to the current screen coordinates.
erikchen 2015/08/12 22:08:52 It looks like initialFrameRelativeToScreen_ is use
spqchan1 2015/08/13 20:38:48 Done. I modified the name so that it's less confus
77 NSRect initialFrameRelativeToScreen_;
erikchen 2015/08/12 22:08:52 If this ivar is only used for the exit animation,
spqchan1 2015/08/13 20:38:48 Done.
78
51 // The frame that |primaryWindow_| is expected to have after the transition 79 // The frame that |primaryWindow_| is expected to have after the transition
52 // is finished. 80 // is finished.
53 NSRect primaryWindowFinalFrame_; 81 NSRect finalFrame_;
82
83 // Locks and unlocks the FullSizeContentWindow.
84 scoped_ptr<FrameAndStyleLock> lock_;
54 } 85 }
55 86
56 // Takes a snapshot of |primaryWindow_| and puts it in |snapshotLayer_|. 87 // Takes a snapshot of |primaryWindow_| and puts it in |snapshotLayer_|.
57 - (void)takeSnapshot; 88 - (void)takeSnapshot;
58 89
59 // Creates |snapshotWindow_| and adds |snapshotLayer_| to it. 90 // Creates |snapshotWindow_| and adds |snapshotLayer_| to it.
60 - (void)makeAndPrepareSnapshotWindow; 91 - (void)makeAndPrepareSnapshotWindow;
61 92
62 // This method has several effects on |primaryWindow_|: 93 // This method has several effects on |primaryWindow_|:
63 // - Saves current state. 94 // - Saves current state.
64 // - Makes window transparent, with clear background. 95 // - Makes window transparent, with clear background.
65 // - Adds NSFullScreenWindowMask style mask. 96 // - If we are entering fullscreen, it will also:
66 // - Sets the size to the screen's size. 97 // - Add NSFullScreenWindowMask style mask.
98 // - Set the size to the screen's size.
67 - (void)preparePrimaryWindowForAnimation; 99 - (void)preparePrimaryWindowForAnimation;
68 100
69 // Applies the fullscreen animation to |snapshotLayer_|. 101 // Applies the fullscreen animation to |snapshotLayer_|.
70 - (void)animateSnapshotWindowWithDuration:(CGFloat)duration; 102 - (void)animateSnapshotWindowWithDuration:(CGFloat)duration;
71 103
72 // Applies the fullscreen animation to the root layer of |primaryWindow_|. 104 // Sets |primaryWindow_|'s frame to the expected frame.
73 - (void)animatePrimaryWindowWithDuration:(CGFloat)duration; 105 - (void)changePrimaryWindowToFinalFrame;
74 106
75 // Override of CAAnimation delegate method. 107 // Override of CAAnimation delegate method.
76 - (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)flag; 108 - (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)flag;
77 109
78 // Returns the layer of the root view of |window|. 110 // Returns the layer of the root view of |window|.
79 - (CALayer*)rootLayerOfWindow:(NSWindow*)window; 111 - (CALayer*)rootLayerOfWindow:(NSWindow*)window;
80 112
81 @end 113 @end
82 114
83 @implementation BrowserWindowEnterFullscreenTransition 115 @implementation BrowserWindowFullscreenTransition
84 116
85 // -------------------------Public Methods---------------------------- 117 // -------------------------Public Methods----------------------------
86 118
87 - (instancetype)initWithWindow:(NSWindow*)window { 119 - (instancetype)initEnterWithWindow:(FramedBrowserWindow*)window {
88 DCHECK(window); 120 DCHECK(window);
89 DCHECK([self rootLayerOfWindow:window]); 121 DCHECK([self rootLayerOfWindow:window]);
90 if ((self = [super init])) { 122 if ((self = [super init])) {
91 primaryWindow_.reset([window retain]); 123 primaryWindow_.reset([window retain]);
124
125 isEnteringFullscreen_ = YES;
126 initialFrame_ = [primaryWindow_ frame];
127 finalFrame_ = [[primaryWindow_ screen] frame];
92 } 128 }
93 return self; 129 return self;
94 } 130 }
95 131
96 - (NSArray*)customWindowsToEnterFullScreen { 132 - (instancetype)initExitWithWindow:(FramedBrowserWindow*)window
133 frame:(NSRect)frame {
134 DCHECK(window);
135 DCHECK([self rootLayerOfWindow:window]);
136 if ((self = [super init])) {
137 primaryWindow_.reset([window retain]);
138
139 isEnteringFullscreen_ = NO;
140 finalFrame_ = frame;
141 initialFrame_ = [[primaryWindow_ screen] frame];
142
143 // Calculate the inital frame that is relative to coordinates of the
144 // screen which it's on.
145 initialFrameRelativeToScreen_ = finalFrame_;
146 CGFloat screenOriginX = finalFrame_.origin.x - initialFrame_.origin.x;
147 CGFloat screenOriginY = finalFrame_.origin.y - initialFrame_.origin.y;
148 initialFrameRelativeToScreen_.origin =
149 CGPointMake(screenOriginX, screenOriginY);
150
151 lock_.reset(new FrameAndStyleLock(window));
152 }
153 return self;
154 }
155
156 - (NSArray*)customWindowsForFullScreenTransition {
97 [self takeSnapshot]; 157 [self takeSnapshot];
98 [self makeAndPrepareSnapshotWindow]; 158 [self makeAndPrepareSnapshotWindow];
99 [self preparePrimaryWindowForAnimation];
100 return @[ primaryWindow_.get(), snapshotWindow_.get() ]; 159 return @[ primaryWindow_.get(), snapshotWindow_.get() ];
101 } 160 }
102 161
103 - (void)startCustomAnimationToEnterFullScreenWithDuration: 162 // Right before the animation begins, change the content view size
104 (NSTimeInterval)duration { 163 // and lock the primary window so that OSX can't make changes to it
erikchen 2015/08/12 22:08:52 The lock only happens for the exit animation, righ
spqchan1 2015/08/13 20:38:48 Done. Moved this comment to the inside of prepareP
164 // before we finish the animation.
165 - (void)startCustomFullScreenAnimationWithDuration:(NSTimeInterval)duration {
166 [self preparePrimaryWindowForAnimation];
167 [self animatePrimaryWindowWithDuration:duration];
105 [self animateSnapshotWindowWithDuration:duration]; 168 [self animateSnapshotWindowWithDuration:duration];
106 [self animatePrimaryWindowWithDuration:duration];
107 } 169 }
108 170
109 - (BOOL)shouldWindowBeUnconstrained { 171 - (BOOL)shouldWindowBeUnconstrained {
110 return changingPrimaryWindowSize_; 172 return changingPrimaryWindowSize_;
111 } 173 }
112 174
175 - (NSSize)getDesiredWindowLayoutSize {
176 return (isEnteringFullscreen_) ? [primaryWindow_ frame].size
177 : [[primaryWindow_ contentView] bounds].size;
178 }
179
113 // -------------------------Private Methods---------------------------- 180 // -------------------------Private Methods----------------------------
114 181
115 - (void)takeSnapshot { 182 - (void)takeSnapshot {
116 base::ScopedCFTypeRef<CGImageRef> windowSnapshot(CGWindowListCreateImage( 183 base::ScopedCFTypeRef<CGImageRef> windowSnapshot(CGWindowListCreateImage(
117 CGRectNull, kCGWindowListOptionIncludingWindow, 184 CGRectNull, kCGWindowListOptionIncludingWindow,
118 [primaryWindow_ windowNumber], kCGWindowImageBoundsIgnoreFraming)); 185 [primaryWindow_ windowNumber], kCGWindowImageBoundsIgnoreFraming));
119 snapshotLayer_.reset([[CALayer alloc] init]); 186 snapshotLayer_.reset([[CALayer alloc] init]);
120 [snapshotLayer_ setFrame:NSRectToCGRect([primaryWindow_ frame])]; 187 [snapshotLayer_ setFrame:NSRectToCGRect([primaryWindow_ frame])];
121 [snapshotLayer_ setContents:static_cast<id>(windowSnapshot.get())]; 188 [snapshotLayer_ setContents:static_cast<id>(windowSnapshot.get())];
122 [snapshotLayer_ setAnchorPoint:CGPointMake(0, 0)]; 189 [snapshotLayer_ setAnchorPoint:CGPointMake(0, 0)];
123 CGColorRef colorRef = CGColorCreateGenericRGB(0, 0, 0, 0); 190 CGColorRef colorRef = CGColorCreateGenericRGB(0, 0, 0, 0);
124 [snapshotLayer_ setBackgroundColor:colorRef]; 191 [snapshotLayer_ setBackgroundColor:colorRef];
125 CGColorRelease(colorRef); 192 CGColorRelease(colorRef);
126 } 193 }
127 194
128 - (void)makeAndPrepareSnapshotWindow { 195 - (void)makeAndPrepareSnapshotWindow {
129 DCHECK(snapshotLayer_); 196 DCHECK(snapshotLayer_);
130 197
131 snapshotWindow_.reset( 198 snapshotWindow_.reset([[NSWindow alloc]
132 [[NSWindow alloc] initWithContentRect:[[primaryWindow_ screen] frame] 199 initWithContentRect:[[primaryWindow_ screen] frame]
133 styleMask:0 200 styleMask:0
134 backing:NSBackingStoreBuffered 201 backing:NSBackingStoreBuffered
135 defer:NO]); 202 defer:NO]);
136 [[snapshotWindow_ contentView] setWantsLayer:YES]; 203 [[snapshotWindow_ contentView] setWantsLayer:YES];
137 [snapshotWindow_ setOpaque:NO]; 204 [snapshotWindow_ setOpaque:NO];
138 [snapshotWindow_ setBackgroundColor:[NSColor clearColor]]; 205 [snapshotWindow_ setBackgroundColor:[NSColor clearColor]];
139 [snapshotWindow_ setAnimationBehavior:NSWindowAnimationBehaviorNone]; 206 [snapshotWindow_ setAnimationBehavior:NSWindowAnimationBehaviorNone];
140 207
141 [snapshotWindow_ orderFront:nil];
142 [[[snapshotWindow_ contentView] layer] addSublayer:snapshotLayer_]; 208 [[[snapshotWindow_ contentView] layer] addSublayer:snapshotLayer_];
143 209
144 // Compute the frame of the snapshot layer such that the snapshot is 210 // Compute the frame of the snapshot layer such that the snapshot is
145 // positioned exactly on top of the original position of |primaryWindow_|. 211 // positioned exactly on top of the original position of |primaryWindow_|.
146 NSRect snapshotLayerFrame = 212 NSRect snapshotLayerFrame =
147 [snapshotWindow_ convertRectFromScreen:[primaryWindow_ frame]]; 213 [snapshotWindow_ convertRectFromScreen:[primaryWindow_ frame]];
148 [snapshotLayer_ setFrame:snapshotLayerFrame]; 214 [snapshotLayer_ setFrame:snapshotLayerFrame];
149 } 215 }
150 216
151 - (void)preparePrimaryWindowForAnimation { 217 - (void)preparePrimaryWindowForAnimation {
152 // Save initial state of |primaryWindow_|. 218 // Save the initial state of the primary window.
153 primaryWindowInitialFrame_ = [primaryWindow_ frame];
154 primaryWindowInitialBackgroundColor_.reset( 219 primaryWindowInitialBackgroundColor_.reset(
155 [[primaryWindow_ backgroundColor] copy]); 220 [[primaryWindow_ backgroundColor] copy]);
156 primaryWindowInitialOpaque_ = [primaryWindow_ isOpaque]; 221 primaryWindowInitialOpaque_ = [primaryWindow_ isOpaque];
157 222
158 primaryWindowFinalFrame_ = [[primaryWindow_ screen] frame]; 223 [primaryWindow_ setOpaque:NO];
159 224
160 // Make |primaryWindow_| invisible. This must happen before the window is 225 CALayer* root = [self rootLayerOfWindow:primaryWindow_];
erikchen 2015/08/12 22:08:52 Why did you remove these comments?
spqchan1 2015/08/13 20:38:48 Whoops, these were accidentally removed when I was
161 // resized, since resizing the window will call drawRect: and cause content 226 root.opacity = 0;
162 // to flash over the entire screen. 227 root.frame = initialFrameRelativeToScreen_;
erikchen 2015/08/12 22:08:52 The enter animation didn't need to set the root's
spqchan1 2015/08/13 20:38:48 This should only be used for the exit animation. I
163 [primaryWindow_ setOpaque:NO];
164 [primaryWindow_ setBackgroundColor:[NSColor clearColor]];
165 CALayer* rootLayer = [self rootLayerOfWindow:primaryWindow_];
166 rootLayer.opacity = 0;
167 228
168 // As soon as the style mask includes the flag NSFullScreenWindowMask, the 229 if (isEnteringFullscreen_) {
169 // window is expected to receive fullscreen layout. This must be set before 230 [primaryWindow_
170 // the window is resized, as that causes a relayout. 231 setStyleMask:[primaryWindow_ styleMask] | NSFullScreenWindowMask];
171 [primaryWindow_ 232 [self changePrimaryWindowToFinalFrame];
172 setStyleMask:[primaryWindow_ styleMask] | NSFullScreenWindowMask]; 233 } else {
173 234 FullSizeContentView* content =
174 // Resize |primaryWindow_|. 235 base::mac::ObjCCast<FullSizeContentView>([primaryWindow_ contentView]);
175 changingPrimaryWindowSize_ = YES; 236 [content forceFrameSize:finalFrame_.size];
176 [primaryWindow_ setFrame:primaryWindowFinalFrame_ display:YES]; 237 lock_->setLock(YES);
177 changingPrimaryWindowSize_ = NO; 238 }
178 } 239 }
179 240
180 - (void)animateSnapshotWindowWithDuration:(CGFloat)duration { 241 - (void)animateSnapshotWindowWithDuration:(CGFloat)duration {
181 // Move the snapshot layer until it's bottom-left corner is at the 242 [snapshotWindow_ orderFront:nil];
erikchen 2015/08/12 22:08:52 Why did you move this from makeAndPrepareSnapshotW
spqchan1 2015/08/13 20:38:48 I moved this out of makeAndPrepareSnapshotWindow b
182 // bottom-left corner of the screen. 243
244 // Calculate the frame so that it's relative to the screen
245 NSRect finalFrameRelativeToScreen =
246 [snapshotWindow_ convertRectFromScreen:finalFrame_];
247
183 CABasicAnimation* positionAnimation = 248 CABasicAnimation* positionAnimation =
184 [CABasicAnimation animationWithKeyPath:@"position"]; 249 [CABasicAnimation animationWithKeyPath:@"position"];
185 positionAnimation.toValue = [NSValue valueWithPoint:NSZeroPoint]; 250 positionAnimation.toValue =
251 [NSValue valueWithPoint:finalFrameRelativeToScreen.origin];
186 positionAnimation.timingFunction = [CAMediaTimingFunction 252 positionAnimation.timingFunction = [CAMediaTimingFunction
187 functionWithName:TransformAnimationTimingFunction()]; 253 functionWithName:TransformAnimationTimingFunction()];
188 254
189 // Expand the bounds until it covers the screen. 255 // Resize the bounds until it reaches the expected size at the end of the
190 NSRect finalBounds = NSMakeRect(0, 0, NSWidth(primaryWindowFinalFrame_), 256 // animation.
191 NSHeight(primaryWindowFinalFrame_)); 257 NSRect finalBounds =
258 NSMakeRect(0, 0, NSWidth(finalFrame_), NSHeight(finalFrame_));
192 CABasicAnimation* boundsAnimation = 259 CABasicAnimation* boundsAnimation =
193 [CABasicAnimation animationWithKeyPath:@"bounds"]; 260 [CABasicAnimation animationWithKeyPath:@"bounds"];
194 boundsAnimation.toValue = [NSValue valueWithRect:finalBounds]; 261 boundsAnimation.toValue = [NSValue valueWithRect:finalBounds];
195 boundsAnimation.timingFunction = [CAMediaTimingFunction 262 boundsAnimation.timingFunction = [CAMediaTimingFunction
196 functionWithName:TransformAnimationTimingFunction()]; 263 functionWithName:TransformAnimationTimingFunction()];
197 264
198 // Fade out the snapshot layer. 265 // Fade out the snapshot layer.
199 CABasicAnimation* opacityAnimation = 266 CABasicAnimation* opacityAnimation =
200 [CABasicAnimation animationWithKeyPath:@"opacity"]; 267 [CABasicAnimation animationWithKeyPath:@"opacity"];
201 opacityAnimation.toValue = @(0.0); 268 opacityAnimation.toValue = @(0.0);
(...skipping 18 matching lines...) Expand all
220 // set back to 1. There are a couple of ways to do this. The easiest is to 287 // set back to 1. There are a couple of ways to do this. The easiest is to
221 // just have a dummy animation as part of the same animation group. 288 // just have a dummy animation as part of the same animation group.
222 CABasicAnimation* opacityAnimation = 289 CABasicAnimation* opacityAnimation =
223 [CABasicAnimation animationWithKeyPath:@"opacity"]; 290 [CABasicAnimation animationWithKeyPath:@"opacity"];
224 opacityAnimation.fromValue = @(1.0); 291 opacityAnimation.fromValue = @(1.0);
225 opacityAnimation.toValue = @(1.0); 292 opacityAnimation.toValue = @(1.0);
226 293
227 // The root layer's size should start scaled down to the initial size of 294 // The root layer's size should start scaled down to the initial size of
228 // |primaryWindow_|. The animation increases the size until the root layer 295 // |primaryWindow_|. The animation increases the size until the root layer
229 // fills the screen. 296 // fills the screen.
230 NSRect initialFrame = primaryWindowInitialFrame_; 297 NSRect initialFrame = initialFrame_;
231 NSRect endFrame = primaryWindowFinalFrame_; 298 NSRect endFrame = finalFrame_;
232 CGFloat xScale = NSWidth(initialFrame) / NSWidth(endFrame); 299 CGFloat xScale = NSWidth(initialFrame) / NSWidth(endFrame);
233 CGFloat yScale = NSHeight(initialFrame) / NSHeight(endFrame); 300 CGFloat yScale = NSHeight(initialFrame) / NSHeight(endFrame);
234 CATransform3D initial = CATransform3DMakeScale(xScale, yScale, 1); 301 CATransform3D initial = CATransform3DMakeScale(xScale, yScale, 1);
235 CABasicAnimation* transformAnimation = 302 CABasicAnimation* transformAnimation =
236 [CABasicAnimation animationWithKeyPath:@"transform"]; 303 [CABasicAnimation animationWithKeyPath:@"transform"];
237 transformAnimation.fromValue = [NSValue valueWithCATransform3D:initial]; 304 transformAnimation.fromValue = [NSValue valueWithCATransform3D:initial];
238 305
239 CALayer* root = [self rootLayerOfWindow:primaryWindow_];
240
241 // Calculate the initial position of the root layer. This calculation is 306 // Calculate the initial position of the root layer. This calculation is
242 // agnostic of the anchorPoint. 307 // agnostic of the anchorPoint.
308 CALayer* root = [self rootLayerOfWindow:primaryWindow_];
243 CGFloat layerStartPositionDeltaX = NSMidX(initialFrame) - NSMidX(endFrame); 309 CGFloat layerStartPositionDeltaX = NSMidX(initialFrame) - NSMidX(endFrame);
244 CGFloat layerStartPositionDeltaY = NSMidY(initialFrame) - NSMidY(endFrame); 310 CGFloat layerStartPositionDeltaY = NSMidY(initialFrame) - NSMidY(endFrame);
245 NSPoint layerStartPosition = 311 NSPoint layerStartPosition =
246 NSMakePoint(root.position.x + layerStartPositionDeltaX, 312 NSMakePoint(root.position.x + layerStartPositionDeltaX,
247 root.position.y + layerStartPositionDeltaY); 313 root.position.y + layerStartPositionDeltaY);
248 314
249 // Animate the primary window from its initial position. 315 // Animate the primary window from its initial position.
250 CABasicAnimation* positionAnimation = 316 CABasicAnimation* positionAnimation =
251 [CABasicAnimation animationWithKeyPath:@"position"]; 317 [CABasicAnimation animationWithKeyPath:@"position"];
252 positionAnimation.fromValue = [NSValue valueWithPoint:layerStartPosition]; 318 positionAnimation.fromValue = [NSValue valueWithPoint:layerStartPosition];
253 319
254 CAAnimationGroup* group = [CAAnimationGroup animation]; 320 CAAnimationGroup* group = [CAAnimationGroup animation];
255 group.removedOnCompletion = NO; 321 group.removedOnCompletion = NO;
256 group.fillMode = kCAFillModeForwards; 322 group.fillMode = kCAFillModeForwards;
257 group.animations = 323 group.animations =
258 @[ transformAnimation, opacityAnimation, positionAnimation ]; 324 @[ opacityAnimation, positionAnimation, transformAnimation ];
259 group.timingFunction = [CAMediaTimingFunction 325 group.timingFunction = [CAMediaTimingFunction
260 functionWithName:TransformAnimationTimingFunction()]; 326 functionWithName:TransformAnimationTimingFunction()];
261 group.duration = duration; 327 group.duration = duration;
262 [group setValue:kPrimaryWindowAnimationID forKey:kAnimationIDKey]; 328 [group setValue:kPrimaryWindowAnimationID forKey:kAnimationIDKey];
263 group.delegate = self; 329 group.delegate = self;
264 330
265 [root addAnimation:group forKey:kPrimaryWindowAnimationID]; 331 [root addAnimation:group forKey:kPrimaryWindowAnimationID];
266 } 332 }
267 333
334 - (void)changePrimaryWindowToFinalFrame {
335 changingPrimaryWindowSize_ = YES;
336 [primaryWindow_ setFrame:finalFrame_ display:NO];
337 changingPrimaryWindowSize_ = NO;
338 }
339
268 - (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)flag { 340 - (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)flag {
269 NSString* animationID = [theAnimation valueForKey:kAnimationIDKey]; 341 NSString* animationID = [theAnimation valueForKey:kAnimationIDKey];
342
343 // Remove the snapshot window.
270 if ([animationID isEqual:kSnapshotWindowAnimationID]) { 344 if ([animationID isEqual:kSnapshotWindowAnimationID]) {
271 [snapshotWindow_ orderOut:nil]; 345 [snapshotWindow_ orderOut:nil];
272 snapshotWindow_.reset(); 346 snapshotWindow_.reset();
273 snapshotLayer_.reset(); 347 snapshotLayer_.reset();
274 return; 348 return;
275 } 349 }
276 350
277 if ([animationID isEqual:kPrimaryWindowAnimationID]) { 351 if ([animationID isEqual:kPrimaryWindowAnimationID]) {
278 [primaryWindow_ setOpaque:YES]; 352 // If we're exiting full screen, we want to set the primary window
353 // size to the expected frame at the end. The window's frame will also
354 // need to be unlocked.
355 if (!isEnteringFullscreen_) {
356 lock_->setLock(NO);
357 [primaryWindow_
358 setStyleMask:[primaryWindow_ styleMask] & ~NSFullScreenWindowMask];
359 [self changePrimaryWindowToFinalFrame];
360 }
361
362 // Check if the final content view size is correct
363 NSSize expectedSize = finalFrame_.size;
364 NSView* content = [primaryWindow_ contentView];
365 DCHECK_EQ(NSHeight(content.frame), expectedSize.height);
366 DCHECK_EQ(NSWidth(content.frame), expectedSize.width);
367
368 // Restore the state of the primary window and make it visible again.
369 [primaryWindow_ setOpaque:primaryWindowInitialOpaque_];
279 [primaryWindow_ setBackgroundColor:primaryWindowInitialBackgroundColor_]; 370 [primaryWindow_ setBackgroundColor:primaryWindowInitialBackgroundColor_];
371
280 CALayer* root = [self rootLayerOfWindow:primaryWindow_]; 372 CALayer* root = [self rootLayerOfWindow:primaryWindow_];
373 [root removeAnimationForKey:kPrimaryWindowAnimationID];
281 root.opacity = 1; 374 root.opacity = 1;
282 [root removeAnimationForKey:kPrimaryWindowAnimationID];
283 } 375 }
284 } 376 }
285 377
286 - (CALayer*)rootLayerOfWindow:(NSWindow*)window { 378 - (CALayer*)rootLayerOfWindow:(NSWindow*)window {
287 return [[[window contentView] superview] layer]; 379 return [[[window contentView] superview] layer];
288 } 380 }
289 381
290 @end 382 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698