pinch-to-zoom and double-tap flicker when using the new scrolling model
authorandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Mar 2012 04:33:16 +0000 (04:33 +0000)
committerandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Mar 2012 04:33:16 +0000 (04:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=80368
<rdar://problem/10866221>

Reviewed by Sam Weinig.

Source/WebCore:

In order to work better with zooming, make the tile cache undo the scale transformation
and handle the scaling manually. This avoids creating huge tile backing stores when zoomed in.

* platform/graphics/ca/mac/TileCache.mm:
(WebCore::TileCache::TileCache):
Initialize m_scale to 1.

(WebCore::TileCache::setNeedsDisplayInRect):
Scale the given rect appropriately.

(WebCore::TileCache::drawLayer):
Apply a scale context transform.

(WebCore::TileCache::setScale):
No longer set the contents scale. Instead, update the scale and revalidate the tiles.

(WebCore::TileCache::revalidateTiles):
Return early if the bounds are empty. This avoids showing a single tile if that happens due to a race condition.

(WebCore::TileCache::getTileIndexRangeForRect):
Apply the scale to the bounds.

(WebCore::TileCache::createTileLayer):
Don't set the contents scale.

* platform/graphics/ca/mac/WebTileCacheLayer.mm:
(-[WebTileCacheLayer setContentsScale:]):
Call TileCache::setScale.

* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateCompositedBounds):
Make sure to give the tile cache layer sane composited bounds, even if the page has absolutely positioned
elements that are outside of the page.

Source/WebKit2:

Add a way for drawing areas to respond to callback based force repaint requests asynchronously.
This is currently needed for the tiled drawing area when there might be outstanding scroll updates
that are sent from the scrolling thread to the main thread and we need to ensure that they're processed
before sending a message back.

* WebProcess/WebPage/DrawingArea.h:
(WebKit::DrawingArea::forceRepaintAsync):
Add new member function.

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::forceRepaint):
Try forceRepaintAsync first.

* WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
(WebKit::forceRepaintAndSendMessage):
Force the repaint and send the message.

(WebKit::dispatchBackToMainThread):
Dispatch a call to forceRepaintAndSendMessage to the main thread.

(WebKit::TiledCoreAnimationDrawingArea::forceRepaintAsync):
Dispatch a function on the scrolling thread. Its sole purpose is to dispatch a function back to the
main thread, ensuring that all previously dispatched functions have been executed.

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/ca/mac/TileCache.h
Source/WebCore/platform/graphics/ca/mac/TileCache.mm
Source/WebCore/platform/graphics/ca/mac/WebTileCacheLayer.mm
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/WebPage/DrawingArea.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.h
Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm

index 11d8aac..16f47a4 100644 (file)
@@ -1,3 +1,45 @@
+2012-03-05  Anders Carlsson  <andersca@apple.com>
+
+        pinch-to-zoom and double-tap flicker when using the new scrolling model
+        https://bugs.webkit.org/show_bug.cgi?id=80368
+        <rdar://problem/10866221>
+
+        Reviewed by Sam Weinig.
+
+        In order to work better with zooming, make the tile cache undo the scale transformation
+        and handle the scaling manually. This avoids creating huge tile backing stores when zoomed in.
+
+        * platform/graphics/ca/mac/TileCache.mm:
+        (WebCore::TileCache::TileCache):
+        Initialize m_scale to 1.
+
+        (WebCore::TileCache::setNeedsDisplayInRect):
+        Scale the given rect appropriately.
+
+        (WebCore::TileCache::drawLayer):
+        Apply a scale context transform.
+
+        (WebCore::TileCache::setScale):
+        No longer set the contents scale. Instead, update the scale and revalidate the tiles.
+
+        (WebCore::TileCache::revalidateTiles):
+        Return early if the bounds are empty. This avoids showing a single tile if that happens due to a race condition.
+
+        (WebCore::TileCache::getTileIndexRangeForRect):
+        Apply the scale to the bounds.
+
+        (WebCore::TileCache::createTileLayer):
+        Don't set the contents scale.
+
+        * platform/graphics/ca/mac/WebTileCacheLayer.mm:
+        (-[WebTileCacheLayer setContentsScale:]):
+        Call TileCache::setScale.
+
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::updateCompositedBounds):
+        Make sure to give the tile cache layer sane composited bounds, even if the page has absolutely positioned
+        elements that are outside of the page.
+
 2012-03-05  Leo Yang  <leo.yang@torchmobile.com.cn>
 
         GraphicsContext3D.h should include RefCounted.h explicitly
