Add the clipToOutline by just using the clipPathOp

Change-Id: I6ba23b589e579599d018600d0744be0efe2028c1
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 418aec3..a96d46c 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -442,7 +442,8 @@
     }
 
     /**
-     * Sets the outline, defining the shape that casts a shadow.
+     * Sets the outline, defining the shape that casts a shadow, and the path to
+     * be clipped if setClipToOutline is set.
      *
      * Deep copies the native path to simplify reference ownership.
      *
@@ -456,6 +457,17 @@
     }
 
     /**
+     * Enables or disables clipping to the outline.
+     *
+     * @param clipToOutline true if clipping to the outline.
+     */
+    public void setClipToOutline(boolean clipToOutline) {
+        if (hasNativeDisplayList()) {
+            nSetClipToOutline(mFinalizer.mNativeDisplayList, clipToOutline);
+        }
+    }
+
+    /**
      * Set the static matrix on the display list. The specified matrix is combined with other
      * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
      *
@@ -1079,6 +1091,7 @@
     private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve);
     private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume);
     private static native void nSetOutline(long displayList, long nativePath);
+    private static native void nSetClipToOutline(long displayList, boolean clipToOutline);
     private static native void nSetAlpha(long displayList, float alpha);
     private static native void nSetHasOverlappingRendering(long displayList,
             boolean hasOverlappingRendering);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7ce2140..d017d56 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2371,6 +2371,11 @@
     static final int PFLAG3_CALLED_SUPER = 0x10;
 
     /**
+     * Flag indicating that an view will be clipped to its outline.
+     */
+    static final int PFLAG3_CLIP_TO_OUTLINE = 0x20;
+
+    /**
      * Flag indicating that we're in the process of applying window insets.
      */
     static final int PFLAG3_APPLYING_INSETS = 0x40;
@@ -3327,7 +3332,8 @@
     private int[] mDrawableState = null;
 
     /**
-     * Stores the outline of the view, passed down to the DisplayList level for shadow shape.
+     * Stores the outline of the view, passed down to the DisplayList level for
+     * defining shadow shape and clipping.
      */
     private Path mOutline;
 
@@ -6128,7 +6134,7 @@
      * @return {@code true} if this view applied the insets and it should not
      * continue propagating further down the hierarchy, {@code false} otherwise.
      * @see #getFitsSystemWindows()
-     * @see #setFitsSystemWindows(boolean) 
+     * @see #setFitsSystemWindows(boolean)
      * @see #setSystemUiVisibility(int)
      *
      * @deprecated As of API XX use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply
@@ -10820,6 +10826,30 @@
     }
 
     /**
+     * @hide
+     */
+    public void setClipToOutline(boolean clipToOutline) {
+        // TODO : Add a fast invalidation here.
+        if (getClipToOutline() != clipToOutline) {
+            if (clipToOutline) {
+                mPrivateFlags3 |= PFLAG3_CLIP_TO_OUTLINE;
+            } else {
+                mPrivateFlags3 &= ~PFLAG3_CLIP_TO_OUTLINE;
+            }
+            if (mDisplayList != null) {
+                mDisplayList.setClipToOutline(clipToOutline);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public final boolean getClipToOutline() {
+        return ((mPrivateFlags3 & PFLAG3_CLIP_TO_OUTLINE) != 0);
+    }
+
+    /**
      * Hit rectangle in parent's coordinates
      *
      * @param outRect The hit rectangle of the view.
@@ -14471,6 +14501,7 @@
                         (((ViewGroup) this).mGroupFlags & ViewGroup.FLAG_ISOLATED_Z_VOLUME) != 0);
             }
             displayList.setOutline(mOutline);
+            displayList.setClipToOutline(getClipToOutline());
             float alpha = 1;
             if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
                     ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp
index 4bacdde..5f7912b 100644
--- a/core/jni/android_view_DisplayList.cpp
+++ b/core/jni/android_view_DisplayList.cpp
@@ -130,6 +130,12 @@
     displayList->setOutline(outline);
 }
 
+static void android_view_DisplayList_setClipToOutline(JNIEnv* env,
+        jobject clazz, jlong displayListPtr, jboolean clipToOutline) {
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+    displayList->setClipToOutline(clipToOutline);
+}
+
 static void android_view_DisplayList_setAlpha(JNIEnv* env,
         jobject clazz, jlong displayListPtr, float alpha) {
     DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
@@ -400,6 +406,7 @@
     { "nSetProjectBackwards",  "(JZ)V",  (void*) android_view_DisplayList_setProjectBackwards },
     { "nSetProjectionReceiver","(JZ)V",  (void*) android_view_DisplayList_setProjectionReceiver },
     { "nSetOutline",           "(JJ)V",  (void*) android_view_DisplayList_setOutline },
+    { "nSetClipToOutline",     "(JZ)V",  (void*) android_view_DisplayList_setClipToOutline },
     { "nSetAlpha",             "(JF)V",  (void*) android_view_DisplayList_setAlpha },
     { "nSetHasOverlappingRendering", "(JZ)V",
             (void*) android_view_DisplayList_setHasOverlappingRendering },
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 4742f91..2a39bd9 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -242,6 +242,7 @@
     mProjectBackwards = false;
     mProjectionReceiver = false;
     mOutline.rewind();
+    mClipToOutline = false;
     mAlpha = 1;
     mHasOverlappingRendering = true;
     mTranslationX = 0;
@@ -465,6 +466,10 @@
                 mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op);
         handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
     }
+    if (CC_UNLIKELY(mClipToOutline && !mOutline.isEmpty())) {
+        ClipPathOp* op = new (handler.allocator()) ClipPathOp(&mOutline, SkRegion::kIntersect_Op);
+        handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
+    }
 }
 
 /**
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index adf48d4..42a4e74 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -213,6 +213,10 @@
         }
     }
 
+    void setClipToOutline(bool clipToOutline) {
+        mClipToOutline = clipToOutline;
+    }
+
     void setStaticMatrix(SkMatrix* matrix) {
         delete mStaticMatrix;
         mStaticMatrix = new SkMatrix(*matrix);
@@ -609,6 +613,7 @@
     bool mProjectBackwards;
     bool mProjectionReceiver;
     SkPath mOutline;
+    bool mClipToOutline;
     float mAlpha;
     bool mHasOverlappingRendering;
     float mTranslationX, mTranslationY, mTranslationZ;