Support shadows on the root RenderNode

bug:13211941

Cleans up some of the RenderNode method naming

Also removes unnecessary clip/save/restores, clipping shadows
predictably, as drawn by the parent, before drawing (and clipping,
etc.) the shadow casting child.

Change-Id: I795115e1fb869bbbdd7be43e279b97490fecc7e0
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index bdf6674..34d98a1 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -132,10 +132,9 @@
 #define PROPERTY_SAVECOUNT 0
 
 template <class T>
-void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler,
-        const int level) {
+void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
 #if DEBUG_DISPLAY_LIST
-    properties().debugOutputProperties(level);
+    properties().debugOutputProperties(handler.level() + 1);
 #endif
     if (properties().getLeft() != 0 || properties().getTop() != 0) {
         renderer.translate(properties().getLeft(), properties().getTop());
@@ -302,7 +301,6 @@
             child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
         }
     }
-
 }
 
 class DeferOperationHandler {
@@ -313,15 +311,25 @@
         operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
     }
     inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
+    inline void startMark(const char* name) {} // do nothing
+    inline void endMark() {}
+    inline int level() { return mLevel; }
+    inline int replayFlags() { return mDeferStruct.mReplayFlags; }
 
 private:
     DeferStateStruct& mDeferStruct;
     const int mLevel;
 };
 
-void RenderNode::defer(DeferStateStruct& deferStruct, const int level) {
+void RenderNode::deferNodeTree(DeferStateStruct& deferStruct) {
+    DeferOperationHandler handler(deferStruct, 0);
+    if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
+    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
+}
+
+void RenderNode::deferNodeInParent(DeferStateStruct& deferStruct, const int level) {
     DeferOperationHandler handler(deferStruct, level);
-    iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
+    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
 }
 
 class ReplayOperationHandler {
@@ -335,21 +343,31 @@
         operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
     }
     inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
+    inline void startMark(const char* name) {
+        mReplayStruct.mRenderer.startMark(name);
+    }
+    inline void endMark() {
+        mReplayStruct.mRenderer.endMark();
+        DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
+                mReplayStruct.mDrawGlStatus);
+    }
+    inline int level() { return mLevel; }
+    inline int replayFlags() { return mReplayStruct.mReplayFlags; }
 
 private:
     ReplayStateStruct& mReplayStruct;
     const int mLevel;
 };
 
-void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
+void RenderNode::replayNodeTree(ReplayStateStruct& replayStruct) {
+    ReplayOperationHandler handler(replayStruct, 0);
+    if (properties().getTranslationZ() > 0.0f) issueDrawShadowOperation(Matrix4::identity(), handler);
+    issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
+}
+
+void RenderNode::replayNodeInParent(ReplayStateStruct& replayStruct, const int level) {
     ReplayOperationHandler handler(replayStruct, level);
-
-    replayStruct.mRenderer.startMark(mName.string());
-    iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
-    replayStruct.mRenderer.endMark();
-
-    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
-            replayStruct.mDrawGlStatus);
+    issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
 }
 
 void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
@@ -373,10 +391,42 @@
     std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end());
 }
 
+template <class T>
+void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) {
+    if (properties().getAlpha() <= 0.0f) return;
+
+    mat4 shadowMatrixXY(transformFromParent);
+    applyViewPropertyTransforms(shadowMatrixXY);
+
+    // Z matrix needs actual 3d transformation, so mapped z values will be correct
+    mat4 shadowMatrixZ(transformFromParent);
+    applyViewPropertyTransforms(shadowMatrixZ, true);
+
+    const SkPath* outlinePath = properties().getOutline().getPath();
+    const RevealClip& revealClip = properties().getRevealClip();
+    const SkPath* revealClipPath = revealClip.hasConvexClip()
+            ?  revealClip.getPath() : NULL; // only pass the reveal clip's path if it's convex
+
+    /**
+     * The drawing area of the caster is always the same as the its perimeter (which
+     * the shadow system uses) *except* in the inverse clip case. Inform the shadow
+     * system that the caster's drawing area (as opposed to its perimeter) has been
+     * clipped, so that it knows the caster can't be opaque.
+     */
+    bool casterUnclipped = !revealClip.willClip() || revealClip.hasConvexClip();
+
+    DisplayListOp* shadowOp  = new (handler.allocator()) DrawShadowOp(
+            shadowMatrixXY, shadowMatrixZ,
+            properties().getAlpha(), casterUnclipped,
+            properties().getWidth(), properties().getHeight(),
+            outlinePath, revealClipPath);
+    handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
+}
+
 #define SHADOW_DELTA 0.1f
 
 template <class T>
