Flicker when exiting element fullscreen.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Dec 2018 00:27:50 +0000 (00:27 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Dec 2018 00:27:50 +0000 (00:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=192774
rdar://problem/33088878

Patch by Jeremy Jones <jeremyj@apple.com> on 2018-12-20
Reviewed by Jer Noble.

Fixes an issue where the web page would flicker upon exiting element fullscreen.

Replace WebView with a snapshot while the WebView is restyled and resized for inline.

* UIProcess/mac/WKFullScreenWindowController.h:
* UIProcess/mac/WKFullScreenWindowController.mm:
(-[WKFullScreenWindowController initWithWindow:webView:page:]):
(-[WKFullScreenWindowController finishedExitFullScreenAnimation:]):
(-[WKFullScreenWindowController completeFinishExitFullScreenAnimationAfterRepaint]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@239475 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/ChangeLog
Source/WebKit/UIProcess/mac/WKFullScreenWindowController.h
Source/WebKit/UIProcess/mac/WKFullScreenWindowController.mm

index 6044dc0..f90802d 100644 (file)
@@ -1,3 +1,21 @@
+2018-12-20  Jeremy Jones  <jeremyj@apple.com>
+
+        Flicker when exiting element fullscreen.
+        https://bugs.webkit.org/show_bug.cgi?id=192774
+        rdar://problem/33088878
+
+        Reviewed by Jer Noble.
+
+        Fixes an issue where the web page would flicker upon exiting element fullscreen.
+
+        Replace WebView with a snapshot while the WebView is restyled and resized for inline.
+
+        * UIProcess/mac/WKFullScreenWindowController.h:
+        * UIProcess/mac/WKFullScreenWindowController.mm:
+        (-[WKFullScreenWindowController initWithWindow:webView:page:]):
+        (-[WKFullScreenWindowController finishedExitFullScreenAnimation:]):
+        (-[WKFullScreenWindowController completeFinishExitFullScreenAnimationAfterRepaint]):
+
 2018-12-20  Chris Dumez  <cdumez@apple.com>
 
         Move HTTPS_UPGRADE code behind a runtime flag, off by default
index 33c58e7..4336c25 100644 (file)
@@ -48,6 +48,7 @@ typedef enum FullScreenState : NSInteger FullScreenState;
     NSView *_webView; // Cannot be retained, see <rdar://problem/14884666>.
     WebKit::WebPageProxy* _page;
     RetainPtr<WebCoreFullScreenPlaceholderView> _webViewPlaceholder;
+    RetainPtr<NSView> _exitPlaceholder;
     RetainPtr<NSView> _clipView;
     RetainPtr<NSView> _backgroundView;
     NSRect _initialFrame;
index 10668e6..0f76b8d 100644 (file)
@@ -440,6 +440,26 @@ static const float minVideoWidth = 480 + 20 + 20; // Note: Keep in sync with med
     [[self window] exitFullScreenMode:self];
 }
 
+WTF_DECLARE_CF_TYPE_TRAIT(CGImage);
+
+static RetainPtr<CGImageRef> takeWindowSnapshot(CGSWindowID windowID, bool captureAtNominalResolution)
+{
+    CGSWindowCaptureOptions options = kCGSCaptureIgnoreGlobalClipShape;
+    if (captureAtNominalResolution)
+        options |= kCGSWindowCaptureNominalResolution;
+    RetainPtr<CFArrayRef> windowSnapshotImages = adoptCF(CGSHWCaptureWindowList(CGSMainConnectionID(), &windowID, 1, options));
+
+    if (windowSnapshotImages && CFArrayGetCount(windowSnapshotImages.get()))
+        return checked_cf_cast<CGImageRef>(CFArrayGetValueAtIndex(windowSnapshotImages.get(), 0));
+
+    // Fall back to the non-hardware capture path if we didn't get a snapshot
+    // (which usually happens if the window is fully off-screen).
+    CGWindowImageOption imageOptions = kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque;
+    if (captureAtNominalResolution)
+        imageOptions |= kCGWindowImageNominalResolution;
+    return adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, imageOptions));
+}
+
 - (void)finishedExitFullScreenAnimation:(bool)completed
 {
     if (_fullScreenState == InFullScreen) {
@@ -457,28 +477,42 @@ static const float minVideoWidth = 480 + 20 + 20; // Note: Keep in sync with med
 
     NSResponder *firstResponder = [[self window] firstResponder];
 
-    ALLOW_DEPRECATED_DECLARATIONS_BEGIN
-    // Screen updates to be re-enabled in completeFinishExitFullScreenAnimationAfterRepaint.
-    NSDisableScreenUpdates();
-    ALLOW_DEPRECATED_DECLARATIONS_END
-    _page->setSuppressVisibilityUpdates(true);
-    [[self window] orderOut:self];
-    NSView *contentView = [[self window] contentView];
-    contentView.hidden = YES;
+    [CATransaction begin];
+    [CATransaction setDisableActions:YES];
+    NSRect exitPlaceholderScreenRect = _initialFrame;
+    exitPlaceholderScreenRect.origin.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - NSMaxY(exitPlaceholderScreenRect);
+
+    RetainPtr<CGImageRef> webViewContents = takeWindowSnapshot([[_webView window] windowNumber], true);
+    webViewContents = adoptCF(CGImageCreateWithImageInRect(webViewContents.get(), NSRectToCGRect(exitPlaceholderScreenRect)));
+    
+    _exitPlaceholder = adoptNS([[NSView alloc] initWithFrame:[_webView frame]]);
+    [_exitPlaceholder setWantsLayer: YES];
+    [_exitPlaceholder setAutoresizesSubviews: YES];
+    [_exitPlaceholder setLayerContentsPlacement: NSViewLayerContentsPlacementScaleProportionallyToFit];
+    [_exitPlaceholder setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawNever];
+    [_exitPlaceholder setFrame:[_webView frame]];
+    [[_exitPlaceholder layer] setContents:(__bridge id)webViewContents.get()];
+    [[_webView superview] addSubview:_exitPlaceholder.get() positioned:NSWindowAbove relativeTo:_webView];
+
+    [CATransaction commit];
+    [CATransaction flush];
+
+    [CATransaction begin];
+    [CATransaction setDisableActions:YES];
+    
     [_backgroundView.get().layer removeAllAnimations];
-    ALLOW_DEPRECATED_DECLARATIONS_BEGIN
-    [[_webViewPlaceholder window] setAutodisplay:NO];
-    ALLOW_DEPRECATED_DECLARATIONS_END
+    _page->setSuppressVisibilityUpdates(true);
+    [_webView removeFromSuperview];
+    [_webView setFrame:[_webViewPlaceholder frame]];
+    [_webView setAutoresizingMask:[_webViewPlaceholder autoresizingMask]];
+    [[_webViewPlaceholder superview] addSubview:_webView positioned:NSWindowBelow relativeTo:_webViewPlaceholder.get()];
 
-    [self _replaceView:_webViewPlaceholder.get() with:_webView];
     BEGIN_BLOCK_OBJC_EXCEPTIONS
     [NSLayoutConstraint activateConstraints:self.savedConstraints];
     END_BLOCK_OBJC_EXCEPTIONS
     self.savedConstraints = nil;
     makeResponderFirstResponderIfDescendantOfView(_webView.window, firstResponder, _webView);
 
-    [[_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);
@@ -496,19 +530,32 @@ static const float minVideoWidth = 480 + 20 + 20; // Note: Keep in sync with med
         [self completeFinishExitFullScreenAnimationAfterRepaint];
     });
     _page->forceRepaint(_repaintCallback.copyRef());
+
+    [CATransaction commit];
+    [CATransaction flush];
 }
 
 - (void)completeFinishExitFullScreenAnimationAfterRepaint
 {
+    [CATransaction begin];
+    [CATransaction setDisableActions:YES];
+
+    [_webViewPlaceholder removeFromSuperview];
+    [[self window] orderOut:self];
+    NSView *contentView = [[self window] contentView];
+    contentView.hidden = YES;
+    [_exitPlaceholder removeFromSuperview];
+    [[_exitPlaceholder layer] setContents:nil];
+    _exitPlaceholder = nil;
+    
+    [[_webView window] makeKeyAndOrderFront:self];
+    _webViewPlaceholder = nil;
+    
     _repaintCallback = nullptr;
-    ALLOW_DEPRECATED_DECLARATIONS_BEGIN
-    [[_webView window] setAutodisplay:YES];
-    ALLOW_DEPRECATED_DECLARATIONS_END
-    [[_webView window] displayIfNeeded];
     _page->setSuppressVisibilityUpdates(false);
-    ALLOW_DEPRECATED_DECLARATIONS_BEGIN
-    NSEnableScreenUpdates();
-    ALLOW_DEPRECATED_DECLARATIONS_END
+
+    [CATransaction commit];
+    [CATransaction flush];
 }
 
 - (void)performClose:(id)sender