DeprecatedPaintLayerStackingNode should walk DPL

https://codereview.chromium.org/1199413006 changed the way we
collect DeprecatedPaintLayers for the purpose of painting.
The change made the implicit assumptions that stacking contexts
would have DeprecatedPaintLayer, else there is no way we could
correctly paint. It turns out that this is not an assumption
that holds in our code. The reason is that some LayoutObject
just can't have DeprecatedPaintLayer (any objects that are not
LayoutBoxModelObject) or they don't want one (LayoutTableCol),
even if they should have one.

The old code worked because it didn't discriminate these cases
and was a lot more robust to the widespread abuse in the code.
Thus the logical solution is to revert the change.

BUG=527927

Review URL: https://codereview.chromium.org/1346103003

git-svn-id: svn://svn.chromium.org/blink/trunk@202653 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/third_party/WebKit/LayoutTests/fast/layers/perspective-inline-no-display-expected.png b/third_party/WebKit/LayoutTests/fast/layers/perspective-inline-no-display-expected.png
new file mode 100644
index 0000000..bd2d7bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/layers/perspective-inline-no-display-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/layers/perspective-inline-no-display-expected.txt b/third_party/WebKit/LayoutTests/fast/layers/perspective-inline-no-display-expected.txt
new file mode 100644
index 0000000..408aeb7c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/layers/perspective-inline-no-display-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x155
+  LayoutBlockFlow {HTML} at (0,0) size 800x155
+    LayoutBlockFlow {BODY} at (8,16) size 784x131
+      LayoutBlockFlow {P} at (0,0) size 784x16
+        LayoutText {#text} at (0,0) size 496x16
+          text run at (0,0) width 496: "There should be an image below:"
+      LayoutBlockFlow (anonymous) at (0,32) size 784x99
+        LayoutInline {A} at (0,0) size 96x16
+        LayoutText {#text} at (0,0) size 0x0
+layer at (8,48) size 96x96
+  LayoutImage {IMG} at (0,0) size 96x96
diff --git a/third_party/WebKit/LayoutTests/fast/layers/perspective-inline-no-display.html b/third_party/WebKit/LayoutTests/fast/layers/perspective-inline-no-display.html
new file mode 100644
index 0000000..a2f096b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/layers/perspective-inline-no-display.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<style>
+html {
+    font: 16px/1 Ahem;
+}
+
+a, img {
+    transform: perspective(2000px);
+}
+</style>
+<p>There should be an image below:</p>
+<a><img src="../../ietestcenter/css3/support/green_color_no_srgb.png"/></a>
diff --git a/third_party/WebKit/LayoutTests/fast/layers/perspective-relpos-image-no-display-expected.html b/third_party/WebKit/LayoutTests/fast/layers/perspective-relpos-image-no-display-expected.html
new file mode 100644
index 0000000..7bc183227
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/layers/perspective-relpos-image-no-display-expected.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<p>There should be an image below:</p>
+<div style="height: 96px; width: 96px; background-color: green"></div>
diff --git a/third_party/WebKit/LayoutTests/fast/layers/perspective-relpos-image-no-display.html b/third_party/WebKit/LayoutTests/fast/layers/perspective-relpos-image-no-display.html
new file mode 100644
index 0000000..e9c42f47d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/layers/perspective-relpos-image-no-display.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<style>
+img {
+    position: relative;
+}
+
+a {
+    -webkit-perspective: 1000;
+}
+</style>
+
+<p>There should be an image below:</p>
+<a>
+    <img src="../../ietestcenter/css3/support/green_color_no_srgb.png"/>
+</a>
diff --git a/third_party/WebKit/LayoutTests/fast/layers/transform-inline-no-display-expected.html b/third_party/WebKit/LayoutTests/fast/layers/transform-inline-no-display-expected.html
new file mode 100644
index 0000000..7bc183227
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/layers/transform-inline-no-display-expected.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<p>There should be an image below:</p>
+<div style="height: 96px; width: 96px; background-color: green"></div>
diff --git a/third_party/WebKit/LayoutTests/fast/layers/transform-inline-no-display.html b/third_party/WebKit/LayoutTests/fast/layers/transform-inline-no-display.html
new file mode 100644
index 0000000..589e85f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/layers/transform-inline-no-display.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<style>
+span, img {-webkit-transform:translateZ(0) }
+</style>
+<p>There should be an image below:</p>
+<span>
+    <img src="../../ietestcenter/css3/support/green_color_no_srgb.png"/>
+</span>
diff --git a/third_party/WebKit/Source/core/paint/DeprecatedPaintLayer.cpp b/third_party/WebKit/Source/core/paint/DeprecatedPaintLayer.cpp
index 02734767..dbb7a96 100644
--- a/third_party/WebKit/Source/core/paint/DeprecatedPaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/DeprecatedPaintLayer.cpp
@@ -1369,7 +1369,9 @@
 {
     ASSERT(!m_stackingNode);
     if (requiresStackingNode())
-        m_stackingNode = adoptPtr(new DeprecatedPaintLayerStackingNode(*layoutObject()));
+        m_stackingNode = adoptPtr(new DeprecatedPaintLayerStackingNode(this));
+    else
+        m_stackingNode = nullptr;
 }
 
 void DeprecatedPaintLayer::updateScrollableArea()
@@ -1552,6 +1554,12 @@
     return 0;
 }
 
+bool DeprecatedPaintLayer::isInTopLayer() const
+{
+    Node* node = layoutObject()->node();
+    return node && node->isElementNode() && toElement(node)->isInTopLayer();
+}
+
 // Compute the z-offset of the point in the transformState.
 // This is effectively projecting a ray normal to the plane of ancestor, finding where that
 // ray intersects target, and computing the z delta between those two points.
diff --git a/third_party/WebKit/Source/core/paint/DeprecatedPaintLayer.h b/third_party/WebKit/Source/core/paint/DeprecatedPaintLayer.h
index 237d205..d8853945 100644
--- a/third_party/WebKit/Source/core/paint/DeprecatedPaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/DeprecatedPaintLayer.h
@@ -399,6 +399,8 @@
 
     Node* enclosingElement() const;
 
+    bool isInTopLayer() const;
+
     bool scrollsWithViewport() const;
     bool scrollsWithRespectTo(const DeprecatedPaintLayer*) const;
 
diff --git a/third_party/WebKit/Source/core/paint/DeprecatedPaintLayerStackingNode.cpp b/third_party/WebKit/Source/core/paint/DeprecatedPaintLayerStackingNode.cpp
index d60f207..316914e 100644
--- a/third_party/WebKit/Source/core/paint/DeprecatedPaintLayerStackingNode.cpp
+++ b/third_party/WebKit/Source/core/paint/DeprecatedPaintLayerStackingNode.cpp
@@ -44,7 +44,6 @@
 #include "config.h"
 #include "core/paint/DeprecatedPaintLayerStackingNode.h"
 
-#include "core/dom/Node.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/compositing/DeprecatedPaintLayerCompositor.h"
 #include "core/paint/DeprecatedPaintLayer.h"
@@ -55,8 +54,8 @@
 // FIXME: This should not require DeprecatedPaintLayer. There is currently a cycle where
 // in order to determine if we shoulBeTreatedAsStackingContext() we have to ask the paint
 // layer about some of its state.
-DeprecatedPaintLayerStackingNode::DeprecatedPaintLayerStackingNode(LayoutBoxModelObject& layoutObject)
-    : m_layoutObject(layoutObject)
+DeprecatedPaintLayerStackingNode::DeprecatedPaintLayerStackingNode(DeprecatedPaintLayer* layer)
+    : m_layer(layer)
 #if ENABLE(ASSERT)
     , m_layerListMutationAllowed(true)
     , m_stackingParent(0)
@@ -72,7 +71,7 @@
 DeprecatedPaintLayerStackingNode::~DeprecatedPaintLayerStackingNode()
 {
 #if ENABLE(ASSERT)
-    if (!layoutObject().documentBeingDestroyed()) {
+    if (!layoutObject()->documentBeingDestroyed()) {
         ASSERT(!isInStackingParentZOrderLists());
 
         updateStackingParentForZOrderLists(0);
@@ -88,8 +87,8 @@
 
 DeprecatedPaintLayerCompositor* DeprecatedPaintLayerStackingNode::compositor() const
 {
-    ASSERT(layoutObject().view());
-    return layoutObject().view()->compositor();
+    ASSERT(layoutObject()->view());
+    return layoutObject()->view()->compositor();
 }
 
 void DeprecatedPaintLayerStackingNode::dirtyZOrderLists()
@@ -107,7 +106,7 @@
         m_negZOrderList->clear();
     m_zOrderListsDirty = true;
 
-    if (!layoutObject().documentBeingDestroyed())
+    if (!layoutObject()->documentBeingDestroyed())
         compositor()->setNeedsCompositingUpdate(CompositingUpdateRebuildTree);
 }
 
@@ -117,41 +116,14 @@
         stackingNode->dirtyZOrderLists();
 }
 
-static bool isInTopLayer(const LayoutObject& layoutObject)
-{
-    const Node* node = layoutObject.node();
-    return node && node->isElementNode() && toElement(node)->isInTopLayer();
-}
-
 void DeprecatedPaintLayerStackingNode::rebuildZOrderLists()
 {
     ASSERT(m_layerListMutationAllowed);
     ASSERT(isDirtyStackingContext());
 
-    for (LayoutObject* descendant = layoutObject().slowFirstChild(); descendant;) {
-        if (isInTopLayer(*descendant)) {
-            // Top layer objects are handled below.
-            descendant = descendant->nextInPreOrderAfterChildren(&layoutObject());
-            continue;
-        }
-
-        // FIXME: Some non-LayoutBoxModeObject can have position != static and thus would be treated like
-        // stacking context. However we can't store them in the lists unless they have a DeprecatedPaintLayer.
-        if (descendant->styleRef().isTreatedAsOrStackingContext() && descendant->hasLayer()) {
-            OwnPtr<Vector<DeprecatedPaintLayerStackingNode*>>& buffer = (descendant->style()->zIndex() >= 0) ? m_posZOrderList : m_negZOrderList;
-            if (!buffer)
-                buffer = adoptPtr(new Vector<DeprecatedPaintLayerStackingNode*>);
-            buffer->append(toLayoutBoxModelObject(descendant)->layer()->stackingNode());
-        }
-
-        if (descendant->styleRef().isStackingContext()) {
-            // We found a stacking context, just continue walking the other subtrees.
-            // They will collect their own descendant stacking contexts.
-            descendant = descendant->nextInPreOrderAfterChildren(&layoutObject());
-        } else {
-            // Not stacking context, continue deeper.
-            descendant = descendant->nextInPreOrder(&layoutObject());
-        }
+    for (DeprecatedPaintLayer* child = layer()->firstChild(); child; child = child->nextSibling()) {
+        if (!layer()->reflectionInfo() || layer()->reflectionInfo()->reflectionLayer() != child)
+            child->stackingNode()->collectLayers(m_posZOrderList, m_negZOrderList);
     }
 
     // Sort the two lists.
@@ -161,19 +133,19 @@
     if (m_negZOrderList)
         std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex);
 
-    // Append stacking contexts for top layer elements after normal layer collection, to ensure they are on top regardless of z-indexes.
+    // Append layers for top layer elements after normal layer collection, to ensure they are on top regardless of z-indexes.
     // The layoutObjects of top layer elements are children of the view, sorted in top layer stacking order.
-    if (layoutObject().isLayoutView()) {
-        LayoutView& view = toLayoutView(layoutObject());
-        for (LayoutObject* child = view.firstChild(); child; child = child->nextSibling()) {
-            if (!isInTopLayer(*child))
-                continue;
-
-            // Create the buffer if it doesn't exist yet.
-            if (!m_posZOrderList)
-                m_posZOrderList = adoptPtr(new Vector<DeprecatedPaintLayerStackingNode*>);
-            ASSERT(child->style()->isStackingContext());
-            m_posZOrderList->append(toLayoutBoxModelObject(child)->layer()->stackingNode());
+    if (layer()->isRootLayer()) {
+        LayoutView* view = layoutObject()->view();
+        for (LayoutObject* child = view->firstChild(); child; child = child->nextSibling()) {
+            Element* childElement = (child->node() && child->node()->isElementNode()) ? toElement(child->node()) : 0;
+            if (childElement && childElement->isInTopLayer()) {
+                DeprecatedPaintLayer* layer = toLayoutBoxModelObject(child)->layer();
+                // Create the buffer if it doesn't exist yet.
+                if (!m_posZOrderList)
+                    m_posZOrderList = adoptPtr(new Vector<DeprecatedPaintLayerStackingNode*>);
+                m_posZOrderList->append(layer->stackingNode());
+            }
         }
     }
 
@@ -184,6 +156,26 @@
     m_zOrderListsDirty = false;
 }
 
+void DeprecatedPaintLayerStackingNode::collectLayers(OwnPtr<Vector<DeprecatedPaintLayerStackingNode*>>& posBuffer, OwnPtr<Vector<DeprecatedPaintLayerStackingNode*>>& negBuffer)
+{
+    if (layer()->isInTopLayer())
+        return;
+
+    if (isTreatedAsOrStackingContext()) {
+        OwnPtr<Vector<DeprecatedPaintLayerStackingNode*>>& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
+        if (!buffer)
+            buffer = adoptPtr(new Vector<DeprecatedPaintLayerStackingNode*>);
+        buffer->append(this);
+    }
+
+    if (!isStackingContext()) {
+        for (DeprecatedPaintLayer* child = layer()->firstChild(); child; child = child->nextSibling()) {
+            if (!layer()->reflectionInfo() || layer()->reflectionInfo()->reflectionLayer() != child)
+                child->stackingNode()->collectLayers(posBuffer, negBuffer);
+        }
+    }
+}
+
 #if ENABLE(ASSERT)
 bool DeprecatedPaintLayerStackingNode::isInStackingParentZOrderLists() const
 {
@@ -249,7 +241,7 @@
         return;
 
     m_isTreatedAsOrStackingContext = isTreatedAsOrStackingContext;
-    if (!layoutObject().documentBeingDestroyed() && !layer()->isRootLayer())
+    if (!layoutObject()->documentBeingDestroyed() && !layer()->isRootLayer())
         compositor()->setNeedsCompositingUpdate(CompositingUpdateRebuildTree);
     dirtyStackingContextZOrderLists();
 }
@@ -264,9 +256,9 @@
     return 0;
 }
 
-DeprecatedPaintLayer* DeprecatedPaintLayerStackingNode::layer() const
+LayoutBoxModelObject* DeprecatedPaintLayerStackingNode::layoutObject() const
 {
-    return layoutObject().layer();
+    return m_layer->layoutObject();
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/DeprecatedPaintLayerStackingNode.h b/third_party/WebKit/Source/core/paint/DeprecatedPaintLayerStackingNode.h
index 29b33d3..975305d 100644
--- a/third_party/WebKit/Source/core/paint/DeprecatedPaintLayerStackingNode.h
+++ b/third_party/WebKit/Source/core/paint/DeprecatedPaintLayerStackingNode.h
@@ -89,12 +89,12 @@
     WTF_MAKE_FAST_ALLOCATED(DeprecatedPaintLayerStackingNode);
     WTF_MAKE_NONCOPYABLE(DeprecatedPaintLayerStackingNode);
 public:
-    explicit DeprecatedPaintLayerStackingNode(LayoutBoxModelObject&);
+    explicit DeprecatedPaintLayerStackingNode(DeprecatedPaintLayer*);
     ~DeprecatedPaintLayerStackingNode();
 
-    int zIndex() const { return layoutObject().style()->zIndex(); }
+    int zIndex() const { return layoutObject()->style()->zIndex(); }
 
-    bool isStackingContext() const { return layoutObject().style()->isStackingContext(); }
+    bool isStackingContext() const { return layoutObject()->style()->isStackingContext(); }
 
     // Update our normal and z-index lists.
     void updateLayerListsIfNeeded();
@@ -115,9 +115,7 @@
 
     DeprecatedPaintLayerStackingNode* ancestorStackingContextNode() const;
 
-    // FIXME: A lot of code depends on this function but shouldn't. We should
-    // build our code on top of LayoutBoxModelObject, not DeprecatedPaintLayer.
-    DeprecatedPaintLayer* layer() const;
+    DeprecatedPaintLayer* layer() const { return m_layer; }
 
 #if ENABLE(ASSERT)
     bool layerListMutationAllowed() const { return m_layerListMutationAllowed; }
@@ -144,6 +142,7 @@
     }
 
     void rebuildZOrderLists();
+    void collectLayers(OwnPtr<Vector<DeprecatedPaintLayerStackingNode*>>& posZOrderList, OwnPtr<Vector<DeprecatedPaintLayerStackingNode*>>& negZOrderList);
 
 #if ENABLE(ASSERT)
     bool isInStackingParentZOrderLists() const;
@@ -151,15 +150,15 @@
     void setStackingParent(DeprecatedPaintLayerStackingNode* stackingParent) { m_stackingParent = stackingParent; }
 #endif
 
-    bool shouldBeTreatedAsOrStackingContext() const { return layoutObject().style()->isTreatedAsOrStackingContext(); }
+    bool shouldBeTreatedAsOrStackingContext() const { return layoutObject()->style()->isTreatedAsOrStackingContext(); }
 
     bool isDirtyStackingContext() const { return m_zOrderListsDirty && isStackingContext(); }
 
     DeprecatedPaintLayerCompositor* compositor() const;
     // We can't return a LayoutBox as LayoutInline can be a stacking context.
-    LayoutBoxModelObject& layoutObject() const { return m_layoutObject; }
+    LayoutBoxModelObject* layoutObject() const;
 
-    LayoutBoxModelObject& m_layoutObject;
+    DeprecatedPaintLayer* m_layer;
 
     // m_posZOrderList holds a sorted list of all the descendant nodes within
     // that have z-indices of 0 or greater (auto will count as 0).