2009-03-26 Simon Fraser <simon.fraser@apple.com>
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Mar 2009 01:12:01 +0000 (01:12 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Mar 2009 01:12:01 +0000 (01:12 +0000)
        Reviewed by Dave Hyatt

        https://bugs.webkit.org/show_bug.cgi?id=24864

        Change the terminology from "inner content layer" to "direct compositing"
        for cases where we can push an image directly over to the compositing system,
        without having to draw it.

        Clean up much of the code which looks at style to determine if this is possible,
        and fix some bugs when backgrounds change dynamically.

        * rendering/RenderLayerBacking.cpp:
        (WebCore::hasBorderOutlineOrShadow):
        (WebCore::hasBoxDecorations):
        (WebCore::hasBoxDecorationsWithBackgroundImage):
        (WebCore::RenderLayerBacking::canBeSimpleContainerCompositingLayer):
        (WebCore::RenderLayerBacking::canUseDirectCompositing):
        (WebCore::RenderLayerBacking::detectDrawingOptimizations):
        (WebCore::RenderLayerBacking::rendererContentChanged):
        (WebCore::RenderLayerBacking::updateImageContents):
        * rendering/RenderLayerBacking.h:

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

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

index 1243eae..7fe6a9c 100644 (file)
 
         Reviewed by Dave Hyatt
         
+        https://bugs.webkit.org/show_bug.cgi?id=24864
+
+        Change the terminology from "inner content layer" to "direct compositing"
+        for cases where we can push an image directly over to the compositing system,
+        without having to draw it.
+        
+        Clean up much of the code which looks at style to determine if this is possible,
+        and fix some bugs when backgrounds change dynamically.
+        
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::hasBorderOutlineOrShadow):
+        (WebCore::hasBoxDecorations):
+        (WebCore::hasBoxDecorationsWithBackgroundImage):
+        (WebCore::RenderLayerBacking::canBeSimpleContainerCompositingLayer):
+        (WebCore::RenderLayerBacking::canUseDirectCompositing):
+        (WebCore::RenderLayerBacking::detectDrawingOptimizations):
+        (WebCore::RenderLayerBacking::rendererContentChanged):
+        (WebCore::RenderLayerBacking::updateImageContents):
+        * rendering/RenderLayerBacking.h:
+
+2009-03-26  Simon Fraser  <simon.fraser@apple.com>
+
+        Reviewed by Dave Hyatt
+        
         https://bugs.webkit.org/show_bug.cgi?id=23914
 
         Tests: compositing/overflow/ancestor-overflow.html
index f61b976..742483d 100644 (file)
@@ -391,15 +391,19 @@ float RenderLayerBacking::compositingOpacity(float rendererOpacity) const
     return finalOpacity;
 }
 
-// A simple background is either none or a solid color.
-static bool hasSimpleBackground(RenderStyle* style)
+static bool hasBorderOutlineOrShadow(const RenderStyle* style)
 {
-    return !style->hasBackgroundImage();
+    return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow();
 }
 
-static bool hasBorderOutlineOrShadow(RenderStyle* style)
+static bool hasBoxDecorations(const RenderStyle* style)
 {
-    return (style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || (style->boxShadow() != 0));
+    return hasBorderOutlineOrShadow(style) || style->hasBackground();
+}
+
+static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle* style)
+{
+    return hasBorderOutlineOrShadow(style) || style->hasBackgroundImage();
 }
 
 bool RenderLayerBacking::rendererHasBackground() const
@@ -454,8 +458,7 @@ bool RenderLayerBacking::canBeSimpleContainerCompositingLayer() const
     // Reject anything that has a border, a border-radius or outline,
     // or any background (color or image).
     // FIXME: we could optimize layers for simple backgrounds.
-    if (hasBorderOutlineOrShadow(style) ||
-        style->hasBackground())
+    if (hasBoxDecorations(style))
         return false;
 
     // If we have got this far and the renderer has no children, then we're ok.
@@ -472,8 +475,7 @@ bool RenderLayerBacking::canBeSimpleContainerCompositingLayer() const
         
         // Reject anything that has a border, a border-radius or outline,
         // or is not a simple background (no background, or solid color).
-        if (hasBorderOutlineOrShadow(style) ||
-            !hasSimpleBackground(style))
+        if (hasBoxDecorationsWithBackgroundImage(style))
             return false;
         
         // Now look at the body's renderer.
@@ -484,8 +486,7 @@ bool RenderLayerBacking::canBeSimpleContainerCompositingLayer() const
         
         style = bodyObject->style();
         
-        if (hasBorderOutlineOrShadow(style) ||
-            !hasSimpleBackground(style))
+        if (hasBoxDecorationsWithBackgroundImage(style))
             return false;
 
         // Ceck to see if all the body's children are compositing layers.
@@ -555,34 +556,24 @@ bool RenderLayerBacking::hasNonCompositingContent() const
     return false;
 }
 
-// A layer can use an inner content layer if the render layer's object is a replaced object and has no children.
+// A layer can use direct compositing if the render layer's object is a replaced object and has no children.
 // This allows the GraphicsLayer to display the RenderLayer contents directly; it's used for images.
