Convert the compositing overlap map to use LayoutRects
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 7 Feb 2015 01:11:07 +0000 (01:11 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 7 Feb 2015 01:11:07 +0000 (01:11 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141346
Source/WebCore:

rdar://problem/18206365

Reviewed by Zalan Bujtas.

If two compositing layers were adjoining but not overlapping, but happened to
have non-integral offsets, then using enclosing IntRects in the overlap map
would cause us to think they are overlapping, and create unnecessary backing store.

Fix by converting the overlap map to use LayoutRects.

Test: compositing/layer-creation/subpixel-adjacent-layers-overlap.html

* rendering/RenderLayerCompositor.cpp:
(WebCore::OverlapMapContainer::add):
(WebCore::OverlapMapContainer::overlapsLayers):
(WebCore::RenderLayerCompositor::OverlapMap::add):
(WebCore::RenderLayerCompositor::OverlapMap::overlapsLayers):
(WebCore::RenderLayerCompositor::OverlapMap::RectList::append):
(WebCore::RenderLayerCompositor::OverlapMap::RectList::intersects):
(WebCore::RenderLayerCompositor::logLayerInfo):
(WebCore::RenderLayerCompositor::addToOverlapMap):
(WebCore::RenderLayerCompositor::addToOverlapMapRecursive):
(WebCore::RenderLayerCompositor::computeCompositingRequirements):
* rendering/RenderLayerCompositor.h:

LayoutTests:

Reviewed by Zalan Bujtas.

Test with adjacent layers on non-pixel boundaries.

* compositing/layer-creation/subpixel-adjacent-layers-overlap-expected.txt: Added.
* compositing/layer-creation/subpixel-adjacent-layers-overlap.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/compositing/layer-creation/subpixel-adjacent-layers-overlap-expected.txt [new file with mode: 0644]
LayoutTests/compositing/layer-creation/subpixel-adjacent-layers-overlap.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderLayerCompositor.h

index 00b9ad6..7b03ca8 100644 (file)
@@ -1,3 +1,15 @@
+2015-02-06  Simon Fraser  <simon.fraser@apple.com>
+
+        Convert the compositing overlap map to use LayoutRects
+        https://bugs.webkit.org/show_bug.cgi?id=141346
+
+        Reviewed by Zalan Bujtas.
+        
+        Test with adjacent layers on non-pixel boundaries.
+
+        * compositing/layer-creation/subpixel-adjacent-layers-overlap-expected.txt: Added.
+        * compositing/layer-creation/subpixel-adjacent-layers-overlap.html: Added.
+
 2015-02-06  Bartlomiej Gajda  <b.gajda@samsung.com>
 
         [MSE] Implement Append Error algorithm.
diff --git a/LayoutTests/compositing/layer-creation/subpixel-adjacent-layers-overlap-expected.txt b/LayoutTests/compositing/layer-creation/subpixel-adjacent-layers-overlap-expected.txt
new file mode 100644 (file)
index 0000000..b1f0707
--- /dev/null
@@ -0,0 +1,20 @@
+Here is some text
+
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (children 1
+        (GraphicsLayer
+          (position 0.00 44.00)
+          (anchor 0.50 0.50)
+          (bounds 200.00 201.00)
+        )
+      )
+    )
+  )
+)
+
diff --git a/LayoutTests/compositing/layer-creation/subpixel-adjacent-layers-overlap.html b/LayoutTests/compositing/layer-creation/subpixel-adjacent-layers-overlap.html
new file mode 100644 (file)
index 0000000..087bb28
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        body {
+            margin: 0;
+        }
+        .box {
+            height: 200px;
+            width: 200px;
+            background-color: silver;
+            position: relative;
+        }
+        .composited {
+            -webkit-transform: translateZ(0);
+        }
+        
+        p {
+            height: 12.345px; /* Subpixel height */
+        }
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        function runTest()
+        {
+            if (window.testRunner)
+              document.getElementById('layers').innerText = window.internals.layerTreeAsText(document);
+        }
+        window.addEventListener('load', runTest, false);
+    </script>
+</head>
+<body>
+<p>Here is some text</p>
+<div class="composited box">
+</div>
+<div class="box">
+</div>
+<pre id="layers"></pre>
+</body>
+</html>
index b9cf9e7..2c21297 100644 (file)
@@ -1,3 +1,32 @@
+2015-02-06  Simon Fraser  <simon.fraser@apple.com>
+
+        Convert the compositing overlap map to use LayoutRects
+        https://bugs.webkit.org/show_bug.cgi?id=141346
+        rdar://problem/18206365
+
+        Reviewed by Zalan Bujtas.
+        
+        If two compositing layers were adjoining but not overlapping, but happened to
+        have non-integral offsets, then using enclosing IntRects in the overlap map
+        would cause us to think they are overlapping, and create unnecessary backing store.
+        
+        Fix by converting the overlap map to use LayoutRects.
+
+        Test: compositing/layer-creation/subpixel-adjacent-layers-overlap.html
+
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::OverlapMapContainer::add):
+        (WebCore::OverlapMapContainer::overlapsLayers):
+        (WebCore::RenderLayerCompositor::OverlapMap::add):
+        (WebCore::RenderLayerCompositor::OverlapMap::overlapsLayers):
+        (WebCore::RenderLayerCompositor::OverlapMap::RectList::append):
+        (WebCore::RenderLayerCompositor::OverlapMap::RectList::intersects):
+        (WebCore::RenderLayerCompositor::logLayerInfo):
+        (WebCore::RenderLayerCompositor::addToOverlapMap):
+        (WebCore::RenderLayerCompositor::addToOverlapMapRecursive):
+        (WebCore::RenderLayerCompositor::computeCompositingRequirements):
+        * rendering/RenderLayerCompositor.h:
+
 2015-02-06  Andreas Kling  <akling@apple.com>
 
         Ref-ify various getters that return HTMLCollection.
