Add shadow support to new reorderer/renderer

Doesn't yet use correct lighting info (esp. in layers), or
tessellate shadows asynchronously

Change-Id: I9ccec24b28869be42138a9bb234b1af874291a44
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index 68f80ea..80efaed 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -22,6 +22,7 @@
 #include "utils/PaintUtils.h"
 
 #include <SkCanvas.h>
+#include <SkPathOps.h>
 #include <utils/Trace.h>
 #include <utils/TypeHelpers.h>
 
@@ -312,7 +313,7 @@
         : mCanvasState(*this) {
     ATRACE_NAME("prepare drawing commands");
     mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
-        mLayerStack.push_back(0);
+    mLayerStack.push_back(0);
 
     mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
             clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
@@ -347,7 +348,6 @@
 OpReorderer::OpReorderer(int viewportWidth, int viewportHeight, const DisplayList& displayList)
         : mCanvasState(*this) {
     ATRACE_NAME("prepare drawing commands");
-
     mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
     mLayerStack.push_back(0);
 
@@ -462,8 +462,60 @@
 }
 
 void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) {
-    // TODO
+    auto& node = *casterNodeOp.renderNode;
+    auto& properties = node.properties();
+
+    if (properties.getAlpha() <= 0.0f
+            || properties.getOutline().getAlpha() <= 0.0f
+            || !properties.getOutline().getPath()
+            || properties.getScaleX() == 0
+            || properties.getScaleY() == 0) {
+        // no shadow to draw
+        return;
+    }
+
+    const SkPath* casterOutlinePath = properties.getOutline().getPath();
+    const SkPath* revealClipPath = properties.getRevealClip().getPath();
+    if (revealClipPath && revealClipPath->isEmpty()) return;
+
+    float casterAlpha = properties.getAlpha() * properties.getOutline().getAlpha();
+
+    // holds temporary SkPath to store the result of intersections
+    SkPath* frameAllocatedPath = nullptr;
+    const SkPath* casterPath = casterOutlinePath;
+
+    // intersect the shadow-casting path with the reveal, if present
+    if (revealClipPath) {
+        frameAllocatedPath = createFrameAllocatedPath();
+
+        Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath);
+        casterPath = frameAllocatedPath;
+    }
+
+    // intersect the shadow-casting path with the clipBounds, if present
+    if (properties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS) {
+        if (!frameAllocatedPath) {
+            frameAllocatedPath = createFrameAllocatedPath();
+        }
+        Rect clipBounds;
+        properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
+        SkPath clipBoundsPath;
+        clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
+                clipBounds.right, clipBounds.bottom);
+
+        Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath);
+        casterPath = frameAllocatedPath;
+    }
+
+    ShadowOp* shadowOp = new (mAllocator) ShadowOp(casterNodeOp, casterAlpha, casterPath,
+            mCanvasState.getLocalClipBounds());
+    BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
+            mAllocator, *mCanvasState.currentSnapshot(), shadowOp);
+    if (CC_LIKELY(bakedOpState)) {
+        currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
+    }
 }
+
 /**
  * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods.
  *
@@ -593,5 +645,9 @@
     LOG_ALWAYS_FATAL("unsupported");
 }
 
+void OpReorderer::onShadowOp(const ShadowOp& op) {
+    LOG_ALWAYS_FATAL("unsupported");
+}
+
 } // namespace uirenderer
 } // namespace android