1/* 2 * Copyright (C) 2009, 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#import "config.h" 27 28#if ENABLE(FULLSCREEN_API) && !PLATFORM(IOS) 29 30#import "WKFullScreenWindowController.h" 31 32#import "LayerTreeContext.h" 33#import "WKAPICast.h" 34#import "WKViewInternal.h" 35#import "WKViewPrivate.h" 36#import "WebFullScreenManagerProxy.h" 37#import "WebPageProxy.h" 38#import <QuartzCore/QuartzCore.h> 39#import <WebCore/DisplaySleepDisabler.h> 40#import <WebCore/FloatRect.h> 41#import <WebCore/IntRect.h> 42#import <WebCore/LocalizedStrings.h> 43#import <WebCore/WebCoreFullScreenPlaceholderView.h> 44#import <WebCore/WebCoreFullScreenWindow.h> 45#import <WebCore/WebWindowAnimation.h> 46#import <WebKitSystemInterface.h> 47 48using namespace WebKit; 49using namespace WebCore; 50 51static RetainPtr<NSWindow> createBackgroundFullscreenWindow(NSRect frame); 52 53static const NSTimeInterval DefaultWatchdogTimerInterval = 1; 54 55enum FullScreenState : NSInteger { 56 NotInFullScreen, 57 WaitingToEnterFullScreen, 58 EnteringFullScreen, 59 InFullScreen, 60 WaitingToExitFullScreen, 61 ExitingFullScreen, 62}; 63 64@interface NSWindow (WebNSWindowDetails) 65- (void)exitFullScreenMode:(id)sender; 66- (void)enterFullScreenMode:(id)sender; 67@end 68 69@interface WKFullScreenWindowController(Private)<NSAnimationDelegate> 70- (void)_replaceView:(NSView*)view with:(NSView*)otherView; 71- (WebPageProxy*)_page; 72- (WebFullScreenManagerProxy*)_manager; 73- (void)_startEnterFullScreenAnimationWithDuration:(NSTimeInterval)duration; 74- (void)_startExitFullScreenAnimationWithDuration:(NSTimeInterval)duration; 75@end 76 77static NSRect convertRectToScreen(NSWindow *window, NSRect rect) 78{ 79 return [window convertRectToScreen:rect]; 80} 81 82static void makeResponderFirstResponderIfDescendantOfView(NSWindow *window, NSResponder *responder, NSView *view) 83{ 84 if ([responder isKindOfClass:[NSView class]] && [(NSView *)responder isDescendantOf:view]) 85 [window makeFirstResponder:responder]; 86} 87 88@implementation WKFullScreenWindowController 89 90#pragma mark - 91#pragma mark Initialization 92- (id)initWithWindow:(NSWindow *)window webView:(WKView *)webView 93{ 94 self = [super initWithWindow:window]; 95 if (!self) 96 return nil; 97 [window setDelegate:self]; 98 [window setCollectionBehavior:([window collectionBehavior] | NSWindowCollectionBehaviorFullScreenPrimary)]; 99 [self windowDidLoad]; 100 _webView = webView; 101 102 return self; 103} 104 105- (void)dealloc 106{ 107 [[self window] setDelegate:nil]; 108 109 [NSObject cancelPreviousPerformRequestsWithTarget:self]; 110 111 [[NSNotificationCenter defaultCenter] removeObserver:self]; 112 113 if (_repaintCallback) { 114 _repaintCallback->invalidate(CallbackBase::Error::OwnerWasInvalidated); 115 // invalidate() calls completeFinishExitFullScreenAnimationAfterRepaint, which 116 // clears _repaintCallback. 117 ASSERT(!_repaintCallback); 118 } 119 120 [super dealloc]; 121} 122 123- (void)windowDidLoad 124{ 125 [super windowDidLoad]; 126 127 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidChangeScreenParameters:) name:NSApplicationDidChangeScreenParametersNotification object:NSApp]; 128} 129 130#pragma mark - 131#pragma mark Accessors 132 133- (BOOL)isFullScreen 134{ 135 return _fullScreenState == WaitingToEnterFullScreen 136 || _fullScreenState == EnteringFullScreen 137 || _fullScreenState == InFullScreen; 138} 139 140- (WebCoreFullScreenPlaceholderView*)webViewPlaceholder 141{ 142 return _webViewPlaceholder.get(); 143} 144 145#pragma mark - 146#pragma mark NSWindowController overrides 147 148- (void)cancelOperation:(id)sender 149{ 150 // If the page doesn't respond in DefaultWatchdogTimerInterval seconds, it could be because 151 // the WebProcess has hung, so exit anyway. 152 if (!_watchdogTimer) { 153 [self _manager]->requestExitFullScreen(); 154 _watchdogTimer = adoptNS([[NSTimer alloc] initWithFireDate:nil interval:DefaultWatchdogTimerInterval target:self selector:@selector(exitFullScreen) userInfo:nil repeats:NO]); 155 [[NSRunLoop mainRunLoop] addTimer:_watchdogTimer.get() forMode:NSDefaultRunLoopMode]; 156 } 157} 158 159#pragma mark - 160#pragma mark Notifications 161 162- (void)applicationDidChangeScreenParameters:(NSNotification*)notification 163{ 164 // The user may have changed the main screen by moving the menu bar, or they may have changed 165 // the Dock's size or location, or they may have changed the fullScreen screen's dimensions. 166 // Update our presentation parameters, and ensure that the full screen window occupies the 167 // entire screen: 168 NSWindow* window = [self window]; 169 NSRect screenFrame = [[window screen] frame]; 170 [window setFrame:screenFrame display:YES]; 171 [_backgroundWindow setFrame:screenFrame display:YES]; 172} 173 174#pragma mark - 175#pragma mark Exposed Interface 176 177static RetainPtr<CGDataProviderRef> createImageProviderWithCopiedData(CGDataProviderRef sourceProvider) 178{ 179 RetainPtr<CFDataRef> data = adoptCF(CGDataProviderCopyData(sourceProvider)); 180 return adoptCF(CGDataProviderCreateWithCFData(data.get())); 181} 182 183static RetainPtr<CGImageRef> createImageWithCopiedData(CGImageRef sourceImage) 184{ 185 size_t width = CGImageGetWidth(sourceImage); 186 size_t height = CGImageGetHeight(sourceImage); 187 size_t bitsPerComponent = CGImageGetBitsPerComponent(sourceImage); 188 size_t bitsPerPixel = CGImageGetBitsPerPixel(sourceImage); 189 size_t bytesPerRow = CGImageGetBytesPerRow(sourceImage); 190 CGColorSpaceRef colorSpace = CGImageGetColorSpace(sourceImage); 191 CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(sourceImage); 192 RetainPtr<CGDataProviderRef> provider = createImageProviderWithCopiedData(CGImageGetDataProvider(sourceImage)); 193 bool shouldInterpolate = CGImageGetShouldInterpolate(sourceImage); 194 CGColorRenderingIntent intent = CGImageGetRenderingIntent(sourceImage); 195 196 return adoptCF(CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, bitmapInfo, provider.get(), 0, shouldInterpolate, intent)); 197} 198 199- (void)enterFullScreen:(NSScreen *)screen 200{ 201 if ([self isFullScreen]) 202 return; 203 _fullScreenState = WaitingToEnterFullScreen; 204 205 if (!screen) 206 screen = [NSScreen mainScreen]; 207 NSRect screenFrame = [screen frame]; 208 209 NSRect webViewFrame = convertRectToScreen([_webView window], [_webView convertRect:[_webView frame] toView:nil]); 210 211 // Flip coordinate system: 212 webViewFrame.origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - NSMaxY(webViewFrame); 213 214 CGWindowID windowID = [[_webView window] windowNumber]; 215 RetainPtr<CGImageRef> webViewContents = adoptCF(CGWindowListCreateImage(NSRectToCGRect(webViewFrame), kCGWindowListOptionIncludingWindow, windowID, kCGWindowImageShouldBeOpaque)); 216 217 // Using the returned CGImage directly would result in calls to the WindowServer every time 218 // the image was painted. Instead, copy the image data into our own process to eliminate that 219 // future overhead. 220 webViewContents = createImageWithCopiedData(webViewContents.get()); 221 222 // Screen updates to be re-enabled in _startEnterFullScreenAnimationWithDuration: 223 NSDisableScreenUpdates(); 224 [[self window] setAutodisplay:NO]; 225 226 NSResponder *webWindowFirstResponder = [[_webView window] firstResponder]; 227 [self _manager]->saveScrollPosition(); 228 [[self window] setFrame:screenFrame display:NO]; 229 230 // Painting is normally suspended when the WKView is removed from the window, but this is 231 // unnecessary in the full-screen animation case, and can cause bugs; see 232 // https://bugs.webkit.org/show_bug.cgi?id=88940 and https://bugs.webkit.org/show_bug.cgi?id=88374 233 // We will resume the normal behavior in _startEnterFullScreenAnimationWithDuration: 234 [_webView _setSuppressVisibilityUpdates:YES]; 235 236 // Swap the webView placeholder into place. 237 if (!_webViewPlaceholder) { 238 _webViewPlaceholder = adoptNS([[WebCoreFullScreenPlaceholderView alloc] initWithFrame:[_webView frame]]); 239 [_webViewPlaceholder setAction:@selector(cancelOperation:)]; 240 } 241 [_webViewPlaceholder setTarget:nil]; 242 [_webViewPlaceholder setContents:(id)webViewContents.get()]; 243 [self _replaceView:_webView with:_webViewPlaceholder.get()]; 244 245 // Then insert the WebView into the full screen window 246 NSView* contentView = [[self window] contentView]; 247 [contentView addSubview:_webView positioned:NSWindowBelow relativeTo:nil]; 248 [_webView setFrame:[contentView bounds]]; 249 250 makeResponderFirstResponderIfDescendantOfView(self.window, webWindowFirstResponder, _webView); 251 252 [self _manager]->setAnimatingFullScreen(true); 253 [self _manager]->willEnterFullScreen(); 254 _savedScale = [self _page]->pageScaleFactor(); 255 [self _page]->scalePage(1, IntPoint()); 256} 257 258- (void)beganEnterFullScreenWithInitialFrame:(const WebCore::IntRect&)initialFrame finalFrame:(const WebCore::IntRect&)finalFrame 259{ 260 if (_fullScreenState != WaitingToEnterFullScreen) 261 return; 262 _fullScreenState = EnteringFullScreen; 263 264 _initialFrame = initialFrame; 265 _finalFrame = finalFrame; 266 267 if (!_backgroundWindow) 268 _backgroundWindow = createBackgroundFullscreenWindow(NSZeroRect); 269 270 [self.window orderBack: self]; // Make sure the full screen window is part of the correct Space. 271 [[self window] enterFullScreenMode:self]; 272} 273 274- (void)finishedEnterFullScreenAnimation:(bool)completed 275{ 276 if (_fullScreenState != EnteringFullScreen) 277 return; 278 279 if (completed) { 280 _fullScreenState = InFullScreen; 281 282 // Screen updates to be re-enabled ta the end of the current block. 283 NSDisableScreenUpdates(); 284 [self _manager]->didEnterFullScreen(); 285 [self _manager]->setAnimatingFullScreen(false); 286 287 NSRect windowBounds = [[self window] frame]; 288 windowBounds.origin = NSZeroPoint; 289 WKWindowSetClipRect([self window], windowBounds); 290 291 [_fadeAnimation stopAnimation]; 292 [_fadeAnimation setWindow:nil]; 293 _fadeAnimation = nullptr; 294 295 [_backgroundWindow orderOut:self]; 296 [_backgroundWindow setFrame:NSZeroRect display:YES]; 297 298 [_webViewPlaceholder setExitWarningVisible:YES]; 299 [_webViewPlaceholder setTarget:self]; 300 } else { 301 // Transition to fullscreen failed. Clean up. 302 _fullScreenState = NotInFullScreen; 303 304 [_scaleAnimation stopAnimation]; 305 306 [_backgroundWindow orderOut:self]; 307 [_backgroundWindow setFrame:NSZeroRect display:YES]; 308 309 [[self window] setAutodisplay:YES]; 310 [_webView _setSuppressVisibilityUpdates:NO]; 311 312 NSResponder *firstResponder = [[self window] firstResponder]; 313 [self _replaceView:_webViewPlaceholder.get() with:_webView]; 314 makeResponderFirstResponderIfDescendantOfView(_webView.window, firstResponder, _webView); 315 [[_webView window] makeKeyAndOrderFront:self]; 316 317 [self _manager]->didExitFullScreen(); 318 [self _manager]->setAnimatingFullScreen(false); 319 [self _page]->scalePage(_savedScale, IntPoint()); 320 [self _manager]->restoreScrollPosition(); 321 } 322 323 NSEnableScreenUpdates(); 324} 325 326- (void)exitFullScreen 327{ 328 if (_watchdogTimer) { 329 [_watchdogTimer invalidate]; 330 _watchdogTimer.clear(); 331 } 332 333 if (![self isFullScreen]) 334 return; 335 _fullScreenState = WaitingToExitFullScreen; 336 337 [_webViewPlaceholder setExitWarningVisible:NO]; 338 339 // Screen updates to be re-enabled in _startExitFullScreenAnimationWithDuration: or beganExitFullScreenWithInitialFrame:finalFrame: 340 NSDisableScreenUpdates(); 341 [[self window] setAutodisplay:NO]; 342 343 // See the related comment in enterFullScreen: 344 // We will resume the normal behavior in _startExitFullScreenAnimationWithDuration: 345 [_webView _setSuppressVisibilityUpdates:YES]; 346 [_webViewPlaceholder setTarget:nil]; 347 348 [self _manager]->setAnimatingFullScreen(true); 349 [self _manager]->willExitFullScreen(); 350} 351 352- (void)beganExitFullScreenWithInitialFrame:(const WebCore::IntRect&)initialFrame finalFrame:(const WebCore::IntRect&)finalFrame 353{ 354 if (_fullScreenState != WaitingToExitFullScreen) 355 return; 356 _fullScreenState = ExitingFullScreen; 357 358 if (![[self window] isOnActiveSpace]) { 359 // If the full screen window is not in the active space, the NSWindow full screen animation delegate methods 360 // will never be called. So call finishedExitFullScreenAnimation explicitly. 361 [self finishedExitFullScreenAnimation:YES]; 362 363 // Because we are breaking the normal animation pattern, re-enable screen updates 364 // as exitFullScreen has disabled them, but _startExitFullScreenAnimationWithDuration: 365 // will never be called. 366 NSEnableScreenUpdates(); 367 } 368 369 [[self window] exitFullScreenMode:self]; 370} 371 372- (void)finishedExitFullScreenAnimation:(bool)completed 373{ 374 if (_fullScreenState != ExitingFullScreen) 375 return; 376 _fullScreenState = NotInFullScreen; 377 378 // Screen updates to be re-enabled in completeFinishExitFullScreenAnimationAfterRepaint. 379 NSDisableScreenUpdates(); 380 [[_webViewPlaceholder window] setAutodisplay:NO]; 381 382 NSResponder *firstResponder = [[self window] firstResponder]; 383 [self _replaceView:_webViewPlaceholder.get() with:_webView]; 384 makeResponderFirstResponderIfDescendantOfView(_webView.window, firstResponder, _webView); 385 386 NSRect windowBounds = [[self window] frame]; 387 windowBounds.origin = NSZeroPoint; 388 WKWindowSetClipRect([self window], windowBounds); 389 390 [[self window] orderOut:self]; 391 [[self window] setFrame:NSZeroRect display:YES]; 392 393 [_scaleAnimation stopAnimation]; 394 [_scaleAnimation setWindow:nil]; 395 _scaleAnimation = nullptr; 396 397 [_fadeAnimation stopAnimation]; 398 [_fadeAnimation setWindow:nil]; 399 _fadeAnimation = nullptr; 400 401 [_backgroundWindow orderOut:self]; 402 [_backgroundWindow setFrame:NSZeroRect display:YES]; 403 404 [[_webView window] makeKeyAndOrderFront:self]; 405 406 // These messages must be sent after the swap or flashing will occur during forceRepaint: 407 [self _manager]->didExitFullScreen(); 408 [self _manager]->setAnimatingFullScreen(false); 409 [self _page]->scalePage(_savedScale, IntPoint()); 410 [self _manager]->restoreScrollPosition(); 411 412 if (_repaintCallback) { 413 _repaintCallback->invalidate(CallbackBase::Error::OwnerWasInvalidated); 414 // invalidate() calls completeFinishExitFullScreenAnimationAfterRepaint, which 415 // clears _repaintCallback. 416 ASSERT(!_repaintCallback); 417 } 418 _repaintCallback = VoidCallback::create([self](CallbackBase::Error) { 419 [self completeFinishExitFullScreenAnimationAfterRepaint]; 420 }); 421 [self _page]->forceRepaint(_repaintCallback); 422} 423 424- (void)completeFinishExitFullScreenAnimationAfterRepaint 425{ 426 _repaintCallback = nullptr; 427 [[_webView window] setAutodisplay:YES]; 428 [[_webView window] displayIfNeeded]; 429 NSEnableScreenUpdates(); 430} 431 432- (void)performClose:(id)sender 433{ 434 if ([self isFullScreen]) 435 [self cancelOperation:sender]; 436} 437 438- (void)close 439{ 440 // We are being asked to close rapidly, most likely because the page 441 // has closed or the web process has crashed. Just walk through our 442 // normal exit full screen sequence, but don't wait to be called back 443 // in response. 444 if ([self isFullScreen]) 445 [self exitFullScreen]; 446 447 if (_fullScreenState == ExitingFullScreen) 448 [self finishedExitFullScreenAnimation:YES]; 449 450 [_scaleAnimation stopAnimation]; 451 [_scaleAnimation setWindow:nil]; 452 [_fadeAnimation stopAnimation]; 453 [_fadeAnimation setWindow:nil]; 454 455 _webView = nil; 456 457 [super close]; 458} 459 460#pragma mark - 461#pragma mark Custom NSWindow Full Screen Animation 462 463- (NSArray *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window 464{ 465 return [NSArray arrayWithObjects:[self window], _backgroundWindow.get(), nil]; 466} 467 468- (NSArray *)customWindowsToExitFullScreenForWindow:(NSWindow *)window 469{ 470 return [NSArray arrayWithObjects:[self window], _backgroundWindow.get(), nil]; 471} 472 473- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration 474{ 475 [self _startEnterFullScreenAnimationWithDuration:duration]; 476} 477 478- (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration 479{ 480 [self _startExitFullScreenAnimationWithDuration:duration]; 481} 482 483- (void)windowDidFailToEnterFullScreen:(NSWindow *)window 484{ 485 [self finishedEnterFullScreenAnimation:NO]; 486} 487 488- (void)windowDidEnterFullScreen:(NSNotification*)notification 489{ 490 [self finishedEnterFullScreenAnimation:YES]; 491} 492 493- (void)windowDidFailToExitFullScreen:(NSWindow *)window 494{ 495 [self finishedExitFullScreenAnimation:NO]; 496} 497 498- (void)windowDidExitFullScreen:(NSNotification*)notification 499{ 500 [self finishedExitFullScreenAnimation:YES]; 501} 502 503#pragma mark - 504#pragma mark Internal Interface 505 506- (WebPageProxy*)_page 507{ 508 return toImpl([_webView pageRef]); 509} 510 511- (WebFullScreenManagerProxy*)_manager 512{ 513 WebPageProxy* webPage = [self _page]; 514 if (!webPage) 515 return 0; 516 return webPage->fullScreenManager(); 517} 518 519- (void)_replaceView:(NSView*)view with:(NSView*)otherView 520{ 521 [CATransaction begin]; 522 [CATransaction setDisableActions:YES]; 523 [otherView setFrame:[view frame]]; 524 [otherView setAutoresizingMask:[view autoresizingMask]]; 525 [otherView removeFromSuperview]; 526 [[view superview] addSubview:otherView positioned:NSWindowAbove relativeTo:view]; 527 [view removeFromSuperview]; 528 [CATransaction commit]; 529} 530 531static RetainPtr<NSWindow> createBackgroundFullscreenWindow(NSRect frame) 532{ 533 NSWindow *window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; 534 [window setOpaque:YES]; 535 [window setBackgroundColor:[NSColor blackColor]]; 536 [window setReleasedWhenClosed:NO]; 537 return adoptNS(window); 538} 539 540static NSRect windowFrameFromApparentFrames(NSRect screenFrame, NSRect initialFrame, NSRect finalFrame) 541{ 542 NSRect initialWindowFrame; 543 if (!NSWidth(initialFrame) || !NSWidth(finalFrame) || !NSHeight(initialFrame) || !NSHeight(finalFrame)) 544 return screenFrame; 545 546 CGFloat xScale = NSWidth(screenFrame) / NSWidth(finalFrame); 547 CGFloat yScale = NSHeight(screenFrame) / NSHeight(finalFrame); 548 CGFloat xTrans = NSMinX(screenFrame) - NSMinX(finalFrame); 549 CGFloat yTrans = NSMinY(screenFrame) - NSMinY(finalFrame); 550 initialWindowFrame.size = NSMakeSize(NSWidth(initialFrame) * xScale, NSHeight(initialFrame) * yScale); 551 initialWindowFrame.origin = NSMakePoint 552 ( NSMinX(initialFrame) + xTrans / (NSWidth(finalFrame) / NSWidth(initialFrame)) 553 , NSMinY(initialFrame) + yTrans / (NSHeight(finalFrame) / NSHeight(initialFrame))); 554 return initialWindowFrame; 555} 556 557- (void)_startEnterFullScreenAnimationWithDuration:(NSTimeInterval)duration 558{ 559 NSRect screenFrame = [[[self window] screen] frame]; 560 NSRect initialWindowFrame = windowFrameFromApparentFrames(screenFrame, _initialFrame, _finalFrame); 561 562 _scaleAnimation = adoptNS([[WebWindowScaleAnimation alloc] initWithHintedDuration:duration window:[self window] initalFrame:initialWindowFrame finalFrame:screenFrame]); 563 564 [_scaleAnimation setAnimationBlockingMode:NSAnimationNonblocking]; 565 [_scaleAnimation setCurrentProgress:0]; 566 [_scaleAnimation startAnimation]; 567 568 // WKWindowSetClipRect takes window coordinates, so convert from screen coordinates here: 569 NSRect finalBounds = _finalFrame; 570#pragma clang diagnostic push 571#pragma clang diagnostic ignored "-Wdeprecated-declarations" 572 finalBounds.origin = [[self window] convertScreenToBase:finalBounds.origin]; 573#pragma clang diagnostic pop 574 WKWindowSetClipRect([self window], finalBounds); 575 576 NSWindow* window = [self window]; 577 NSWindowCollectionBehavior behavior = [window collectionBehavior]; 578 [window setCollectionBehavior:(behavior | NSWindowCollectionBehaviorCanJoinAllSpaces)]; 579 [window makeKeyAndOrderFront:self]; 580 [window setCollectionBehavior:behavior]; 581 582 583 if (!_backgroundWindow) 584 _backgroundWindow = createBackgroundFullscreenWindow(screenFrame); 585 else 586 [_backgroundWindow setFrame:screenFrame display:NO]; 587 588 CGFloat currentAlpha = 0; 589 if (_fadeAnimation) { 590 currentAlpha = [_fadeAnimation currentAlpha]; 591 [_fadeAnimation stopAnimation]; 592 [_fadeAnimation setWindow:nil]; 593 } 594 595 _fadeAnimation = adoptNS([[WebWindowFadeAnimation alloc] initWithDuration:duration 596 window:_backgroundWindow.get() 597 initialAlpha:currentAlpha 598 finalAlpha:1]); 599 [_fadeAnimation setAnimationBlockingMode:NSAnimationNonblocking]; 600 [_fadeAnimation setCurrentProgress:0]; 601 [_fadeAnimation startAnimation]; 602 603 [_backgroundWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]]; 604 605 [_webView _setSuppressVisibilityUpdates:NO]; 606 [[self window] setAutodisplay:YES]; 607 [[self window] displayIfNeeded]; 608 NSEnableScreenUpdates(); 609} 610 611- (void)_startExitFullScreenAnimationWithDuration:(NSTimeInterval)duration 612{ 613 if ([self isFullScreen]) { 614 // We still believe we're in full screen mode, so we must have been asked to exit full 615 // screen by the system full screen button. 616 [self _manager]->requestExitFullScreen(); 617 [self exitFullScreen]; 618 _fullScreenState = ExitingFullScreen; 619 } 620 621 NSRect screenFrame = [[[self window] screen] frame]; 622 NSRect initialWindowFrame = windowFrameFromApparentFrames(screenFrame, _initialFrame, _finalFrame); 623 624 NSRect currentFrame = _scaleAnimation ? [_scaleAnimation currentFrame] : [[self window] frame]; 625 _scaleAnimation = adoptNS([[WebWindowScaleAnimation alloc] initWithHintedDuration:duration window:[self window] initalFrame:currentFrame finalFrame:initialWindowFrame]); 626 627 [_scaleAnimation setAnimationBlockingMode:NSAnimationNonblocking]; 628 [_scaleAnimation setCurrentProgress:0]; 629 [_scaleAnimation startAnimation]; 630 631 if (!_backgroundWindow) 632 _backgroundWindow = createBackgroundFullscreenWindow(screenFrame); 633 else 634 [_backgroundWindow setFrame:screenFrame display:NO]; 635 636 CGFloat currentAlpha = 1; 637 if (_fadeAnimation) { 638 currentAlpha = [_fadeAnimation currentAlpha]; 639 [_fadeAnimation stopAnimation]; 640 [_fadeAnimation setWindow:nil]; 641 } 642 _fadeAnimation = adoptNS([[WebWindowFadeAnimation alloc] initWithDuration:duration 643 window:_backgroundWindow.get() 644 initialAlpha:currentAlpha 645 finalAlpha:0]); 646 [_fadeAnimation setAnimationBlockingMode:NSAnimationNonblocking]; 647 [_fadeAnimation setCurrentProgress:0]; 648 [_fadeAnimation startAnimation]; 649 650 [_backgroundWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]]; 651 652 // WKWindowSetClipRect takes window coordinates, so convert from screen coordinates here: 653 NSRect finalBounds = _finalFrame; 654#pragma clang diagnostic push 655#pragma clang diagnostic ignored "-Wdeprecated-declarations" 656 finalBounds.origin = [[self window] convertScreenToBase:finalBounds.origin]; 657#pragma clang diagnostic pop 658 WKWindowSetClipRect([self window], finalBounds); 659 660 [_webView _setSuppressVisibilityUpdates:NO]; 661 [[self window] setAutodisplay:YES]; 662 [[self window] displayIfNeeded]; 663 NSEnableScreenUpdates(); 664} 665@end 666 667#endif // ENABLE(FULLSCREEN_API) && !PLATFORM(IOS) 668