Use RoundRect clipping for circle reveal animation

bug:16630975

Also, remove inverse clipping feature from reveal animator.

Change-Id: I770a4eb48cd123b0ca0f39d16a0f3eefd1be3653
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 24ed6cd..dd2e2fd 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -288,21 +288,20 @@
     LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
 }
 
-RevealAnimator::RevealAnimator(int centerX, int centerY, bool inverseClip,
+RevealAnimator::RevealAnimator(int centerX, int centerY,
         float startValue, float finalValue)
         : BaseRenderNodeAnimator(finalValue)
         , mCenterX(centerX)
-        , mCenterY(centerY)
-        , mInverseClip(inverseClip) {
+        , mCenterY(centerY) {
     setStartValue(startValue);
 }
 
 float RevealAnimator::getValue(RenderNode* target) const {
-    return target->properties().getRevealClip().radius();
+    return target->properties().getRevealClip().getRadius();
 }
 
 void RevealAnimator::setValue(RenderNode* target, float value) {
-    target->animatorProperties().mutableRevealClip().set(true, mInverseClip,
+    target->animatorProperties().mutableRevealClip().set(true,
             mCenterX, mCenterY, value);
 }
 
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 9a080a7..b0dcf2d 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -171,7 +171,7 @@
 
 class RevealAnimator : public BaseRenderNodeAnimator {
 public:
-    ANDROID_API RevealAnimator(int centerX, int centerY, bool inverseClip,
+    ANDROID_API RevealAnimator(int centerX, int centerY,
             float startValue, float finalValue);
 protected:
     virtual float getValue(RenderNode* target) const;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 9f66904..777a35a 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1535,10 +1535,9 @@
 class DrawShadowOp : public DrawOp {
 public:
     DrawShadowOp(const mat4& transformXY, const mat4& transformZ,
-            float casterAlpha, bool casterUnclipped,
-            const SkPath* casterOutline, const SkPath* revealClip)
+            float casterAlpha, const SkPath* casterOutline, const SkPath* revealClip)
             : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ),
-            mCasterAlpha(casterAlpha), mCasterUnclipped(casterUnclipped) {
+            mCasterAlpha(casterAlpha) {
         mOutline = *casterOutline;
         if (revealClip) {
             // intersect the outline with the convex reveal clip
@@ -1572,12 +1571,11 @@
     virtual const char* name() { return "DrawShadow"; }
 
 private:
-    bool isCasterOpaque() { return mCasterAlpha >= 1.0f && mCasterUnclipped; }
+    bool isCasterOpaque() { return mCasterAlpha >= 1.0f; }
 
     const mat4 mTransformXY;
     const mat4 mTransformZ;
     const float mCasterAlpha;
-    const bool mCasterUnclipped;
     SkPath mOutline;
 };
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index de777f0..5e6ae3f 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1742,12 +1742,12 @@
     if (mDescription.hasRoundRectClip) {
         // TODO: avoid doing this repeatedly, stashing state pointer in program
         const RoundRectClipState* state = mSnapshot->roundRectClipState;
-        const Rect& innerRect = state->outlineInnerRect;
+        const Rect& innerRect = state->innerRect;
         glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
-                innerRect.left,  innerRect.top,
-                innerRect.right,  innerRect.bottom);
+                innerRect.left, innerRect.top,
+                innerRect.right, innerRect.bottom);
         glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"),
-                state->outlineRadius);
+                state->radius);
         glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"),
                 1, GL_FALSE, &state->matrix.data[0]);
     }
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 1df2055..0662ca2 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -384,11 +384,15 @@
         handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
     }
 
