Merge "Make setter methods on Outline call setEmpty() based on params" into lmp-dev
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 0a1204d..73c73218 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -346,7 +346,9 @@
      * Deep copies the data into native to simplify reference ownership.
      */
     public boolean setOutline(Outline outline) {
-        if (outline == null || outline.isEmpty()) {
+        if (outline == null) {
+            return nSetOutlineNone(mNativeRenderNode);
+        } else if (outline.isEmpty()) {
             return nSetOutlineEmpty(mNativeRenderNode);
         } else if (outline.mRect != null) {
             return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
@@ -878,6 +880,7 @@
             int right, int bottom, float radius);
     private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath);
     private static native boolean nSetOutlineEmpty(long renderNode);
+    private static native boolean nSetOutlineNone(long renderNode);
     private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
     private static native boolean nSetRevealClip(long renderNode,
             boolean shouldClip, boolean inverseClip, float x, float y, float radius);
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index c6ae9cc..1f3909a 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -153,6 +153,14 @@
     return true;
 }
 
+static jboolean android_view_RenderNode_setOutlineNone(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    renderNode->mutateStagingProperties().mutableOutline().setNone();
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+    return true;
+}
+
 static jboolean android_view_RenderNode_setClipToOutline(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -486,6 +494,7 @@
     { "nSetOutlineRoundRect",  "(JIIIIF)Z", (void*) android_view_RenderNode_setOutlineRoundRect },
     { "nSetOutlineConvexPath", "(JJ)Z",  (void*) android_view_RenderNode_setOutlineConvexPath },
     { "nSetOutlineEmpty",      "(J)Z",   (void*) android_view_RenderNode_setOutlineEmpty },
+    { "nSetOutlineNone",       "(J)Z",   (void*) android_view_RenderNode_setOutlineNone },
     { "nSetClipToOutline",     "(JZ)Z",  (void*) android_view_RenderNode_setClipToOutline },
     { "nSetRevealClip",        "(JZZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
 
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 1709558..3a4c2a7 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -155,6 +155,11 @@
      * Passing a zero radius is equivalent to calling {@link #setRect(int, int, int, int)}
      */
     public void setRoundRect(int left, int top, int right, int bottom, float radius) {
+        if (left >= right || top >= bottom) {
+            setEmpty();
+            return;
+        }
+
         if (mRect == null) mRect = new Rect();
         mRect.set(left, top, right, bottom);
         mRadius = radius;
@@ -173,11 +178,17 @@
      * Sets the outline to the oval defined by input rect.
      */
     public void setOval(int left, int top, int right, int bottom) {
+        if (left >= right || top >= bottom) {
+            setEmpty();
+            return;
+        }
+
         if ((bottom - top) == (right - left)) {
             // represent circle as round rect, for efficiency, and to enable clipping
             setRoundRect(left, top, right, bottom, (bottom - top) / 2.0f);
             return;
         }
+
         if (mPath == null) mPath = new Path();
         mPath.reset();
         mPath.addOval(left, top, right, bottom, Path.Direction.CW);
@@ -196,6 +207,11 @@
      * Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}.
      */
     public void setConvexPath(@NonNull Path convexPath) {
+        if (convexPath.isEmpty()) {
+            setEmpty();
+            return;
+        }
+
         if (!convexPath.isConvex()) {
             throw new IllegalArgumentException("path must be convex");
         }
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 024bdfd..83426e8 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -49,15 +49,20 @@
         mBounds.set(outline->getBounds());
     }
 
-    bool isEmpty() const {
-        return mType == kOutlineType_None;
+    void setEmpty() {
+        mType = kOutlineType_Empty;
+        mPath.reset();
     }
 
-    void setEmpty() {
+    void setNone() {
         mType = kOutlineType_None;
         mPath.reset();
     }
 
+    bool isEmpty() const {
+        return mType == kOutlineType_Empty;
+    }
+
     void setShouldClip(bool clip) {
         mShouldClip = clip;
     }
@@ -81,7 +86,7 @@
     }
 
     const SkPath* getPath() const {
-        if (mType == kOutlineType_None) return NULL;
+        if (mType == kOutlineType_None || mType == kOutlineType_Empty) return NULL;
 
         return &mPath;
     }
@@ -89,8 +94,9 @@
 private:
     enum OutlineType {
         kOutlineType_None = 0,
-        kOutlineType_ConvexPath = 1,
-        kOutlineType_RoundRect = 2
+        kOutlineType_Empty = 1,
+        kOutlineType_ConvexPath = 2,
+        kOutlineType_RoundRect = 3
     };
 
     bool mShouldClip;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index fe03806..3eb779f 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -581,7 +581,7 @@
 
 template <class T>
 void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) {
-    if (properties().getAlpha() <= 0.0f || properties().getOutline().isEmpty()) return;
+    if (properties().getAlpha() <= 0.0f || !properties().getOutline().getPath()) return;
 
     mat4 shadowMatrixXY(transformFromParent);
     applyViewPropertyTransforms(shadowMatrixXY);
@@ -776,16 +776,23 @@
  */
 template <class T>
 void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
+    const int level = handler.level();
+    if (mDisplayListData->isEmpty()) {
+        DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
+        return;
+    }
+
     const bool drawLayer = (mLayer && (&renderer != mLayer->renderer));
     // If we are updating the contents of mLayer, we don't want to apply any of
     // the RenderNode's properties to this issueOperations pass. Those will all
     // be applied when the layer is drawn, aka when this is true.
     const bool useViewProperties = (!mLayer || drawLayer);
-
-    const int level = handler.level();
-    if (mDisplayListData->isEmpty() || (useViewProperties && properties().getAlpha() <= 0)) {
-        DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
-        return;
+    if (useViewProperties) {
+        const Outline& outline = properties().getOutline();
+        if (properties().getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty())) {
+            DISPLAY_LIST_LOGD("%*sRejected display list (%p, %s)", level * 2, "", this, getName());
+            return;
+        }
     }
 
     handler.startMark(getName());