fea80a8baa2b8c7f7e53dbf645227348b9400b3e
[WebKit-https.git] / Source / WebKit / mac / WebView / WebFullScreenController.mm
1 /*
2  * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #if ENABLE(FULLSCREEN_API)
27
28 #import "WebFullScreenController.h"
29
30 #import "WebNSWindowExtras.h"
31 #import "WebPreferencesPrivate.h"
32 #import "WebViewInternal.h"
33 #import <WebCore/Document.h>
34 #import <WebCore/Element.h>
35 #import <WebCore/FloatRect.h>
36 #import <WebCore/HTMLElement.h>
37 #import <WebCore/IntRect.h>
38 #import <WebCore/Page.h>
39 #import <WebCore/RenderLayer.h>
40 #import <WebCore/RenderLayerBacking.h>
41 #import <WebCore/RenderObject.h>
42 #import <WebCore/RenderView.h>
43 #import <WebCore/SoftLinking.h>
44 #import <WebCore/WebCoreFullScreenWindow.h>
45 #import <WebCore/WebWindowAnimation.h>
46 #import <WebKitSystemInterface.h>
47 #import <wtf/RetainPtr.h>
48 #import <wtf/UnusedParam.h>
49
50 using namespace WebCore;
51
52 static const CFTimeInterval defaultAnimationDuration = 0.5;
53
54 static IntRect screenRectOfContents(Element* element)
55 {
56     ASSERT(element);
57     if (element->renderer() && element->renderer()->hasLayer() && element->renderer()->enclosingLayer()->isComposited()) {
58         FloatQuad contentsBox = static_cast<FloatRect>(element->renderer()->enclosingLayer()->backing()->contentsBox());
59         contentsBox = element->renderer()->localToAbsoluteQuad(contentsBox);
60         return element->renderer()->view()->frameView()->contentsToScreen(contentsBox.enclosingBoundingBox());
61     }
62     return element->screenRect();
63 }
64
65 @interface WebFullScreenController(Private)<NSAnimationDelegate>
66 - (void)_updateMenuAndDockForFullScreen;
67 - (void)_swapView:(NSView*)view with:(NSView*)otherView;
68 - (Document*)_document;
69 - (void)_startEnterFullScreenAnimationWithDuration:(NSTimeInterval)duration;
70 - (void)_startExitFullScreenAnimationWithDuration:(NSTimeInterval)duration;
71 @end
72
73 #if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1060
74 @interface NSWindow(convertRectToScreenForLeopardAndSnowLeopard)
75 - (NSRect)convertRectToScreen:(NSRect)aRect;
76 @end
77
78 @implementation NSWindow(convertRectToScreenForLeopardAndSnowLeopard)
79 - (NSRect)convertRectToScreen:(NSRect)rect
80 {
81     NSRect frame = [self frame];
82     rect.origin.x += frame.origin.x;
83     rect.origin.y += frame.origin.y;
84     return rect;
85 }
86 @end
87 #endif
88
89 @interface NSWindow(IsOnActiveSpaceAdditionForTigerAndLeopard)
90 - (BOOL)isOnActiveSpace;
91 @end
92
93 @implementation WebFullScreenController
94
95 #pragma mark -
96 #pragma mark Initialization
97 - (id)init
98 {
99     // Do not defer window creation, to make sure -windowNumber is created (needed by WebWindowScaleAnimation).
100     NSWindow *window = [[WebCoreFullScreenWindow alloc] initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
101     self = [super initWithWindow:window];
102     [window release];
103     if (!self)
104         return nil;
105     [self windowDidLoad];
106
107     return self;
108 }
109
110 - (void)dealloc
111 {
112     [self setWebView:nil];
113
114     [NSObject cancelPreviousPerformRequestsWithTarget:self];
115     
116     [[NSNotificationCenter defaultCenter] removeObserver:self];
117     [super dealloc];
118 }
119
120 - (void)windowDidLoad
121 {
122     [super windowDidLoad];
123
124     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidResignActive:) name:NSApplicationDidResignActiveNotification object:NSApp];
125     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidChangeScreenParameters:) name:NSApplicationDidChangeScreenParametersNotification object:NSApp];
126 }
127
128 #pragma mark -
129 #pragma mark Accessors
130
131 - (WebView*)webView
132 {
133     return _webView;
134 }
135
136 - (void)setWebView:(WebView *)webView
137 {
138     [webView retain];
139     [_webView release];
140     _webView = webView;
141 }
142
143 - (Element*)element
144 {
145     return _element.get();
146 }
147
148 - (void)setElement:(PassRefPtr<Element>)element
149 {
150     _element = element;
151 }
152
153 - (BOOL)isFullScreen
154 {
155     return _isFullScreen;
156 }
157
158 #pragma mark -
159 #pragma mark NSWindowController overrides
160
161 - (void)cancelOperation:(id)sender
162 {
163     [self performSelector:@selector(requestExitFullScreen) withObject:nil afterDelay:0];
164 }
165
166 #pragma mark -
167 #pragma mark Notifications
168
169 - (void)applicationDidResignActive:(NSNotification*)notification
170 {   
171     // Check to see if the fullscreenWindow is on the active space; this function is available
172     // on 10.6 and later, so default to YES if the function is not available:
173     NSWindow* fullscreenWindow = [self window];
174     BOOL isOnActiveSpace = ([fullscreenWindow respondsToSelector:@selector(isOnActiveSpace)] ? [fullscreenWindow isOnActiveSpace] : YES);
175
176     // Replicate the QuickTime Player (X) behavior when losing active application status:
177     // Is the fullscreen screen the main screen? (Note: this covers the case where only a 
178     // single screen is available.)  Is the fullscreen screen on the current space? IFF so, 
179     // then exit fullscreen mode. 
180     if ([fullscreenWindow screen] == [[NSScreen screens] objectAtIndex:0] && isOnActiveSpace)
181          [self cancelOperation:self];
182 }
183
184 - (void)applicationDidChangeScreenParameters:(NSNotification*)notification
185 {
186     // The user may have changed the main screen by moving the menu bar, or they may have changed
187     // the Dock's size or location, or they may have changed the fullscreen screen's dimensions. 
188     // Update our presentation parameters, and ensure that the full screen window occupies the 
189     // entire screen:
190     [self _updateMenuAndDockForFullScreen];
191     NSWindow* window = [self window];
192     NSRect screenFrame = [[window screen] frame];
193     [window setFrame:screenFrame display:YES];
194     [_backgroundWindow.get() setFrame:screenFrame display:YES];
195 }
196
197 #pragma mark -
198 #pragma mark Exposed Interface
199
200 - (void)enterFullScreen:(NSScreen *)screen
201 {
202     if (_isFullScreen)
203         return;
204     _isFullScreen = YES;
205     
206     [self _updateMenuAndDockForFullScreen];   
207     
208     if (!screen)
209         screen = [NSScreen mainScreen];
210     NSRect screenFrame = [screen frame];
211     
212     NSRect webViewFrame = [[_webView window] convertRectToScreen:
213                            [_webView convertRect:[_webView frame] toView:nil]];
214     
215     // Flip coordinate system:
216     webViewFrame.origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - NSMaxY(webViewFrame);
217     
218     CGWindowID windowID = [[_webView window] windowNumber];
219     RetainPtr<CGImageRef> webViewContents = adoptCF(CGWindowListCreateImage(NSRectToCGRect(webViewFrame), kCGWindowListOptionIncludingWindow, windowID, kCGWindowImageShouldBeOpaque));
220     
221     // Screen updates to be re-enabled in beganEnterFullScreenWithInitialFrame:finalFrame:
222     NSDisableScreenUpdates();
223     [[self window] setAutodisplay:NO];
224     
225     NSResponder *webWindowFirstResponder = [[_webView window] firstResponder];
226     [[self window] setFrame:screenFrame display:NO];
227
228     _initialFrame = screenRectOfContents(_element.get());
229
230     // Swap the webView placeholder into place.
231     if (!_webViewPlaceholder) {
232         _webViewPlaceholder.adoptNS([[NSView alloc] init]);
233         [_webViewPlaceholder.get() setLayer:[CALayer layer]];
234         [_webViewPlaceholder.get() setWantsLayer:YES];
235     }
236     [[_webViewPlaceholder.get() layer] setContents:(id)webViewContents.get()];
237     [self _swapView:_webView with:_webViewPlaceholder.get()];
238     
239     // Then insert the WebView into the full screen window
240     NSView* contentView = [[self window] contentView];
241     [contentView addSubview:_webView positioned:NSWindowBelow relativeTo:nil];
242     [_webView setFrame:[contentView bounds]];
243     
244     [[self window] makeResponder:webWindowFirstResponder firstResponderIfDescendantOfView:_webView];
245     
246     [self _document]->webkitWillEnterFullScreenForElement(_element.get());
247     [self _document]->setAnimatingFullScreen(true);
248     [self _document]->updateLayout();
249
250     _finalFrame = screenRectOfContents(_element.get());
251     
252     [self _updateMenuAndDockForFullScreen];   
253     
254     [self _startEnterFullScreenAnimationWithDuration:defaultAnimationDuration];
255
256     _isEnteringFullScreen = true;
257 }
258
259 - (void)finishedEnterFullScreenAnimation:(bool)completed
260 {
261     if (!_isEnteringFullScreen)
262         return;
263     _isEnteringFullScreen = NO;
264     
265     if (completed) {
266         // Screen updates to be re-enabled at the end of this block
267         NSDisableScreenUpdates();
268         [self _document]->setAnimatingFullScreen(false);
269         [self _document]->webkitDidEnterFullScreenForElement(_element.get());
270         
271         NSRect windowBounds = [[self window] frame];
272         windowBounds.origin = NSZeroPoint;
273         WKWindowSetClipRect([self window], windowBounds);
274         
275         NSWindow *webWindow = [_webViewPlaceholder.get() window];
276 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
277         // In Lion, NSWindow will animate into and out of orderOut operations. Suppress that
278         // behavior here, making sure to reset the animation behavior afterward.
279         NSWindowAnimationBehavior animationBehavior = [webWindow animationBehavior];
280         [webWindow setAnimationBehavior:NSWindowAnimationBehaviorNone];
281 #endif
282         [webWindow orderOut:self];
283 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
284         [webWindow setAnimationBehavior:animationBehavior];
285 #endif
286         
287         [_fadeAnimation.get() stopAnimation];
288         [_fadeAnimation.get() setWindow:nil];
289         _fadeAnimation = nullptr;
290         
291         [_backgroundWindow.get() orderOut:self];
292         [_backgroundWindow.get() setFrame:NSZeroRect display:YES];
293         NSEnableScreenUpdates();
294     } else
295         [_scaleAnimation.get() stopAnimation];
296 }
297
298 - (void)requestExitFullScreen
299 {
300     if (!_element)
301         return;
302     _element->document()->webkitCancelFullScreen();
303 }
304
305 - (void)exitFullScreen
306 {
307     if (!_isFullScreen)
308         return;
309     _isFullScreen = NO;
310     
311     // Screen updates to be re-enabled in beganExitFullScreenWithInitialFrame:finalFrame:
312     NSDisableScreenUpdates();
313     [[self window] setAutodisplay:NO];
314
315     _finalFrame = screenRectOfContents(_element.get());
316
317     [self _document]->webkitWillExitFullScreenForElement(_element.get());
318     [self _document]->setAnimatingFullScreen(true);
319
320     if (_isEnteringFullScreen)
321         [self finishedEnterFullScreenAnimation:NO];
322     
323     [self _updateMenuAndDockForFullScreen];
324     
325     NSWindow* webWindow = [_webViewPlaceholder.get() window];
326 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
327     // In Lion, NSWindow will animate into and out of orderOut operations. Suppress that
328     // behavior here, making sure to reset the animation behavior afterward.
329     NSWindowAnimationBehavior animationBehavior = [webWindow animationBehavior];
330     [webWindow setAnimationBehavior:NSWindowAnimationBehaviorNone];
331 #endif
332     // If the user has moved the fullScreen window into a new space, temporarily change
333     // the collectionBehavior of the webView's window so that it is pulled into the active space:
334     if (!([webWindow respondsToSelector:@selector(isOnActiveSpace)] ? [webWindow isOnActiveSpace] : YES)) {
335         NSWindowCollectionBehavior behavior = [webWindow collectionBehavior];
336         [webWindow setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
337         [webWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]];
338         [webWindow setCollectionBehavior:behavior];
339     } else
340         [webWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]];
341 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
342     [webWindow setAnimationBehavior:animationBehavior];
343 #endif
344
345     [self _startExitFullScreenAnimationWithDuration:defaultAnimationDuration];
346     _isExitingFullScreen = YES;    
347 }
348
349 - (void)finishedExitFullScreenAnimation:(bool)completed
350 {
351     if (!_isExitingFullScreen)
352         return;
353     _isExitingFullScreen = NO;
354     
355     [self _updateMenuAndDockForFullScreen];
356     
357     // Screen updates to be re-enabled at the end of this function
358     NSDisableScreenUpdates();
359     
360     [self _document]->setAnimatingFullScreen(false);
361     [self _document]->webkitDidExitFullScreenForElement(_element.get());
362     
363     NSResponder *firstResponder = [[self window] firstResponder];
364     [self _swapView:_webViewPlaceholder.get() with:_webView];
365     [[_webView window] makeResponder:firstResponder firstResponderIfDescendantOfView:_webView];
366     
367     NSRect windowBounds = [[self window] frame];
368     windowBounds.origin = NSZeroPoint;
369     WKWindowSetClipRect([self window], windowBounds);
370     
371     [[self window] orderOut:self];
372     [[self window] setFrame:NSZeroRect display:YES];
373     
374     [_fadeAnimation.get() stopAnimation];
375     [_fadeAnimation.get() setWindow:nil];
376     _fadeAnimation = nullptr;
377     
378     [_backgroundWindow.get() orderOut:self];
379     [_backgroundWindow.get() setFrame:NSZeroRect display:YES];
380
381     [[_webView window] makeKeyAndOrderFront:self];
382
383     NSEnableScreenUpdates();
384 }
385
386 - (void)close
387 {
388     // We are being asked to close rapidly, most likely because the page 
389     // has closed or the web process has crashed.  Just walk through our
390     // normal exit full screen sequence, but don't wait to be called back
391     // in response.
392     if (_isFullScreen)
393         [self exitFullScreen];
394     
395     if (_isExitingFullScreen)
396         [self finishedExitFullScreenAnimation:YES];
397     
398     [super close];
399 }
400
401 #pragma mark -
402 #pragma mark NSAnimation delegate
403
404 - (void)animationDidEnd:(NSAnimation*)animation
405 {
406     if (_isFullScreen)
407         [self finishedEnterFullScreenAnimation:YES];
408     else
409         [self finishedExitFullScreenAnimation:YES];
410 }
411
412 #pragma mark -
413 #pragma mark Internal Interface
414
415 - (void)_updateMenuAndDockForFullScreen
416 {
417     // NSApplicationPresentationOptions is available on > 10.6 only:
418 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
419     NSApplicationPresentationOptions options = NSApplicationPresentationDefault;
420     NSScreen* fullscreenScreen = [[self window] screen];
421     
422     if (_isFullScreen) {
423         // Auto-hide the menu bar if the fullscreenScreen contains the menu bar:
424         // NOTE: if the fullscreenScreen contains the menu bar but not the dock, we must still 
425         // auto-hide the dock, or an exception will be thrown.
426         if ([[NSScreen screens] objectAtIndex:0] == fullscreenScreen)
427             options |= (NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock);
428         // Check if the current screen contains the dock by comparing the screen's frame to its
429         // visibleFrame; if a dock is present, the visibleFrame will differ. If the current screen
430         // contains the dock, hide it.
431         else if (!NSEqualRects([fullscreenScreen frame], [fullscreenScreen visibleFrame]))
432             options |= NSApplicationPresentationAutoHideDock;
433     }
434     
435     if ([NSApp respondsToSelector:@selector(setPresentationOptions:)])
436         [NSApp setPresentationOptions:options];
437     else
438 #endif
439         SetSystemUIMode(_isFullScreen ? kUIModeAllHidden : kUIModeNormal, 0);
440 }
441
442 #pragma mark -
443 #pragma mark Utility Functions
444
445 - (Document*)_document 
446 {
447     return _element->document();
448 }
449
450 - (void)_swapView:(NSView*)view with:(NSView*)otherView
451 {
452     [CATransaction begin];
453     [CATransaction setDisableActions:YES];
454     [otherView setFrame:[view frame]];        
455     [otherView setAutoresizingMask:[view autoresizingMask]];
456     [otherView removeFromSuperview];
457     [[view superview] addSubview:otherView positioned:NSWindowAbove relativeTo:view];
458     [view removeFromSuperview];
459     [CATransaction commit];
460 }
461
462 static RetainPtr<NSWindow> createBackgroundFullscreenWindow(NSRect frame)
463 {
464     NSWindow *window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
465     [window setOpaque:YES];
466     [window setBackgroundColor:[NSColor blackColor]];
467     [window setReleasedWhenClosed:NO];
468     return adoptNS(window);
469 }
470
471 static NSRect windowFrameFromApparentFrames(NSRect screenFrame, NSRect initialFrame, NSRect finalFrame)
472 {
473     NSRect initialWindowFrame;
474     if (!NSWidth(initialFrame) || !NSWidth(finalFrame) || !NSHeight(initialFrame) || !NSHeight(finalFrame))
475         return screenFrame;
476
477     CGFloat xScale = NSWidth(screenFrame) / NSWidth(finalFrame);
478     CGFloat yScale = NSHeight(screenFrame) / NSHeight(finalFrame);
479     CGFloat xTrans = NSMinX(screenFrame) - NSMinX(finalFrame);
480     CGFloat yTrans = NSMinY(screenFrame) - NSMinY(finalFrame);
481     initialWindowFrame.size = NSMakeSize(NSWidth(initialFrame) * xScale, NSHeight(initialFrame) * yScale);
482     initialWindowFrame.origin = NSMakePoint
483     ( NSMinX(initialFrame) + xTrans / (NSWidth(finalFrame) / NSWidth(initialFrame))
484      , NSMinY(initialFrame) + yTrans / (NSHeight(finalFrame) / NSHeight(initialFrame)));
485     return initialWindowFrame;
486 }
487
488 - (void)_startEnterFullScreenAnimationWithDuration:(NSTimeInterval)duration
489 {
490     NSRect screenFrame = [[[self window] screen] frame];
491     NSRect initialWindowFrame = windowFrameFromApparentFrames(screenFrame, _initialFrame, _finalFrame);
492     
493     _scaleAnimation = adoptNS([[WebWindowScaleAnimation alloc] initWithHintedDuration:duration window:[self window] initalFrame:initialWindowFrame finalFrame:screenFrame]);
494     
495     [_scaleAnimation.get() setAnimationBlockingMode:NSAnimationNonblocking];
496     [_scaleAnimation.get() setDelegate:self];
497     [_scaleAnimation.get() setCurrentProgress:0];
498     [_scaleAnimation.get() startAnimation];
499     
500     // WKWindowSetClipRect takes window coordinates, so convert from screen coordinates here:
501     NSRect finalBounds = _finalFrame;
502     finalBounds.origin = [[self window] convertScreenToBase:finalBounds.origin];
503     WKWindowSetClipRect([self window], finalBounds);
504     
505     [[self window] makeKeyAndOrderFront:self];
506     
507     if (!_backgroundWindow)
508         _backgroundWindow = createBackgroundFullscreenWindow(screenFrame);
509     else
510         [_backgroundWindow.get() setFrame:screenFrame display:NO];
511     
512     CGFloat currentAlpha = 0;
513     if (_fadeAnimation) {
514         currentAlpha = [_fadeAnimation.get() currentAlpha];
515         [_fadeAnimation.get() stopAnimation];
516         [_fadeAnimation.get() setWindow:nil];
517     }
518     
519     _fadeAnimation = adoptNS([[WebWindowFadeAnimation alloc] initWithDuration:duration 
520                                                                        window:_backgroundWindow.get() 
521                                                                  initialAlpha:currentAlpha 
522                                                                    finalAlpha:1]);
523     [_fadeAnimation.get() setAnimationBlockingMode:NSAnimationNonblocking];
524     [_fadeAnimation.get() setCurrentProgress:0];
525     [_fadeAnimation.get() startAnimation];
526     
527     [_backgroundWindow.get() orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]];
528     
529     [[self window] setAutodisplay:YES];
530     [[self window] displayIfNeeded];
531     // Screen updates disabled in enterFullScreen:
532     NSEnableScreenUpdates();
533 }
534
535 - (void)_startExitFullScreenAnimationWithDuration:(NSTimeInterval)duration
536 {
537     NSRect screenFrame = [[[self window] screen] frame];
538     NSRect initialWindowFrame = windowFrameFromApparentFrames(screenFrame, _initialFrame, _finalFrame);
539     
540     NSRect currentFrame = _scaleAnimation ? [_scaleAnimation.get() currentFrame] : [[self window] frame];
541     _scaleAnimation = adoptNS([[WebWindowScaleAnimation alloc] initWithHintedDuration:duration window:[self window] initalFrame:currentFrame finalFrame:initialWindowFrame]);
542     
543     [_scaleAnimation.get() setAnimationBlockingMode:NSAnimationNonblocking];
544     [_scaleAnimation.get() setDelegate:self];
545     [_scaleAnimation.get() setCurrentProgress:0];
546     [_scaleAnimation.get() startAnimation];
547     
548     if (!_backgroundWindow)
549         _backgroundWindow = createBackgroundFullscreenWindow(screenFrame);
550     else
551         [_backgroundWindow.get() setFrame:screenFrame display:NO];
552     
553     CGFloat currentAlpha = 1;
554     if (_fadeAnimation) {
555         currentAlpha = [_fadeAnimation.get() currentAlpha];
556         [_fadeAnimation.get() stopAnimation];
557         [_fadeAnimation.get() setWindow:nil];
558     }
559     _fadeAnimation = adoptNS([[WebWindowFadeAnimation alloc] initWithDuration:duration 
560                                                                        window:_backgroundWindow.get() 
561                                                                  initialAlpha:currentAlpha 
562                                                                    finalAlpha:0]);
563     [_fadeAnimation.get() setAnimationBlockingMode:NSAnimationNonblocking];
564     [_fadeAnimation.get() setCurrentProgress:0];
565     [_fadeAnimation.get() startAnimation];
566     
567     [_backgroundWindow.get() orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]];
568     
569     // WKWindowSetClipRect takes window coordinates, so convert from screen coordinates here:
570     NSRect finalBounds = _finalFrame;
571     finalBounds.origin = [[self window] convertScreenToBase:finalBounds.origin];
572     WKWindowSetClipRect([self window], finalBounds);
573     
574     [[self window] setAutodisplay:YES];
575     [[self window] displayIfNeeded];
576
577     // Screen updates disabled in exitFullScreen:
578     NSEnableScreenUpdates();
579 }
580
581 @end
582
583
584 #endif /* ENABLE(FULLSCREEN_API) */