index 2755cf6..672eb26 100644 (file)
@@ -68,8 +68,6 @@
 
 #if PLATFORM(IOS)
 #include "LegacyTileCache.h"
-#include "MainFrame.h"
-#include "Region.h"
 #include "RenderScrollbar.h"
 #endif
 
@@ -104,13 +102,13 @@ using namespace HTMLNames;
 
 class OverlapMapContainer {
 public:
-    void add(const IntRect& bounds)
+    void add(const LayoutRect& bounds)
     {
         m_layerRects.append(bounds);
         m_boundingBox.unite(bounds);
     }
 
-    bool overlapsLayers(const IntRect& bounds) const
+    bool overlapsLayers(const LayoutRect& bounds) const
     {
         // Checking with the bounding box will quickly reject cases when
         // layers are created for lists of items going in one direction and
@@ -130,8 +128,8 @@ public:
         m_boundingBox.unite(otherContainer.m_boundingBox);
     }
 private:
-    Vector<IntRect> m_layerRects;
-    IntRect m_boundingBox;
+    Vector<LayoutRect> m_layerRects;
+    LayoutRect m_boundingBox;
 };
 
 class RenderLayerCompositor::OverlapMap {
@@ -146,7 +144,7 @@ public:
         pushCompositingContainer();
     }
 
-    void add(const RenderLayer* layer, const IntRect& bounds)
+    void add(const RenderLayer* layer, const LayoutRect& bounds)
     {
         // Layers do not contribute to overlap immediately--instead, they will
         // contribute to overlap as soon as their composited ancestor has been
@@ -161,7 +159,7 @@ public:
         return m_layers.contains(layer);
     }
 
-    bool overlapsLayers(const IntRect& bounds) const
+    bool overlapsLayers(const LayoutRect& bounds) const
     {
         return m_overlapStack.last().overlapsLayers(bounds);
     }
