Clarify the behavior of composited canvases
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Dec 2013 03:48:10 +0000 (03:48 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 Dec 2013 03:48:10 +0000 (03:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=126042

Reviewed by Tim Horton.

Different platforms composite 2D and 3D canvases in different ways.

"Accelerated 2D" canvases, and WebGL are always set as GraphicsLayer
contents.

"IOSurface" canvases (Mac and iOS-only) get a compositing layer, but
paint into it (because this is fast, and a convenient way to get
synchronization).

So make these behaviors explicit in RenderLayerBacking and RenderLayerCompositor.
No behavior changes on OS X, bug fix on iOS.

* rendering/RenderLayerBacking.cpp:
(WebCore::canvasCompositingStrategy):
(WebCore::RenderLayerBacking::updateGraphicsLayerConfiguration):
(WebCore::RenderLayerBacking::containsPaintedContent):
(WebCore::RenderLayerBacking::contentChanged):
* rendering/RenderLayerBacking.h:
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::requiresCompositingForCanvas):

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

Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebCore/rendering/RenderLayerBacking.h
Source/WebCore/rendering/RenderLayerCompositor.cpp

index 65ea2f0..54fca39 100644 (file)
@@ -1,3 +1,31 @@
+2013-12-19  Simon Fraser  <simon.fraser@apple.com>
+
+        Clarify the behavior of composited canvases
+        https://bugs.webkit.org/show_bug.cgi?id=126042
+
+        Reviewed by Tim Horton.
+
+        Different platforms composite 2D and 3D canvases in different ways.
+        
+        "Accelerated 2D" canvases, and WebGL are always set as GraphicsLayer
+        contents.
+        
+        "IOSurface" canvases (Mac and iOS-only) get a compositing layer, but
+        paint into it (because this is fast, and a convenient way to get
+        synchronization).
+        
+        So make these behaviors explicit in RenderLayerBacking and RenderLayerCompositor.
+        No behavior changes on OS X, bug fix on iOS.
+
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::canvasCompositingStrategy):
+        (WebCore::RenderLayerBacking::updateGraphicsLayerConfiguration):
+        (WebCore::RenderLayerBacking::containsPaintedContent):
+        (WebCore::RenderLayerBacking::contentChanged):
+        * rendering/RenderLayerBacking.h:
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::requiresCompositingForCanvas):
+
 2013-12-19  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Add InspectorFrontendHost.debuggableType to let the frontend know it's backend is JavaScript or Web
index 1295a06..ebc01d1 100644 (file)
@@ -81,18 +81,23 @@ using namespace HTMLNames;
 static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle*);
 static IntRect clipBox(RenderBox& renderer);
 
-static inline bool isAcceleratedCanvas(RenderObject* renderer)
+CanvasCompositingStrategy canvasCompositingStrategy(const RenderObject& renderer)
 {
-#if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS)
-    if (renderer->isCanvas()) {
-        const HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer->node());
-        if (CanvasRenderingContext* context = canvas->renderingContext())
-            return context->isAccelerated();
-    }
+    ASSERT(renderer.isCanvas());
+    
+    const HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer.node());
+    CanvasRenderingContext* context = canvas->renderingContext();
+    if (!context || !context->isAccelerated())
+        return UnacceleratedCanvas;
+    
+    if (context->is3d())
+        return CanvasAsLayerContents;
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+    return CanvasAsLayerContents;
 #else
-    UNUSED_PARAM(renderer);
+    return CanvasPaintedToLayer; // On Mac and iOS we paint accelerated canvases into their layers.
 #endif
-    return false;
 }
 
 // Get the scrolling coordinator in a way that works inside RenderLayerBacking's destructor.
@@ -626,7 +631,7 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration()
     }
 #endif
 #if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS)
-    else if (isAcceleratedCanvas(&renderer())) {
+    else if (renderer().isCanvas() && canvasCompositingStrategy(renderer()) == CanvasAsLayerContents) {
         const HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer().element());
         if (CanvasRenderingContext* context = canvas->renderingContext())
             m_graphicsLayer->setContentsToCanvas(context->platformLayer());
@@ -1832,9 +1837,9 @@ bool RenderLayerBacking::containsPaintedContent(bool isSimpleContainer) const
     if (renderer().isVideo() && toRenderVideo(renderer()).shouldDisplayVideo())
         return m_owningLayer.hasBoxDecorationsOrBackground();
 #endif
-#if PLATFORM(MAC) && !PLATFORM(IOS) && USE(CA)
-#elif ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS) || PLATFORM(IOS_SIMULATOR)
-    if (isAcceleratedCanvas(&renderer()))
+
+#if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS)
+    if (renderer().isCanvas() && canvasCompositingStrategy(renderer()) == CanvasAsLayerContents)
         return m_owningLayer.hasBoxDecorationsOrBackground();
 #endif
 
@@ -1883,7 +1888,7 @@ void RenderLayerBacking::contentChanged(ContentChangeType changeType)
     }
 
 #if ENABLE(WEBGL) || ENABLE(ACCELERATED_2D_CANVAS)
-    if ((changeType == CanvasChanged || changeType == CanvasPixelsChanged) && isAcceleratedCanvas(&renderer())) {
+    if ((changeType == CanvasChanged || changeType == CanvasPixelsChanged) && renderer().isCanvas() && canvasCompositingStrategy(renderer()) == CanvasAsLayerContents) {
         m_graphicsLayer->setContentsNeedsDisplay();
         return;
     }
index 6179687..3b3f0b1 100644 (file)
@@ -328,6 +328,13 @@ private:
     static bool m_creatingPrimaryGraphicsLayer;
 };
 
+enum CanvasCompositingStrategy {
+    UnacceleratedCanvas,
+    CanvasPaintedToLayer,
+    CanvasAsLayerContents
+};
+CanvasCompositingStrategy canvasCompositingStrategy(const RenderObject&);
+
 } // namespace WebCore
 
 #endif // USE(ACCELERATED_COMPOSITING)
index 61e49da..a1f46da 100644 (file)
@@ -2263,13 +2263,14 @@ bool RenderLayerCompositor::requiresCompositingForCanvas(RenderLayerModelObject&
         return false;
 
     if (renderer.isCanvas()) {
-        HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer.element());
 #if USE(COMPOSITING_FOR_SMALL_CANVASES)
         bool isCanvasLargeEnoughToForceCompositing = true;
 #else
+        HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer.element());
         bool isCanvasLargeEnoughToForceCompositing = canvas->size().area() >= canvasAreaThresholdRequiringCompositing;
 #endif
-        return canvas->renderingContext() && canvas->renderingContext()->isAccelerated() && (canvas->renderingContext()->is3d() || isCanvasLargeEnoughToForceCompositing);
+        CanvasCompositingStrategy compositingStrategy = canvasCompositingStrategy(renderer);
+        return compositingStrategy == CanvasAsLayerContents || (compositingStrategy == CanvasPaintedToLayer && isCanvasLargeEnoughToForceCompositing);
     }
 
     return false;