-bool RenderLayerBacking::canUseInnerContentLayer() const
+bool RenderLayerBacking::canUseDirectCompositing() const
 {
     RenderObject* renderObject = renderer();
     
-    // Reject anything that isn't a RenderReplaced.
-    if (!renderObject->isReplaced())
-        return false;
-    
-    if (renderObject->hasMask())
+    // Reject anything that isn't a RenderReplaced, and not an image or video
+    if (!renderObject->isReplaced() || (!renderObject->isImage() && !renderObject->isVideo()))
         return false;
     
-    RenderStyle* style = renderObject->style();
-    
-    // Reject anything that has a background other than a solid color.
-    if (!hasSimpleBackground(style))
+    if (renderObject->hasMask() || renderObject->hasReflection())
         return false;
     
-    // Only optimize images that are unadorned.
-    if (renderObject->isImage())
-        // Reject anything that has a border, a border-radius, outline, margin or padding.
-        return !hasBorderOutlineOrShadow(style) && !style->hasMargin() && !style->hasPadding();
-    
-    return false;
+    // Reject anything that would require the image to be drawn via the GraphicsContext,
+    // like border, shadows etc. Solid background color is OK.
+    return !hasBoxDecorationsWithBackgroundImage(renderObject->style());
 }
     
-    
 // A "simple container layer" is a RenderLayer which has no visible content to render.
 // It may have no children, or all its children may be themselves composited.
 // This is a useful optimization, because it allows us to avoid allocating backing store.
@@ -601,30 +592,23 @@ void RenderLayerBacking::detectDrawingOptimizations()
     bool drawsContent = true;
 
     // Check if a replaced layer can be further simplified.
-    bool hasImageBackgroundColor = false;
-    if (canUseInnerContentLayer()) {
+    if (canUseDirectCompositing()) {
         if (renderer()->isImage()) {
-            RenderImage* imageRenderer = (RenderImage*)renderer();
-            if (imageRenderer && imageRenderer->cachedImage() && imageRenderer->cachedImage()->image())
-                rendererContentChanged();
-            
+            updateImageContents();
             drawsContent = false;
         }
         
-        if (rendererHasBackground()) {
+        if (rendererHasBackground())
             m_graphicsLayer->setBackgroundColor(rendererBackgroundColor());
-            hasImageBackgroundColor = true;
-        }
+        else
+            m_graphicsLayer->clearBackgroundColor();
+
     } else {
+        m_graphicsLayer->clearBackgroundColor();
         m_graphicsLayer->clearContents();
-        drawsContent = true;
         
         if (isSimpleContainerCompositingLayer())
             drawsContent = false;
-        else if (!hasImageBackgroundColor) {
-            // Clear the background color in case we are swapping away from a simple layer.
-            m_graphicsLayer->clearBackgroundColor();
-        }
     }
     
     if (paintingGoesToWindow())
@@ -640,23 +624,34 @@ void RenderLayerBacking::invalidateDrawingOptimizations()
 
 void RenderLayerBacking::rendererContentChanged()
 {
-    if (canUseInnerContentLayer() && renderer()->isImage()) {
-        RenderImage* imageRenderer = (RenderImage*)renderer();
-        if (imageRenderer &&
-            imageRenderer->cachedImage() &&
-            imageRenderer->cachedImage()->image() &&
-            imageRenderer->cachedImage()->isLoaded()) {
-            // We have to wait until the image is fully loaded before setting it on the layer.
-            
-            // This is a no-op if the layer doesn't have an inner layer for the image.
-            m_graphicsLayer->setContentsToImage(imageRenderer->cachedImage()->image());
-            
-            // Image animation is "lazy", in that it automatically stops unless someone is drawing
-            // the image. So we have to kick the animation each time; this has the downside that the
-            // image will keep animating, even if its layer is not visible.
-            imageRenderer->cachedImage()->image()->startAnimation();
-        }
-    }
+    if (canUseDirectCompositing() && renderer()->isImage())
+        updateImageContents();
+}
+
+void RenderLayerBacking::updateImageContents()
+{
+    ASSERT(renderer()->isImage());
+    RenderImage* imageRenderer = static_cast<RenderImage*>(renderer());
+
+    CachedImage* cachedImage = imageRenderer->cachedImage();
+    if (!cachedImage)
+        return;
+
+    Image* image = cachedImage->image();
+    if (!image)
+        return;
+
+    // We have to wait until the image is fully loaded before setting it on the layer.
+    if (!cachedImage->isLoaded())
+        return;
+
+    // This is a no-op if the layer doesn't have an inner layer for the image.
+    m_graphicsLayer->setContentsToImage(image);
+    
+    // Image animation is "lazy", in that it automatically stops unless someone is drawing
+    // the image. So we have to kick the animation each time; this has the downside that the
+    // image will keep animating, even if its layer is not visible.
+    image->startAnimation();
 }
 
 FloatPoint3D RenderLayerBacking::computeTransformOrigin(const IntRect& borderBox) const
index 496f445..46b81ad 100644 (file)
@@ -140,7 +140,8 @@ private:
     bool isSimpleContainerCompositingLayer();
     // Returns true if we can optimize the RenderLayer to draw the replaced content
     // directly into a compositing buffer
-    bool canUseInnerContentLayer() const;
+    bool canUseDirectCompositing() const;
+    void updateImageContents();
 
     bool rendererHasBackground() const;
     const Color& rendererBackgroundColor() const;