| /* |
| * Copyright (C) 2009, 2010, 2011 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #import "config.h" |
| |
| #if ENABLE(FULLSCREEN_API) && !PLATFORM(IOS) |
| |
| #import "WKFullScreenWindowController.h" |
| |
| #import "LayerTreeContext.h" |
| #import "WKAPICast.h" |
| #import "WKViewInternal.h" |
| #import "WKViewPrivate.h" |
| #import "WebFullScreenManagerProxy.h" |
| #import "WebPageProxy.h" |
| #import <QuartzCore/QuartzCore.h> |
| #import <WebCore/DisplaySleepDisabler.h> |
| #import <WebCore/FloatRect.h> |
| #import <WebCore/IntRect.h> |
| #import <WebCore/LocalizedStrings.h> |
| #import <WebCore/WebCoreFullScreenPlaceholderView.h> |
| #import <WebCore/WebCoreFullScreenWindow.h> |
| #import <WebCore/WebWindowAnimation.h> |
| #import <WebKitSystemInterface.h> |
| |
| using namespace WebKit; |
| using namespace WebCore; |
| |
| static RetainPtr<NSWindow> createBackgroundFullscreenWindow(NSRect frame); |
| |
| static const NSTimeInterval DefaultWatchdogTimerInterval = 1; |
| |
| enum FullScreenState : NSInteger { |
| NotInFullScreen, |
| WaitingToEnterFullScreen, |
| EnteringFullScreen, |
| InFullScreen, |
| WaitingToExitFullScreen, |
| ExitingFullScreen, |
| }; |
| |
| @interface NSWindow (WebNSWindowDetails) |
| - (void)exitFullScreenMode:(id)sender; |
| - (void)enterFullScreenMode:(id)sender; |
| @end |
| |
| @interface WKFullScreenWindowController(Private)<NSAnimationDelegate> |
| - (void)_replaceView:(NSView*)view with:(NSView*)otherView; |
| - (WebPageProxy*)_page; |
| - (WebFullScreenManagerProxy*)_manager; |
| - (void)_startEnterFullScreenAnimationWithDuration:(NSTimeInterval)duration; |
| - (void)_startExitFullScreenAnimationWithDuration:(NSTimeInterval)duration; |
| @end |
| |
| static NSRect convertRectToScreen(NSWindow *window, NSRect rect) |
| { |
| return [window convertRectToScreen:rect]; |
| } |
| |
| static void makeResponderFirstResponderIfDescendantOfView(NSWindow *window, NSResponder *responder, NSView *view) |
| { |
| if ([responder isKindOfClass:[NSView class]] && [(NSView *)responder isDescendantOf:view]) |
| [window makeFirstResponder:responder]; |
| } |
| |
| @implementation WKFullScreenWindowController |
| |
| #pragma mark - |
| #pragma mark Initialization |
| - (id)initWithWindow:(NSWindow *)window webView:(WKView *)webView |
| { |
| self = [super initWithWindow:window]; |
| if (!self) |
| return nil; |
| [window setDelegate:self]; |
| [window setCollectionBehavior:([window collectionBehavior] | NSWindowCollectionBehaviorFullScreenPrimary)]; |
| [self windowDidLoad]; |
| _webView = webView; |
| |
| return self; |
| } |
| |
| - (void)dealloc |
| { |
| [[self window] setDelegate:nil]; |
| |
| [NSObject cancelPreviousPerformRequestsWithTarget:self]; |
| |
| [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| |
| if (_repaintCallback) { |
| _repaintCallback->invalidate(CallbackBase::Error::OwnerWasInvalidated); |
| // invalidate() calls completeFinishExitFullScreenAnimationAfterRepaint, which |
| // clears _repaintCallback. |
| ASSERT(!_repaintCallback); |
| } |
| |
| [super dealloc]; |
| } |
| |
| - (void)windowDidLoad |
| { |
| [super windowDidLoad]; |
| |
| [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidChangeScreenParameters:) name:NSApplicationDidChangeScreenParametersNotification object:NSApp]; |
| } |
| |
| #pragma mark - |
| #pragma mark Accessors |
| |
| - (BOOL)isFullScreen |
| { |
| return _fullScreenState == WaitingToEnterFullScreen |
| || _fullScreenState == EnteringFullScreen |
| || _fullScreenState == InFullScreen; |
| } |
| |
| - (WebCoreFullScreenPlaceholderView*)webViewPlaceholder |
| { |
| return _webViewPlaceholder.get(); |
| } |
| |
| #pragma mark - |
| #pragma mark NSWindowController overrides |
| |
| - (void)cancelOperation:(id)sender |
| { |
| // If the page doesn't respond in DefaultWatchdogTimerInterval seconds, it could be because |
| // the WebProcess has hung, so exit anyway. |
| if (!_watchdogTimer) { |
| [self _manager]->requestExitFullScreen(); |
| _watchdogTimer = adoptNS([[NSTimer alloc] initWithFireDate:nil interval:DefaultWatchdogTimerInterval target:self selector:@selector(exitFullScreen) userInfo:nil repeats:NO]); |
| [[NSRunLoop mainRunLoop] addTimer:_watchdogTimer.get() forMode:NSDefaultRunLoopMode]; |
| } |
| } |
| |
| #pragma mark - |
| #pragma mark Notifications |
| |
| - (void)applicationDidChangeScreenParameters:(NSNotification*)notification |
| { |
| // The user may have changed the main screen by moving the menu bar, or they may have changed |
| // the Dock's size or location, or they may have changed the fullScreen screen's dimensions. |
| // Update our presentation parameters, and ensure that the full screen window occupies the |
| // entire screen: |
| NSWindow* window = [self window]; |
| NSRect screenFrame = [[window screen] frame]; |
| [window setFrame:screenFrame display:YES]; |
| [_backgroundWindow setFrame:screenFrame display:YES]; |
| } |
| |
| #pragma mark - |
| #pragma mark Exposed Interface |
| |
| static RetainPtr<CGDataProviderRef> createImageProviderWithCopiedData(CGDataProviderRef sourceProvider) |
| { |
| RetainPtr<CFDataRef> data = adoptCF(CGDataProviderCopyData(sourceProvider)); |
| return adoptCF(CGDataProviderCreateWithCFData(data.get())); |
| } |
| |
| static RetainPtr<CGImageRef> createImageWithCopiedData(CGImageRef sourceImage) |
| { |
| size_t width = CGImageGetWidth(sourceImage); |
| size_t height = CGImageGetHeight(sourceImage); |
| size_t bitsPerComponent = CGImageGetBitsPerComponent(sourceImage); |
| size_t bitsPerPixel = CGImageGetBitsPerPixel(sourceImage); |
| size_t bytesPerRow = CGImageGetBytesPerRow(sourceImage); |
| CGColorSpaceRef colorSpace = CGImageGetColorSpace(sourceImage); |
| CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(sourceImage); |
| RetainPtr<CGDataProviderRef> provider = createImageProviderWithCopiedData(CGImageGetDataProvider(sourceImage)); |
| bool shouldInterpolate = CGImageGetShouldInterpolate(sourceImage); |
| CGColorRenderingIntent intent = CGImageGetRenderingIntent(sourceImage); |
| |
| return adoptCF(CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, bitmapInfo, provider.get(), 0, shouldInterpolate, intent)); |
| } |
| |
| - (void)enterFullScreen:(NSScreen *)screen |
| { |
| if ([self isFullScreen]) |
| return; |
| _fullScreenState = WaitingToEnterFullScreen; |
| |
| if (!screen) |
| screen = [NSScreen mainScreen]; |
| NSRect screenFrame = [screen frame]; |
| |
| NSRect webViewFrame = convertRectToScreen([_webView window], [_webView convertRect:[_webView frame] toView:nil]); |
| |
| // Flip coordinate system: |
| webViewFrame.origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - NSMaxY(webViewFrame); |
| |
| CGWindowID windowID = [[_webView window] windowNumber]; |
| RetainPtr<CGImageRef> webViewContents = adoptCF(CGWindowListCreateImage(NSRectToCGRect(webViewFrame), kCGWindowListOptionIncludingWindow, windowID, kCGWindowImageShouldBeOpaque)); |
| |
| // Using the returned CGImage directly would result in calls to the WindowServer every time |
| // the image was painted. Instead, copy the image data into our own process to eliminate that |
| // future overhead. |
| webViewContents = createImageWithCopiedData(webViewContents.get()); |
| |
| // Screen updates to be re-enabled in _startEnterFullScreenAnimationWithDuration: |
| NSDisableScreenUpdates(); |
| [[self window] setAutodisplay:NO]; |
| |
| NSResponder *webWindowFirstResponder = [[_webView window] firstResponder]; |
| [self _manager]->saveScrollPosition(); |
| [[self window] setFrame:screenFrame display:NO]; |
| |
| // Painting is normally suspended when the WKView is removed from the window, but this is |
| // unnecessary in the full-screen animation case, and can cause bugs; see |
| // https://bugs.webkit.org/show_bug.cgi?id=88940 and https://bugs.webkit.org/show_bug.cgi?id=88374 |
| // We will resume the normal behavior in _startEnterFullScreenAnimationWithDuration: |
| [_webView _setSuppressVisibilityUpdates:YES]; |
| |
| // Swap the webView placeholder into place. |
| if (!_webViewPlaceholder) { |
| _webViewPlaceholder = adoptNS([[WebCoreFullScreenPlaceholderView alloc] initWithFrame:[_webView frame]]); |
| [_webViewPlaceholder setAction:@selector(cancelOperation:)]; |
| } |
| [_webViewPlaceholder setTarget:nil]; |
| [_webViewPlaceholder setContents:(id)webViewContents.get()]; |
| [self _replaceView:_webView with:_webViewPlaceholder.get()]; |
| |
| // Then insert the WebView into the full screen window |
| NSView* contentView = [[self window] contentView]; |
| [contentView addSubview:_webView positioned:NSWindowBelow relativeTo:nil]; |
| [_webView setFrame:[contentView bounds]]; |
| |
| makeResponderFirstResponderIfDescendantOfView(self.window, webWindowFirstResponder, _webView); |
| |
| [self _manager]->setAnimatingFullScreen(true); |
| [self _manager]->willEnterFullScreen(); |
| _savedScale = [self _page]->pageScaleFactor(); |
| [self _page]->scalePage(1, IntPoint()); |
| } |
| |
| - (void)beganEnterFullScreenWithInitialFrame:(const WebCore::IntRect&)initialFrame finalFrame:(const WebCore::IntRect&)finalFrame |
| { |
| if (_fullScreenState != WaitingToEnterFullScreen) |
| return; |
| _fullScreenState = EnteringFullScreen; |
| |
| _initialFrame = initialFrame; |
| _finalFrame = finalFrame; |
| |
| if (!_backgroundWindow) |
| _backgroundWindow = createBackgroundFullscreenWindow(NSZeroRect); |
| |
| [self.window orderBack: self]; // Make sure the full screen window is part of the correct Space. |
| [[self window] enterFullScreenMode:self]; |
| } |
| |
| - (void)finishedEnterFullScreenAnimation:(bool)completed |
| { |
| if (_fullScreenState != EnteringFullScreen) |
| return; |
| |
| if (completed) { |
| _fullScreenState = InFullScreen; |
| |
| // Screen updates to be re-enabled ta the end of the current block. |
| NSDisableScreenUpdates(); |
| [self _manager]->didEnterFullScreen(); |
| [self _manager]->setAnimatingFullScreen(false); |
| |
| NSRect windowBounds = [[self window] frame]; |
| windowBounds.origin = NSZeroPoint; |
| WKWindowSetClipRect([self window], windowBounds); |
| |
| [_fadeAnimation stopAnimation]; |
| [_fadeAnimation setWindow:nil]; |
| _fadeAnimation = nullptr; |
| |
| [_backgroundWindow orderOut:self]; |
| [_backgroundWindow setFrame:NSZeroRect display:YES]; |
| |
| [_webViewPlaceholder setExitWarningVisible:YES]; |
| [_webViewPlaceholder setTarget:self]; |
| } else { |
| // Transition to fullscreen failed. Clean up. |
| _fullScreenState = NotInFullScreen; |
| |
| [_scaleAnimation stopAnimation]; |
| |
| [_backgroundWindow orderOut:self]; |
| [_backgroundWindow setFrame:NSZeroRect display:YES]; |
| |
| [[self window] setAutodisplay:YES]; |
| [_webView _setSuppressVisibilityUpdates:NO]; |
| |
| NSResponder *firstResponder = [[self window] firstResponder]; |
| [self _replaceView:_webViewPlaceholder.get() with:_webView]; |
| makeResponderFirstResponderIfDescendantOfView(_webView.window, firstResponder, _webView); |
| [[_webView window] makeKeyAndOrderFront:self]; |
| |
| [self _manager]->didExitFullScreen(); |
| [self _manager]->setAnimatingFullScreen(false); |
| [self _page]->scalePage(_savedScale, IntPoint()); |
| [self _manager]->restoreScrollPosition(); |
| } |
| |
| NSEnableScreenUpdates(); |
| } |
| |
| - (void)exitFullScreen |
| { |
| if (_watchdogTimer) { |
| [_watchdogTimer invalidate]; |
| _watchdogTimer.clear(); |
| } |
| |
| if (![self isFullScreen]) |
| return; |
| _fullScreenState = WaitingToExitFullScreen; |
| |
| [_webViewPlaceholder setExitWarningVisible:NO]; |
| |
| // Screen updates to be re-enabled in _startExitFullScreenAnimationWithDuration: or beganExitFullScreenWithInitialFrame:finalFrame: |
| NSDisableScreenUpdates(); |
| [[self window] setAutodisplay:NO]; |
| |
| // See the related comment in enterFullScreen: |
| // We will resume the normal behavior in _startExitFullScreenAnimationWithDuration: |
| [_webView _setSuppressVisibilityUpdates:YES]; |
| [_webViewPlaceholder setTarget:nil]; |
| |
| [self _manager]->setAnimatingFullScreen(true); |
| [self _manager]->willExitFullScreen(); |
| } |
| |
| - (void)beganExitFullScreenWithInitialFrame:(const WebCore::IntRect&)initialFrame finalFrame:(const WebCore::IntRect&)finalFrame |
| { |
| if (_fullScreenState != WaitingToExitFullScreen) |
| return; |
| _fullScreenState = ExitingFullScreen; |
| |
| if (![[self window] isOnActiveSpace]) { |
| // If the full screen window is not in the active space, the NSWindow full screen animation delegate methods |
| // will never be called. So call finishedExitFullScreenAnimation explicitly. |
| [self finishedExitFullScreenAnimation:YES]; |
| |
| // Because we are breaking the normal animation pattern, re-enable screen updates |
| // as exitFullScreen has disabled them, but _startExitFullScreenAnimationWithDuration: |
| // will never be called. |
| NSEnableScreenUpdates(); |
| } |
| |
| [[self window] exitFullScreenMode:self]; |
| } |
| |
| - (void)finishedExitFullScreenAnimation:(bool)completed |
| { |
| if (_fullScreenState != ExitingFullScreen) |
| return; |
| _fullScreenState = NotInFullScreen; |
| |
| // Screen updates to be re-enabled in completeFinishExitFullScreenAnimationAfterRepaint. |
| NSDisableScreenUpdates(); |
| [[_webViewPlaceholder window] setAutodisplay:NO]; |
| |
| NSResponder *firstResponder = [[self window] firstResponder]; |
| [self _replaceView:_webViewPlaceholder.get() with:_webView]; |
| makeResponderFirstResponderIfDescendantOfView(_webView.window, firstResponder, _webView); |
| |
| NSRect windowBounds = [[self window] frame]; |
| windowBounds.origin = NSZeroPoint; |
| WKWindowSetClipRect([self window], windowBounds); |
| |
| [[self window] orderOut:self]; |
| [[self window] setFrame:NSZeroRect display:YES]; |
| |
| [_scaleAnimation stopAnimation]; |
| [_scaleAnimation setWindow:nil]; |
| _scaleAnimation = nullptr; |
| |
| [_fadeAnimation stopAnimation]; |
| [_fadeAnimation setWindow:nil]; |
| _fadeAnimation = nullptr; |
| |
| [_backgroundWindow orderOut:self]; |
| [_backgroundWindow setFrame:NSZeroRect display:YES]; |
| |
| [[_webView window] makeKeyAndOrderFront:self]; |
| |
| // These messages must be sent after the swap or flashing will occur during forceRepaint: |
| [self _manager]->didExitFullScreen(); |
| [self _manager]->setAnimatingFullScreen(false); |
| [self _page]->scalePage(_savedScale, IntPoint()); |
| [self _manager]->restoreScrollPosition(); |
| |
| if (_repaintCallback) { |
| _repaintCallback->invalidate(CallbackBase::Error::OwnerWasInvalidated); |
| // invalidate() calls completeFinishExitFullScreenAnimationAfterRepaint, which |
| // clears _repaintCallback. |
| ASSERT(!_repaintCallback); |
| } |
| _repaintCallback = VoidCallback::create([self](CallbackBase::Error) { |
| [self completeFinishExitFullScreenAnimationAfterRepaint]; |
| }); |
| [self _page]->forceRepaint(_repaintCallback); |
| } |
| |
| - (void)completeFinishExitFullScreenAnimationAfterRepaint |
| { |
| _repaintCallback = nullptr; |
| [[_webView window] setAutodisplay:YES]; |
| [[_webView window] displayIfNeeded]; |
| NSEnableScreenUpdates(); |
| } |
| |
| - (void)performClose:(id)sender |
| { |
| if ([self isFullScreen]) |
| [self cancelOperation:sender]; |
| } |
| |
| - (void)close |
| { |
| // We are being asked to close rapidly, most likely because the page |
| // has closed or the web process has crashed. Just walk through our |
| // normal exit full screen sequence, but don't wait to be called back |
| // in response. |
| if ([self isFullScreen]) |
| [self exitFullScreen]; |
| |
| if (_fullScreenState == ExitingFullScreen) |
| [self finishedExitFullScreenAnimation:YES]; |
| |
| [_scaleAnimation stopAnimation]; |
| [_scaleAnimation setWindow:nil]; |
| [_fadeAnimation stopAnimation]; |
| [_fadeAnimation setWindow:nil]; |
| |
| _webView = nil; |
| |
| [super close]; |
| } |
| |
| #pragma mark - |
| #pragma mark Custom NSWindow Full Screen Animation |
| |
| - (NSArray *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window |
| { |
| return [NSArray arrayWithObjects:[self window], _backgroundWindow.get(), nil]; |
| } |
| |
| - (NSArray *)customWindowsToExitFullScreenForWindow:(NSWindow *)window |
| { |
| return [NSArray arrayWithObjects:[self window], _backgroundWindow.get(), nil]; |
| } |
| |
| - (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration |
| { |
| [self _startEnterFullScreenAnimationWithDuration:duration]; |
| } |
| |
| - (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration |
| { |
| [self _startExitFullScreenAnimationWithDuration:duration]; |
| } |
| |
| - (void)windowDidFailToEnterFullScreen:(NSWindow *)window |
| { |
| [self finishedEnterFullScreenAnimation:NO]; |
| } |
| |
| - (void)windowDidEnterFullScreen:(NSNotification*)notification |
| { |
| [self finishedEnterFullScreenAnimation:YES]; |
| } |
| |
| - (void)windowDidFailToExitFullScreen:(NSWindow *)window |
| { |
| [self finishedExitFullScreenAnimation:NO]; |
| } |
| |
| - (void)windowDidExitFullScreen:(NSNotification*)notification |
| { |
| [self finishedExitFullScreenAnimation:YES]; |
| } |
| |
| #pragma mark - |
| #pragma mark Internal Interface |
| |
| - (WebPageProxy*)_page |
| { |
| return toImpl([_webView pageRef]); |
| } |
| |
| - (WebFullScreenManagerProxy*)_manager |
| { |
| WebPageProxy* webPage = [self _page]; |
| if (!webPage) |
| return 0; |
| return webPage->fullScreenManager(); |
| } |
| |
| - (void)_replaceView:(NSView*)view with:(NSView*)otherView |
| { |
| [CATransaction begin]; |
| [CATransaction setDisableActions:YES]; |
| [otherView setFrame:[view frame]]; |
| [otherView setAutoresizingMask:[view autoresizingMask]]; |
| [otherView removeFromSuperview]; |
| [[view superview] addSubview:otherView positioned:NSWindowAbove relativeTo:view]; |
| [view removeFromSuperview]; |
| [CATransaction commit]; |
| } |
| |
| static RetainPtr<NSWindow> createBackgroundFullscreenWindow(NSRect frame) |
| { |
| NSWindow *window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; |
| [window setOpaque:YES]; |
| [window setBackgroundColor:[NSColor blackColor]]; |
| [window setReleasedWhenClosed:NO]; |
| return adoptNS(window); |
| } |
| |
| static NSRect windowFrameFromApparentFrames(NSRect screenFrame, NSRect initialFrame, NSRect finalFrame) |
| { |
| NSRect initialWindowFrame; |
| if (!NSWidth(initialFrame) || !NSWidth(finalFrame) || !NSHeight(initialFrame) || !NSHeight(finalFrame)) |
| return screenFrame; |
| |
| CGFloat xScale = NSWidth(screenFrame) / NSWidth(finalFrame); |
| CGFloat yScale = NSHeight(screenFrame) / NSHeight(finalFrame); |
| CGFloat xTrans = NSMinX(screenFrame) - NSMinX(finalFrame); |
| CGFloat yTrans = NSMinY(screenFrame) - NSMinY(finalFrame); |
| initialWindowFrame.size = NSMakeSize(NSWidth(initialFrame) * xScale, NSHeight(initialFrame) * yScale); |
| initialWindowFrame.origin = NSMakePoint |
| ( NSMinX(initialFrame) + xTrans / (NSWidth(finalFrame) / NSWidth(initialFrame)) |
| , NSMinY(initialFrame) + yTrans / (NSHeight(finalFrame) / NSHeight(initialFrame))); |
| return initialWindowFrame; |
| } |
| |
| - (void)_startEnterFullScreenAnimationWithDuration:(NSTimeInterval)duration |
| { |
| NSRect screenFrame = [[[self window] screen] frame]; |
| NSRect initialWindowFrame = windowFrameFromApparentFrames(screenFrame, _initialFrame, _finalFrame); |
| |
| _scaleAnimation = adoptNS([[WebWindowScaleAnimation alloc] initWithHintedDuration:duration window:[self window] initalFrame:initialWindowFrame finalFrame:screenFrame]); |
| |
| [_scaleAnimation setAnimationBlockingMode:NSAnimationNonblocking]; |
| [_scaleAnimation setCurrentProgress:0]; |
| [_scaleAnimation startAnimation]; |
| |
| // WKWindowSetClipRect takes window coordinates, so convert from screen coordinates here: |
| NSRect finalBounds = _finalFrame; |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| finalBounds.origin = [[self window] convertScreenToBase:finalBounds.origin]; |
| #pragma clang diagnostic pop |
| WKWindowSetClipRect([self window], finalBounds); |
| |
| NSWindow* window = [self window]; |
| NSWindowCollectionBehavior behavior = [window collectionBehavior]; |
| [window setCollectionBehavior:(behavior | NSWindowCollectionBehaviorCanJoinAllSpaces)]; |
| [window makeKeyAndOrderFront:self]; |
| [window setCollectionBehavior:behavior]; |
| |
| |
| if (!_backgroundWindow) |
| _backgroundWindow = createBackgroundFullscreenWindow(screenFrame); |
| else |
| [_backgroundWindow setFrame:screenFrame display:NO]; |
| |
| CGFloat currentAlpha = 0; |
| if (_fadeAnimation) { |
| currentAlpha = [_fadeAnimation currentAlpha]; |
| [_fadeAnimation stopAnimation]; |
| [_fadeAnimation setWindow:nil]; |
| } |
| |
| _fadeAnimation = adoptNS([[WebWindowFadeAnimation alloc] initWithDuration:duration |
| window:_backgroundWindow.get() |
| initialAlpha:currentAlpha |
| finalAlpha:1]); |
| [_fadeAnimation setAnimationBlockingMode:NSAnimationNonblocking]; |
| [_fadeAnimation setCurrentProgress:0]; |
| [_fadeAnimation startAnimation]; |
| |
| [_backgroundWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]]; |
| |
| [_webView _setSuppressVisibilityUpdates:NO]; |
| [[self window] setAutodisplay:YES]; |
| [[self window] displayIfNeeded]; |
| NSEnableScreenUpdates(); |
| } |
| |
| - (void)_startExitFullScreenAnimationWithDuration:(NSTimeInterval)duration |
| { |
| if ([self isFullScreen]) { |
| // We still believe we're in full screen mode, so we must have been asked to exit full |
| // screen by the system full screen button. |
| [self _manager]->requestExitFullScreen(); |
| [self exitFullScreen]; |
| _fullScreenState = ExitingFullScreen; |
| } |
| |
| NSRect screenFrame = [[[self window] screen] frame]; |
| NSRect initialWindowFrame = windowFrameFromApparentFrames(screenFrame, _initialFrame, _finalFrame); |
| |
| NSRect currentFrame = _scaleAnimation ? [_scaleAnimation currentFrame] : [[self window] frame]; |
| _scaleAnimation = adoptNS([[WebWindowScaleAnimation alloc] initWithHintedDuration:duration window:[self window] initalFrame:currentFrame finalFrame:initialWindowFrame]); |
| |
| [_scaleAnimation setAnimationBlockingMode:NSAnimationNonblocking]; |
| [_scaleAnimation setCurrentProgress:0]; |
| [_scaleAnimation startAnimation]; |
| |
| if (!_backgroundWindow) |
| _backgroundWindow = createBackgroundFullscreenWindow(screenFrame); |
| else |
| [_backgroundWindow setFrame:screenFrame display:NO]; |
| |
| CGFloat currentAlpha = 1; |
| if (_fadeAnimation) { |
| currentAlpha = [_fadeAnimation currentAlpha]; |
| [_fadeAnimation stopAnimation]; |
| [_fadeAnimation setWindow:nil]; |
| } |
| _fadeAnimation = adoptNS([[WebWindowFadeAnimation alloc] initWithDuration:duration |
| window:_backgroundWindow.get() |
| initialAlpha:currentAlpha |
| finalAlpha:0]); |
| [_fadeAnimation setAnimationBlockingMode:NSAnimationNonblocking]; |
| [_fadeAnimation setCurrentProgress:0]; |
| [_fadeAnimation startAnimation]; |
| |
| [_backgroundWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]]; |
| |
| // WKWindowSetClipRect takes window coordinates, so convert from screen coordinates here: |
| NSRect finalBounds = _finalFrame; |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| finalBounds.origin = [[self window] convertScreenToBase:finalBounds.origin]; |
| #pragma clang diagnostic pop |
| WKWindowSetClipRect([self window], finalBounds); |
| |
| [_webView _setSuppressVisibilityUpdates:NO]; |
| [[self window] setAutodisplay:YES]; |
| [[self window] displayIfNeeded]; |
| NSEnableScreenUpdates(); |
| } |
| @end |
| |
| #endif // ENABLE(FULLSCREEN_API) && !PLATFORM(IOS) |