2010-04-30 Simon Fraser <simon.fraser@apple.com>
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Apr 2010 23:54:24 +0000 (23:54 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Apr 2010 23:54:24 +0000 (23:54 +0000)
        Reviewed by Dan Bernstein.

        <rdar://problem/7477071> REGRESSION: Bad flicker when wheel-scrolling Google Maps, iPad gallery and other sites

        Sites that frequently toggle content in and out of compositing layers (like http://www.tumblr.com/boothed)
        can cause flickering because of unsychronized compositing layer and view-based updates. There were two
        underlying issues:

        1. On SnowLeopard, AppKit can throttle window updates, thus breaking an assumption that
           NSView drawing will happen on the runloop cycle after a repaint. This provided a window
           for the layerSyncRunLoopObserver to fire and commit layer changes too early.

           Fix this by having the layerSyncRunLoopObserver in WebView check to see if a display is pending,
           and not commit layer changes in that case. We'll commit layer changes later when we
           finally draw.

        2. The change in r49269 was wrong; it was attempting to fix an issue that was actually caused
           by -drawRects: coming in for page snapshots. The correct approach is to avoid hitting the
           synchronization and update disabling code in WebHTMLView for draws that are not to the screen.

        * WebView/WebHTMLView.mm:
        (-[WebHTMLView drawRect:]):
        * WebView/WebView.mm:
        (layerSyncRunLoopObserverCallBack):
        (-[WebView _scheduleCompositingLayerSync]):

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

WebKit/mac/ChangeLog
WebKit/mac/WebView/WebHTMLView.mm
WebKit/mac/WebView/WebView.mm

index 368cce6..0ca02c9 100644 (file)
@@ -1,3 +1,31 @@
+2010-04-30  Simon Fraser  <simon.fraser@apple.com>
+
+        Reviewed by Dan Bernstein.
+
+        <rdar://problem/7477071> REGRESSION: Bad flicker when wheel-scrolling Google Maps, iPad gallery and other sites
+
+        Sites that frequently toggle content in and out of compositing layers (like http://www.tumblr.com/boothed)
+        can cause flickering because of unsychronized compositing layer and view-based updates. There were two
+        underlying issues:
+        
+        1. On SnowLeopard, AppKit can throttle window updates, thus breaking an assumption that
+           NSView drawing will happen on the runloop cycle after a repaint. This provided a window
+           for the layerSyncRunLoopObserver to fire and commit layer changes too early.
+           
+           Fix this by having the layerSyncRunLoopObserver in WebView check to see if a display is pending,
+           and not commit layer changes in that case. We'll commit layer changes later when we
+           finally draw.
+           
+        2. The change in r49269 was wrong; it was attempting to fix an issue that was actually caused
+           by -drawRects: coming in for page snapshots. The correct approach is to avoid hitting the
+           synchronization and update disabling code in WebHTMLView for draws that are not to the screen.
+        
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView drawRect:]):
+        * WebView/WebView.mm:
+        (layerSyncRunLoopObserverCallBack):
+        (-[WebView _scheduleCompositingLayerSync]):
+
 2010-04-30  Anders Carlsson  <andersca@apple.com>
 
         Part of the previous part (forgot to save).
index 76e794b..b3b5878 100644 (file)
@@ -3311,16 +3311,14 @@ WEBCORE_COMMAND(yankAndSelect)
 
     if (subviewsWereSetAside)
         [self _setAsideSubviews];
-        
+
 #if USE(ACCELERATED_COMPOSITING)
-    if ([webView _needsOneShotDrawingSynchronization]) {
-        // Disable screen updates so that any layer changes committed here
-        // don't show up on the screen before the window flush at the end
-        // of the current window display, but only if a window flush is actually
-        // going to happen.
-        NSWindow *window = [self window];
-        if ([window viewsNeedDisplay])
-            [window disableScreenUpdatesUntilFlush];
+    // If we're not drawing to the window, we don't want to perturb the delicate synchronization dance.
+    if (!WKCGContextIsBitmapContext(static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]))
+        && [webView _needsOneShotDrawingSynchronization]) {
+        // Disable screen updates to minimize the chances of the race between the CA
+        // display link and AppKit drawing causing flashes.
+        [[self window] disableScreenUpdatesUntilFlush];
         
         // Make sure any layer changes that happened as a result of layout
         // via -viewWillDraw are committed.
index 85a9111..89ab55f 100644 (file)
@@ -5610,6 +5610,13 @@ static WebFrameView *containingFrameView(NSView *view)
 static void layerSyncRunLoopObserverCallBack(CFRunLoopObserverRef, CFRunLoopActivity, void* info)
 {
     WebView* webView = reinterpret_cast<WebView*>(info);
+
+    // An NSWindow may not display in the next runloop cycle after dirtying due to delayed window display logic,
+    // in which case this observer can fire first. So if the window is due for a display, don't commit
+    // layer changes, otherwise they'll show on screen before the view drawing.
+    if ([[webView window] viewsNeedDisplay])
+        return;
+
     if ([webView _syncCompositingChanges])
         [webView _clearLayerSyncLoopObserver];
 }