index f28a2d3..714d3c9 100644 (file)
@@ -56,7 +56,8 @@ public:
     void setNeedsDisplay();
     void setNeedsDisplayInRect(const IntRect&);
     void drawLayer(WebTileLayer*, CGContextRef);
-    void setContentsScale(CGFloat);
+
+    void setScale(CGFloat);
 
     bool acceleratesDrawing() const { return m_acceleratesDrawing; }
     void setAcceleratesDrawing(bool);
@@ -99,6 +100,8 @@ private:
     Timer<TileCache> m_tileRevalidationTimer;
     IntRect m_tileCoverageRect;
 
+    CGFloat m_scale;
+
     bool m_acceleratesDrawing;
 
     RetainPtr<CGColorRef> m_tileDebugBorderColor;
index 8b577b2..7d21184 100644 (file)
@@ -54,6 +54,7 @@ TileCache::TileCache(WebTileCacheLayer* tileCacheLayer, const IntSize& tileSize)
     , m_tileContainerLayer(adoptCF([[CALayer alloc] init]))
     , m_tileSize(tileSize)
     , m_tileRevalidationTimer(this, &TileCache::tileRevalidationTimerFired)
+    , m_scale(1)
     , m_acceleratesDrawing(false)
     , m_tileDebugBorderWidth(0)
 {
@@ -90,10 +91,13 @@ void TileCache::setNeedsDisplayInRect(const IntRect& rect)
     if (m_tiles.isEmpty())
         return;
 
+    IntRect scaledRect = rect;
+    scaledRect.scale(m_scale);
+
     // Find the tiles that need to be invalidated.
     TileIndex topLeft;
     TileIndex bottomRight;
-    getTileIndexRangeForRect(intersection(rect, m_tileCoverageRect), topLeft, bottomRight);
+    getTileIndexRangeForRect(intersection(scaledRect, m_tileCoverageRect), topLeft, bottomRight);
 
     for (int y = topLeft.y(); y <= bottomRight.y(); ++y) {
         for (int x = topLeft.x(); x <= bottomRight.x(); ++x) {
@@ -126,6 +130,7 @@ void TileCache::drawLayer(WebTileLayer* layer, CGContextRef context)
 
     CGPoint layerOrigin = [layer frame].origin;
     CGContextTranslateCTM(context, -layerOrigin.x, -layerOrigin.y);
+    CGContextScaleCTM(context, m_scale, m_scale);
     drawLayerContents(context, layer, platformLayer);
 
     CGContextRestoreGState(context);
@@ -162,17 +167,22 @@ void TileCache::drawLayer(WebTileLayer* layer, CGContextRef context)
     CGContextRestoreGState(context);
 }
 
-void TileCache::setContentsScale(CGFloat contentsScale)
+void TileCache::setScale(CGFloat scale)
 {
+    if (m_scale == scale)
+        return;
+
 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
-    for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it) {
-        [it->second.get() setContentsScale:contentsScale];
+    m_scale = scale;
+    [m_tileContainerLayer.get() setTransform:CATransform3DMakeScale(1 / m_scale, 1 / m_scale, 1)];
+
+    revalidateTiles();
+
+    for (TileMap::const_iterator it = m_tiles.begin(), end = m_tiles.end(); it != end; ++it)
         [it->second.get() setNeedsDisplay];
-    }
 
     PlatformCALayer* platformLayer = PlatformCALayer::platformCALayer(m_tileCacheLayer);
     platformLayer->owner()->platformCALayerDidCreateTiles();
-    revalidateTiles();
 #else
     UNUSED_PARAM(contentsScale);
 #endif
@@ -234,7 +244,9 @@ IntRect TileCache::rectForTileIndex(const TileIndex& tileIndex) const
 
 void TileCache::getTileIndexRangeForRect(const IntRect& rect, TileIndex& topLeft, TileIndex& bottomRight)
 {
-    IntRect clampedRect = intersection(rect, bounds());
+    IntRect clampedRect = bounds();
+    clampedRect.scale(m_scale);
+    clampedRect.intersect(rect);
 
     topLeft.setX(max(clampedRect.x() / m_tileSize.width(), 0));
     topLeft.setY(max(clampedRect.y() / m_tileSize.height(), 0));
@@ -263,7 +275,7 @@ void TileCache::revalidateTiles()
     if (!platformLayer)
         return;
 
-    if (m_visibleRect.isEmpty())
+    if (m_visibleRect.isEmpty() || bounds().isEmpty())
         return;
 
     IntRect tileCoverageRect = m_visibleRect;
@@ -351,7 +363,6 @@ RetainPtr<WebTileLayer> TileCache::createTileLayer()
     [layer.get() setEdgeAntialiasingMask:0];
 
 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
-    [layer.get() setContentsScale:[m_tileCacheLayer contentsScale]];
     [layer.get() setAcceleratesDrawing:m_acceleratesDrawing];
 #endif
 
index 695c478..83abb72 100644 (file)
@@ -103,16 +103,7 @@ using namespace WebCore;
 
 - (void)setContentsScale:(CGFloat)contentsScale
 {
-#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
-    CGFloat oldContentsScale = [self contentsScale];
-
-    [super setContentsScale:contentsScale];
-
-    if (contentsScale != oldContentsScale)
-        _tileCache->setContentsScale(contentsScale);
-#else
-    UNUSED_PARAM(contentsScale);
-#endif
+    _tileCache->setScale(contentsScale);
 }
 
 - (CALayer *)tileContainerLayer
index f559970..befd74c 100644 (file)
@@ -236,7 +236,7 @@ void RenderLayerBacking::updateCompositedBounds()
     // We'd need RenderObject::convertContainerToLocalQuad(), which doesn't yet exist.  If this
     // is a fullscreen renderer, don't clip to the viewport, as the renderer will be asked to
     // display outside of the viewport bounds.
-    if (compositor()->compositingConsultsOverlap() && !layerOrAncestorIsTransformed(m_owningLayer) 
+    if (compositor()->compositingConsultsOverlap() && (!layerOrAncestorIsTransformed(m_owningLayer) || m_usingTiledCacheLayer)
 #if ENABLE(FULLSCREEN_API)
         && !layerOrAncestorIsFullScreen(m_owningLayer)
 #endif
index b6d31d6..368658f 100644 (file)
@@ -1,3 +1,35 @@
+2012-03-05  Anders Carlsson  <andersca@apple.com>
+
+        pinch-to-zoom and double-tap flicker when using the new scrolling model
+        https://bugs.webkit.org/show_bug.cgi?id=80368
+        <rdar://problem/10866221>
+
+        Reviewed by Sam Weinig.
+
+        Add a way for drawing areas to respond to callback based force repaint requests asynchronously.
+        This is currently needed for the tiled drawing area when there might be outstanding scroll updates
+        that are sent from the scrolling thread to the main thread and we need to ensure that they're processed
+        before sending a message back.
+
+        * WebProcess/WebPage/DrawingArea.h:
+        (WebKit::DrawingArea::forceRepaintAsync):
+        Add new member function.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::forceRepaint):
+        Try forceRepaintAsync first.
+
+        * WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:
+        (WebKit::forceRepaintAndSendMessage):
+        Force the repaint and send the message.
+
+        (WebKit::dispatchBackToMainThread):
+        Dispatch a call to forceRepaintAndSendMessage to the main thread.
+
+        (WebKit::TiledCoreAnimationDrawingArea::forceRepaintAsync):
+        Dispatch a function on the scrolling thread. Its sole purpose is to dispatch a function back to the
+        main thread, ensuring that all previously dispatched functions have been executed.
+
 2012-03-05  Enrica Casucci  <enrica@apple.com>
 
         Can't type on some websites (plug-ins steal key events).
index 2fa3598..2ee6557 100644 (file)
@@ -66,6 +66,7 @@ public:
     // FIXME: These should be pure virtual.
     virtual void pageBackgroundTransparencyChanged() { }
     virtual void forceRepaint() { }
+    virtual bool forceRepaintAsync(uint64_t callbackID) { return false; }
     virtual void setLayerTreeStateIsFrozen(bool) { }
     virtual bool layerTreeStateIsFrozen() const { return false; }
 
index 1c87173..a69f0d7 100644 (file)
@@ -1821,6 +1821,9 @@ void WebPage::forceRepaintWithoutCallback()
 
 void WebPage::forceRepaint(uint64_t callbackID)
 {
+    if (m_drawingArea->forceRepaintAsync(callbackID))
+        return;
+
     forceRepaintWithoutCallback();
     send(Messages::WebPageProxy::VoidCallback(callbackID));
 }
index 3b892bf..a86413f 100644 (file)
@@ -53,6 +53,7 @@ private:
     virtual void scroll(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset) OVERRIDE;
 
     virtual void forceRepaint() OVERRIDE;
+    virtual bool forceRepaintAsync(uint64_t callbackID) OVERRIDE;
     virtual void setLayerTreeStateIsFrozen(bool) OVERRIDE;
     virtual bool layerTreeStateIsFrozen() const OVERRIDE;
     virtual void setRootCompositingLayer(WebCore::GraphicsLayer*) OVERRIDE;
index ce6e21d..ddb4902 100644 (file)
@@ -31,6 +31,7 @@
 #import "LayerHostingContext.h"
 #import "LayerTreeContext.h"
 #import "WebPage.h"
+#import "WebPageProxyMessages.h"
 #import "WebProcess.h"
 #import <QuartzCore/QuartzCore.h>
 #import <WebCore/Frame.h>
@@ -40,7 +41,9 @@
 #import <WebCore/RenderLayerCompositor.h>
 #import <WebCore/RenderView.h>
 #import <WebCore/ScrollingCoordinator.h>
+#import <WebCore/ScrollingThread.h>
 #import <WebCore/Settings.h>
+#import <wtf/MainThread.h>
 
 @interface CATransaction (Details)
 + (void)synchronize;
@@ -125,6 +128,36 @@ void TiledCoreAnimationDrawingArea::forceRepaint()
     [CATransaction synchronize];
 }
 
+#if ENABLE(THREADED_SCROLLING)
+static void forceRepaintAndSendMessage(uint64_t webPageID, uint64_t callbackID)
+{
+    WebPage* webPage = WebProcess::shared().webPage(webPageID);
+    if (!webPage)
+        return;
+
+    webPage->drawingArea()->forceRepaint();
+    webPage->send(Messages::WebPageProxy::VoidCallback(callbackID));
+}
+
+static void dispatchBackToMainThread(uint64_t webPageID, uint64_t callbackID)
+{
+    callOnMainThread(bind(forceRepaintAndSendMessage, webPageID, callbackID));
+}
+#endif
+
+bool TiledCoreAnimationDrawingArea::forceRepaintAsync(uint64_t callbackID)
+{
+#if ENABLE(THREADED_SCROLLING)
+    if (m_layerTreeStateIsFrozen)
+        return false;
+
+    ScrollingThread::dispatch(bind(dispatchBackToMainThread, m_webPage->pageID(), callbackID));
+    return true;
+#else
+    return false;
+#endif
+}
+
 void TiledCoreAnimationDrawingArea::setLayerTreeStateIsFrozen(bool layerTreeStateIsFrozen)
 {
     if (m_layerTreeStateIsFrozen == layerTreeStateIsFrozen)