<http://webkit.org/b/91015> Remove BUILDING_ON / TARGETING macros in favor of system...
[WebKit-https.git] / Source / WebKit2 / UIProcess / mac / WKFullScreenWindowController.mm
index 172c71b..6932b81 100644 (file)
@@ -55,14 +55,14 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
 
 @interface WKFullScreenWindowController(Private)<NSAnimationDelegate>
 - (void)_updateMenuAndDockForFullScreen;
-- (void)_swapView:(NSView*)view with:(NSView*)otherView;
+- (void)_replaceView:(NSView*)view with:(NSView*)otherView;
 - (WebPageProxy*)_page;
 - (WebFullScreenManagerProxy*)_manager;
 - (void)_startEnterFullScreenAnimationWithDuration:(NSTimeInterval)duration;
 - (void)_startExitFullScreenAnimationWithDuration:(NSTimeInterval)duration;
 @end
 
-#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD)
+#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1060
 @interface NSWindow(convertRectToScreenForLeopardAndSnowLeopard)
 - (NSRect)convertRectToScreen:(NSRect)aRect;
 @end
@@ -183,6 +183,28 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
 #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 (_isFullScreen)
@@ -204,13 +226,24 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
     CGWindowID windowID = [[_webView window] windowNumber];
     RetainPtr<CGImageRef> webViewContents(AdoptCF, CGWindowListCreateImage(NSRectToCGRect(webViewFrame), kCGWindowListOptionIncludingWindow, windowID, kCGWindowImageShouldBeOpaque));
 
-    // Screen updates to be re-enabled in beganEnterFullScreenWithInitialFrame:finalFrame:
+    // 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 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([[NSImageView alloc] init]);
@@ -218,7 +251,7 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
         [_webViewPlaceholder.get() setWantsLayer:YES];
     }
     [[_webViewPlaceholder.get() layer] setContents:(id)webViewContents.get()];
-    [self _swapView:_webView with:_webViewPlaceholder.get()];
+    [self _replaceView:_webView with:_webViewPlaceholder.get()];
     
     // Then insert the WebView into the full screen window
     NSView* contentView = [[self window] contentView];
@@ -262,14 +295,14 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
         WKWindowSetClipRect([self window], windowBounds);
 
         NSWindow *webWindow = [_webViewPlaceholder.get() window];
-#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
         // In Lion, NSWindow will animate into and out of orderOut operations. Suppress that
         // behavior here, making sure to reset the animation behavior afterward.
         NSWindowAnimationBehavior animationBehavior = [webWindow animationBehavior];
         [webWindow setAnimationBehavior:NSWindowAnimationBehaviorNone];
 #endif
         [webWindow orderOut:self];
-#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
         [webWindow setAnimationBehavior:animationBehavior];
 #endif
 
@@ -295,10 +328,14 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
         return;
     _isFullScreen = NO;
 
-    // Screen updates to be re-enabled in beganExitFullScreenWithInitialFrame:finalFrame:
+    // Screen updates to be re-enabled in _startExitFullScreenAnimationWithDuration:
     NSDisableScreenUpdates();
     [[self window] setAutodisplay:NO];
 
+    // See the related comment in enterFullScreen:
+    // We will resume the normal behavior in _startExitFullScreenAnimationWithDuration:
+    [_webView _setSuppressVisibilityUpdates:YES];
+
     [self _manager]->setAnimatingFullScreen(true);
     [self _manager]->willExitFullScreen();
 }
@@ -315,7 +352,7 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
     [self _updateMenuAndDockForFullScreen];
     
     NSWindow* webWindow = [_webViewPlaceholder.get() window];
-#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
     // In Lion, NSWindow will animate into and out of orderOut operations. Suppress that
     // behavior here, making sure to reset the animation behavior afterward.
     NSWindowAnimationBehavior animationBehavior = [webWindow animationBehavior];
@@ -323,7 +360,7 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
 #endif
     // If the user has moved the fullScreen window into a new space, temporarily change
     // the collectionBehavior of the webView's window so that it is pulled into the active space:
-    if (![webWindow isOnActiveSpace]) {
+    if (!([webWindow respondsToSelector:@selector(isOnActiveSpace)] ? [webWindow isOnActiveSpace] : YES)) {
         NSWindowCollectionBehavior behavior = [webWindow collectionBehavior];
         [webWindow setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
         [webWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]];
@@ -331,13 +368,15 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
     } else
         [webWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]];
     