-void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
+void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
         ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) {
     const int size = zTranslatedNodes.size();
     if (size == 0
@@ -386,12 +436,6 @@
         return;
     }
 
-    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    LinearAllocator& alloc = handler.allocator();
-    ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().getWidth(), properties().getHeight(),
-            SkRegion::kIntersect_Op); // clip to 3d root bounds
-    handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
-
     /**
      * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
      * with very similar Z heights to draw together.
@@ -419,35 +463,7 @@
             // attempt to render the shadow if the caster about to be drawn is its caster,
             // OR if its caster's Z value is similar to the previous potential caster
             if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
-
-                if (caster->properties().getAlpha() > 0.0f) {
-                    mat4 shadowMatrixXY(casterOp->mTransformFromParent);
-                    caster->applyViewPropertyTransforms(shadowMatrixXY);
-
-                    // Z matrix needs actual 3d transformation, so mapped z values will be correct
-                    mat4 shadowMatrixZ(casterOp->mTransformFromParent);
-                    caster->applyViewPropertyTransforms(shadowMatrixZ, true);
-
-                    const SkPath* outlinePath = caster->properties().getOutline().getPath();
-                    const RevealClip& revealClip = caster->properties().getRevealClip();
-                    const SkPath* revealClipPath = revealClip.hasConvexClip()
-                            ?  revealClip.getPath() : NULL; // only pass the reveal clip's path if it's convex
-
-                    /**
-                     * The drawing area of the caster is always the same as the its perimeter (which
-                     * the shadow system uses) *except* in the inverse clip case. Inform the shadow
-                     * system that the caster's drawing area (as opposed to its perimeter) has been
-                     * clipped, so that it knows the caster can't be opaque.
-                     */
-                    bool casterUnclipped = !revealClip.willClip() || revealClip.hasConvexClip();
-
-                    DisplayListOp* shadowOp  = new (alloc) DrawShadowOp(
-                            shadowMatrixXY, shadowMatrixZ,
-                            caster->properties().getAlpha(), casterUnclipped,
-                            caster->properties().getWidth(), caster->properties().getHeight(),
-                            outlinePath, revealClipPath);
-                    handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
-                }
+                caster->issueDrawShadowOperation(casterOp->mTransformFromParent, handler);
 
                 lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
                 shadowIndex++;
@@ -470,17 +486,10 @@
         renderer.restoreToCount(restoreTo);
         drawIndex++;
     }
-    handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().getClipToBounds());
 }
 
 template <class T>
-void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
-    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    LinearAllocator& alloc = handler.allocator();
-    ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().getWidth(), properties().getHeight(),
-            SkRegion::kReplace_Op); // clip to projection surface root bounds
-    handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
-
+void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) {
     for (size_t i = 0; i < mProjectedNodes.size(); i++) {
         DrawDisplayListOp* childOp = mProjectedNodes[i];
 
@@ -492,7 +501,6 @@
         childOp->mSkipInOrderDraw = true;
         renderer.restoreToCount(restoreTo);
     }
-    handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().getClipToBounds());
 }
 
 /**
@@ -505,7 +513,8 @@
  * defer vs replay logic, per operation
  */
 template <class T>
-void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
+void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
+    const int level = handler.level();
     if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
         ALOGW("Error: %s is drawing after destruction", mName.string());
         CRASH();
@@ -515,6 +524,8 @@
         return;
     }
 
+    handler.startMark(mName.string());
+
 #if DEBUG_DISPLAY_LIST
     Rect* clipRect = renderer.getClipRect();
     DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
@@ -530,7 +541,7 @@
     DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
 
-    setViewProperties<T>(renderer, handler, level + 1);
+    setViewProperties<T>(renderer, handler);
 
     bool quickRejected = properties().getClipToBounds()
             && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
@@ -539,7 +550,7 @@
         buildZSortedChildList(zTranslatedNodes);
 
         // for 3d root, draw children with negative z values
-        iterate3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+        issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
 
         DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
         const int saveCountOffset = renderer.getSaveCount() - 1;
@@ -550,23 +561,24 @@
 #if DEBUG_DISPLAY_LIST
             op->output(level + 1);
 #endif
-
             logBuffer.writeCommand(level, op->name());
             handler(op, saveCountOffset, properties().getClipToBounds());
 
             if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
-                iterateProjectedChildren(renderer, handler, level);
+                issueOperationsOfProjectedChildren(renderer, handler);
             }
         }
 
         // for 3d root, draw children with positive z values
-        iterate3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+        issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
     }
 
     DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
     handler(new (alloc) RestoreToCountOp(restoreTo),
             PROPERTY_SAVECOUNT, properties().getClipToBounds());
     renderer.setOverrideLayerAlpha(1.0f);
+
+    handler.endMark();
 }
 
 } /* namespace uirenderer */