@@ -186,10 +184,10 @@ public:
 
 private:
     struct RectList {
-        Vector<IntRect> rects;
-        IntRect boundingRect;
+        Vector<LayoutRect> rects;
+        LayoutRect boundingRect;
         
-        void append(const IntRect& rect)
+        void append(const LayoutRect& rect)
         {
             rects.append(rect);
             boundingRect.unite(rect);
@@ -201,7 +199,7 @@ private:
             boundingRect.unite(rectList.boundingRect);
         }
         
-        bool intersects(const IntRect& rect) const
+        bool intersects(const LayoutRect& rect) const
         {
             if (!rects.size() || !boundingRect.intersects(rect))
                 return false;
@@ -827,9 +825,12 @@ void RenderLayerCompositor::logLayerInfo(const RenderLayer& layer, int depth)
         m_secondaryBackingStoreBytes += backing->backingStoreMemoryEstimate();
     }
 
+    LayoutRect absoluteBounds = backing->compositedBounds();
+    absoluteBounds.move(layer.offsetFromAncestor(m_renderView.layer()));
+    
     StringBuilder logString;
-    logString.append(String::format("%*p %dx%d %.2fKB", 12 + depth * 2, &layer,
-        backing->compositedBounds().width().round(), backing->compositedBounds().height().round(),
+    logString.append(String::format("%*p (%.6f,%.6f-%.6f,%.6f) %.2fKB", 12 + depth * 2, &layer,
+        absoluteBounds.x().toFloat(), absoluteBounds.y().toFloat(), absoluteBounds.maxX().toFloat(), absoluteBounds.maxY().toFloat(),
         backing->backingStoreMemoryEstimate() / 1024));
     
     logString.append(" (");
@@ -1105,7 +1106,7 @@ RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const Rend
     return nullptr;
 }
 
-void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer& layer, IntRect& layerBounds, bool& boundsComputed)
+void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer& layer, LayoutRect& layerBounds, bool& boundsComputed)
 {
     if (layer.isRootLayer())
         return;
@@ -1113,14 +1114,14 @@ void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer&
     if (!boundsComputed) {
         // FIXME: If this layer's overlap bounds include its children, we don't need to add its
         // children's bounds to the overlap map.
-        layerBounds = enclosingIntRect(overlapMap.geometryMap().absoluteRect(layer.overlapBounds()));
+        layerBounds = enclosingLayoutRect(overlapMap.geometryMap().absoluteRect(layer.overlapBounds()));
         // Empty rects never intersect, but we need them to for the purposes of overlap testing.
         if (layerBounds.isEmpty())
-            layerBounds.setSize(IntSize(1, 1));
+            layerBounds.setSize(LayoutSize(1, 1));
         boundsComputed = true;
     }
 
-    IntRect clipRect = snappedIntRect(layer.backgroundClipRect(RenderLayer::ClipRectsContext(&rootRenderLayer(), AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions.
+    LayoutRect clipRect = layer.backgroundClipRect(RenderLayer::ClipRectsContext(&rootRenderLayer(), AbsoluteClipRects)).rect(); // FIXME: Incorrect for CSS regions.
 
     // On iOS, pageScaleFactor() is not applied by RenderView, so we should not scale here.
     // FIXME: Set Settings::delegatesPageScaling to true for iOS.
@@ -1142,7 +1143,7 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren
     if (ancestorLayer)
         overlapMap.geometryMap().pushMappingsToAncestor(&layer, ancestorLayer);
     
-    IntRect bounds;
+    LayoutRect bounds;
     bool haveComputedBounds = false;
     addToOverlapMap(overlapMap, layer, bounds, haveComputedBounds);
 
@@ -1227,16 +1228,16 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestor
 
     RenderLayer::IndirectCompositingReason compositingReason = compositingState.m_subtreeIsCompositing ? RenderLayer::IndirectCompositingReason::Stacking : RenderLayer::IndirectCompositingReason::None;
     bool haveComputedBounds = false;
-    IntRect absBounds;
+    LayoutRect absBounds;
 
     // If we know for sure the layer is going to be composited, don't bother looking it up in the overlap map
     if (!willBeComposited && !overlapMap.isEmpty() && compositingState.m_testingOverlap) {
         // If we're testing for overlap, we only need to composite if we overlap something that is already composited.
-        absBounds = enclosingIntRect(overlapMap.geometryMap().absoluteRect(layer.overlapBounds()));
+        absBounds = enclosingLayoutRect(overlapMap.geometryMap().absoluteRect(layer.overlapBounds()));
 
         // Empty rects never intersect, but we need them to for the purposes of overlap testing.
         if (absBounds.isEmpty())
-            absBounds.setSize(IntSize(1, 1));
+            absBounds.setSize(LayoutSize(1, 1));
         haveComputedBounds = true;
         compositingReason = overlapMap.overlapsLayers(absBounds) ? RenderLayer::IndirectCompositingReason::Overlap : RenderLayer::IndirectCompositingReason::None;
     }
index 9e68941..97c7c9d 100644 (file)
@@ -333,7 +333,7 @@ private:
     // Repaint this and its child layers.
     void recursiveRepaintLayer(RenderLayer&);
 
-    void addToOverlapMap(OverlapMap&, RenderLayer&, IntRect& layerBounds, bool& boundsComputed);
+    void addToOverlapMap(OverlapMap&, RenderLayer&, LayoutRect& layerBounds, bool& boundsComputed);
     void addToOverlapMapRecursive(OverlapMap&, RenderLayer&, RenderLayer* ancestorLayer = nullptr);
 
     void updateCompositingLayersTimerFired();