-#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
     [webWindow setAnimationBehavior:animationBehavior];
 #endif
 
     [self _startExitFullScreenAnimationWithDuration:defaultAnimationDuration];
 }
 
+static void completeFinishExitFullScreenAnimationAfterRepaint(WKErrorRef, void*);
+
 - (void)finishedExitFullScreenAnimation:(bool)completed
 {
     if (!_isExitingFullScreen)
@@ -346,14 +385,12 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
 
     [self _updateMenuAndDockForFullScreen];
 
-    // Screen updates to be re-enabled ta the end of the current function.
+    // Screen updates to be re-enabled in completeFinishExitFullScreenAnimationAfterRepaint.
     NSDisableScreenUpdates();
-
-    [self _manager]->didExitFullScreen();
-    [self _manager]->setAnimatingFullScreen(false);
+    [[_webViewPlaceholder.get() window] setAutodisplay:NO];
 
     NSResponder *firstResponder = [[self window] firstResponder];
-    [self _swapView:_webViewPlaceholder.get() with:_webView];
+    [self _replaceView:_webViewPlaceholder.get() with:_webView];
     [[_webView window] makeResponder:firstResponder firstResponderIfDescendantOfView:_webView];
 
     NSRect windowBounds = [[self window] frame];
@@ -372,9 +409,25 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
 
     [[_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]->forceRepaint(VoidCallback::create(self, completeFinishExitFullScreenAnimationAfterRepaint));
+}
+
+- (void)completeFinishExitFullScreenAnimationAfterRepaint
+{
+    [[_webView window] setAutodisplay:YES];
+    [[_webView window] displayIfNeeded];
     NSEnableScreenUpdates();
 }
 
+static void completeFinishExitFullScreenAnimationAfterRepaint(WKErrorRef, void* _self)
+{
+    [(WKFullScreenWindowController*)_self completeFinishExitFullScreenAnimationAfterRepaint];
+}
+
 - (void)close
 {
     // We are being asked to close rapidly, most likely because the page 
@@ -407,7 +460,7 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
 - (void)_updateMenuAndDockForFullScreen
 {
     // NSApplicationPresentationOptions is available on > 10.6 only:
-#ifndef BUILDING_ON_LEOPARD
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
     NSApplicationPresentationOptions options = NSApplicationPresentationDefault;
     NSScreen* fullScreenScreen = [[self window] screen];
     
@@ -428,7 +481,7 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
         [NSApp setPresentationOptions:options];
     else
 #endif
-        SetSystemUIMode(_isFullScreen ? kUIModeNormal : kUIModeAllHidden, 0);
+        SetSystemUIMode(_isFullScreen ? kUIModeAllHidden : kUIModeNormal, 0);
 }
 
 - (WebPageProxy*)_page
@@ -444,15 +497,15 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
     return webPage->fullScreenManager();
 }
 
-- (void)_swapView:(NSView*)view with:(NSView*)otherView
+- (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:otherView];
-    [otherView removeFromSuperview];
+    [[view superview] addSubview:otherView positioned:NSWindowAbove relativeTo:view];
+    [view removeFromSuperview];
     [CATransaction commit];
 }
 
@@ -468,6 +521,9 @@ static RetainPtr<NSWindow> createBackgroundFullscreenWindow(NSRect frame)
 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);
@@ -520,6 +576,7 @@ static NSRect windowFrameFromApparentFrames(NSRect screenFrame, NSRect initialFr
 
     [_backgroundWindow.get() orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]];
 
+    [_webView _setSuppressVisibilityUpdates:NO];
     [[self window] setAutodisplay:YES];
     [[self window] displayIfNeeded];
     NSEnableScreenUpdates();
@@ -564,6 +621,7 @@ static NSRect windowFrameFromApparentFrames(NSRect screenFrame, NSRect initialFr
     finalBounds.origin = [[self window] convertScreenToBase:finalBounds.origin];
     WKWindowSetClipRect([self window], finalBounds);
 
+    [_webView _setSuppressVisibilityUpdates:NO];
     [[self window] setAutodisplay:YES];
     [[self window] displayIfNeeded];
     NSEnableScreenUpdates();