-    if (CC_UNLIKELY(properties().hasClippingPath())) {
-        ClipPathOp* op = new (handler.allocator()) ClipPathOp(
-                properties().getClippingPath(), properties().getClippingPathOp());
-        handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
+    // TODO: support both reveal clip and outline clip simultaneously
+    if (mProperties.getRevealClip().willClip()) {
+        Rect bounds;
+        mProperties.getRevealClip().getBounds(&bounds);
+        renderer.setClippingRoundRect(handler.allocator(), bounds, mProperties.getRevealClip().getRadius());
+    } else if (mProperties.getOutline().willClip()) {
+        renderer.setClippingOutline(handler.allocator(), &(mProperties.getOutline()));
     }
+
 }
 
 /**
@@ -600,23 +604,11 @@
     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
-
+    const SkPath* revealClipPath = properties().getRevealClip().getPath();
     if (revealClipPath && revealClipPath->isEmpty()) return;
 
-    /**
-     * 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,
+            shadowMatrixXY, shadowMatrixZ, properties().getAlpha(),
             outlinePath, revealClipPath);
     handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
 }
@@ -828,10 +820,6 @@
     bool quickRejected = properties().getClipToBounds()
             && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
     if (!quickRejected) {
-        if (mProperties.getOutline().willClip()) {
-            renderer.setClippingOutline(alloc, &(mProperties.getOutline()));
-        }
-
         if (drawLayer) {
             handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
                     renderer.getSaveCount() - 1, properties().getClipToBounds());
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index f50e514..9898bde 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -546,19 +546,6 @@
 
     void updateMatrix();
 
-    bool hasClippingPath() const {
-        return mPrimitiveFields.mRevealClip.willClip();
-    }
-
-    const SkPath* getClippingPath() const {
-        return mPrimitiveFields.mRevealClip.getPath();
-    }
-
-    SkRegion::Op getClippingPathOp() const {
-        return mPrimitiveFields.mRevealClip.isInverseClip()
-                ? SkRegion::kDifference_Op : SkRegion::kIntersect_Op;
-    }
-
     Outline& mutableOutline() {
         return mPrimitiveFields.mOutline;
     }
diff --git a/libs/hwui/RevealClip.h b/libs/hwui/RevealClip.h
index 07404cb..a9600f1 100644
--- a/libs/hwui/RevealClip.h
+++ b/libs/hwui/RevealClip.h
@@ -27,14 +27,12 @@
 public:
     RevealClip()
             : mShouldClip(false)
-            , mInverseClip(false)
             , mX(0)
             , mY(0)
             , mRadius(0) {}
 
-    void set(bool shouldClip, bool inverseClip, float x, float y, float radius) {
+    void set(bool shouldClip, float x, float y, float radius) {
         mShouldClip = shouldClip;
-        mInverseClip = inverseClip;
         mX = x;
         mY = y;
         mRadius = radius;
@@ -45,21 +43,15 @@
         }
     }
 
-    bool hasConvexClip() const {
-        return mShouldClip && !mInverseClip;
-    }
-
-    bool isInverseClip() const {
-        return mInverseClip;
-    }
-
     bool willClip() const {
         return mShouldClip;
     }
 
-    float radius() const {
-        return mRadius;
+    void getBounds(Rect* outBounds) const {
+        outBounds->set(mX - mRadius, mY - mRadius,
+                mX + mRadius, mY + mRadius);
     }
+    float getRadius() const { return mRadius; }
 
     const SkPath* getPath() const {
         if (!mShouldClip) return NULL;
@@ -69,7 +61,6 @@
 
 private:
     bool mShouldClip;
-    bool mInverseClip;
     float mX;
     float mY;
     float mRadius;
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 80f7eca..6f19275 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -20,8 +20,6 @@
 
 #include <SkCanvas.h>
 
-#include "utils/MathUtils.h"
-
 namespace android {
 namespace uirenderer {
 
@@ -207,23 +205,22 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Clipping outline
+// Clipping round rect
 ///////////////////////////////////////////////////////////////////////////////
 
-void Snapshot::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
-    Rect bounds;
-    float radius;
-    if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
-
-    if (!MathUtils::isPositive(radius)) return; // leave clipping up to rect clipping
+void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius) {
+    if (bounds.isEmpty()) {
+        clipRect->setEmpty();
+        return;
+    }
 
     RoundRectClipState* state = new (allocator) RoundRectClipState;
 
     // store the inverse drawing matrix
-    Matrix4 outlineDrawingMatrix;
-    outlineDrawingMatrix.load(getOrthoMatrix());
-    outlineDrawingMatrix.multiply(*transform);
-    state->matrix.loadInverse(outlineDrawingMatrix);
+    Matrix4 roundRectDrawingMatrix;
+    roundRectDrawingMatrix.load(getOrthoMatrix());
+    roundRectDrawingMatrix.multiply(*transform);
+    state->matrix.loadInverse(roundRectDrawingMatrix);
 
     // compute area under rounded corners - only draws overlapping these rects need to be clipped
     for (int i = 0 ; i < 4; i++) {
@@ -241,9 +238,9 @@
     }
 
     // store RR area
-    bounds.inset(radius);
-    state->outlineInnerRect = bounds;
-    state->outlineRadius = radius;
+    state->innerRect = bounds;
+    state->innerRect.inset(radius);
+    state->radius = radius;
 
     // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
     roundRectClipState = state;
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 5426e89..98e2440 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -57,8 +57,8 @@
 
     Matrix4 matrix;
     Rect dangerRects[4];
-    Rect outlineInnerRect;
-    float outlineRadius;
+    Rect innerRect;
+    float radius;
 };
 
 /**
@@ -164,7 +164,7 @@
     /**
      * Sets (and replaces) the current clipping outline
      */
-    void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+    void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius);
 
     /**
      * Indicates whether this snapshot should be ignored. A snapshot
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 473005c..dc41157 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -20,6 +20,8 @@
 
 #include "StatefulBaseRenderer.h"
 
+#include "utils/MathUtils.h"
+
 namespace android {
 namespace uirenderer {
 
@@ -189,9 +191,24 @@
 }
 
 void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
-    mSnapshot->setClippingOutline(allocator, outline);
+    Rect bounds;
+    float radius;
+    if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
+
+    if (!MathUtils::isPositive(radius)) {
+        // TODO: consider storing this rect separately, so that this can't be replaced with clip ops
+        clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkRegion::kIntersect_Op);
+        return;
+    }
+    setClippingRoundRect(allocator, bounds, radius);
 }
 
+void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
+        const Rect& rect, float radius) {
+    mSnapshot->setClippingRoundRect(allocator, rect, radius);
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 // Quick Rejection
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index 25cc832..6d83b4c 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -96,6 +96,8 @@
      * The clipping outline is independent from the regular clip.
      */
     void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+    void setClippingRoundRect(LinearAllocator& allocator,
+            const Rect& rect, float radius);
 
 protected:
     const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }