Move ClipBounds to native

bug:15698973

Also simplifies RenderNode LTRB properties

Change-Id: I09263a697b71d325a46b57cd5250a2b165f251c8
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index b77b36f..01c7761 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -347,31 +347,35 @@
         }
     }
     const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
-    bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds();
+    int clipFlags = properties().getClippingFlags();
     if (properties().getAlpha() < 1) {
         if (isLayer) {
+            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+
             renderer.setOverrideLayerAlpha(properties().getAlpha());
         } else if (!properties().getHasOverlappingRendering()) {
             renderer.scaleAlpha(properties().getAlpha());
         } else {
-            // TODO: should be able to store the size of a DL at record time and not
-            // have to pass it into this call. In fact, this information might be in the
-            // location/size info that we store with the new native transform data.
+            Rect layerBounds(0, 0, getWidth(), getHeight());
             int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
-            if (clipToBoundsNeeded) {
+            if (clipFlags) {
                 saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
-                clipToBoundsNeeded = false; // clipping done by saveLayer
+                properties().getClippingRectForFlags(clipFlags, &layerBounds);
+                clipFlags = 0; // all clipping done by saveLayer
             }
 
             SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
-                    0, 0, properties().getWidth(), properties().getHeight(),
+                    layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom,
                     properties().getAlpha() * 255, saveFlags);
             handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
         }
     }
-    if (clipToBoundsNeeded) {
+    if (clipFlags) {
+        Rect clipRect;
+        properties().getClippingRectForFlags(clipFlags, &clipRect);
         ClipRectOp* op = new (handler.allocator()) ClipRectOp(
-                0, 0, properties().getWidth(), properties().getHeight(), SkRegion::kIntersect_Op);
+                clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
+                SkRegion::kIntersect_Op);
         handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
     }
 
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 8848b2f..250cadc 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -75,7 +75,7 @@
 }
 
 RenderProperties::PrimitiveFields::PrimitiveFields()
-        : mClipToBounds(true)
+        : mClippingFlags(CLIP_TO_BOUNDS)
         , mProjectBackwards(false)
         , mProjectionReceiver(false)
         , mAlpha(1)
@@ -146,26 +146,34 @@
         }
     }
 
-    bool clipToBoundsNeeded = layerProperties().type() != kLayerTypeNone ? false : mPrimitiveFields.mClipToBounds;
+    const bool isLayer = layerProperties().type() != kLayerTypeNone;
+    int clipFlags = getClippingFlags();
     if (mPrimitiveFields.mAlpha < 1) {
-        if (layerProperties().type() != kLayerTypeNone) {
+        if (isLayer) {
+            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+
             ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
         } else if (!mPrimitiveFields.mHasOverlappingRendering) {
             ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
         } else {
-            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
-            if (clipToBoundsNeeded) {
-                flags |= SkCanvas::kClipToLayer_SaveFlag;
-                clipToBoundsNeeded = false; // clipping done by save layer
+            Rect layerBounds(0, 0, getWidth(), getHeight());
+            int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
+            if (clipFlags) {
+                saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
+                getClippingRectForFlags(clipFlags, &layerBounds);
+                clipFlags = 0; // all clipping done by saveLayer
             }
+
             ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
-                    0, 0, getWidth(), getHeight(),
-                    (int)(mPrimitiveFields.mAlpha * 255), flags);
+                    (int)layerBounds.left, (int)layerBounds.top, (int)layerBounds.right, (int)layerBounds.bottom,
+                    (int)(mPrimitiveFields.mAlpha * 255), saveFlags);
         }
     }
-    if (clipToBoundsNeeded) {
+    if (clipFlags) {
+        Rect clipRect;
+        getClippingRectForFlags(clipFlags, &clipRect);
         ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "",
-                0, 0, getWidth(), getHeight());
+                (int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
     }
 }
 
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 227d56e..f50e514 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -58,6 +58,11 @@
     // TODO: LayerTypeSurfaceTexture? Maybe?
 };
 
+enum ClippingFlags {
+    CLIP_TO_BOUNDS =      0x1 << 0,
+    CLIP_TO_CLIP_BOUNDS = 0x1 << 1,
+};
+
 class ANDROID_API LayerProperties {
 public:
     bool setType(LayerType type) {
@@ -135,10 +140,35 @@
     RenderProperties();
     virtual ~RenderProperties();
 
+    static bool setFlag(int flag, bool newValue, int* outFlags) {
+        if (newValue) {
+            if (!(flag & *outFlags)) {
+                *outFlags |= flag;
+                return true;
+            }
+            return false;
+        } else {
+            if (flag & *outFlags) {
+                *outFlags &= ~flag;
+                return true;
+            }
+            return false;
+        }
+    }
+
     RenderProperties& operator=(const RenderProperties& other);
 
     bool setClipToBounds(bool clipToBounds) {
-        return RP_SET(mPrimitiveFields.mClipToBounds, clipToBounds);
+        return setFlag(CLIP_TO_BOUNDS, clipToBounds, &mPrimitiveFields.mClippingFlags);
+    }
+
+    bool setClipBounds(const Rect& clipBounds) {
+        bool ret = setFlag(CLIP_TO_CLIP_BOUNDS, true, &mPrimitiveFields.mClippingFlags);
+        return RP_SET(mPrimitiveFields.mClipBounds, clipBounds) || ret;
+    }
+
+    bool setClipBoundsEmpty() {
+        return setFlag(CLIP_TO_CLIP_BOUNDS, false, &mPrimitiveFields.mClippingFlags);
     }
 
     bool setProjectBackwards(bool shouldProject) {
@@ -433,7 +463,7 @@
         return false;
     }
 
-    bool offsetLeftRight(float offset) {
+    bool offsetLeftRight(int offset) {
         if (offset != 0) {
             mPrimitiveFields.mLeft += offset;
             mPrimitiveFields.mRight += offset;
@@ -442,7 +472,7 @@
         return false;
     }
 
-    bool offsetTopBottom(float offset) {
+    bool offsetTopBottom(int offset) {
         if (offset != 0) {
             mPrimitiveFields.mTop += offset;
             mPrimitiveFields.mBottom += offset;
@@ -477,8 +507,23 @@
         return mComputedFields.mTransformMatrix;
     }
 
+    int getClippingFlags() const {
+        return mPrimitiveFields.mClippingFlags;
+    }
+
     bool getClipToBounds() const {
-        return mPrimitiveFields.mClipToBounds;
+        return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS;
+    }
+
+    void getClippingRectForFlags(uint32_t flags, Rect* outRect) const {
+        if (flags & CLIP_TO_BOUNDS) {
+            outRect->set(0, 0, getWidth(), getHeight());
+            if (flags & CLIP_TO_CLIP_BOUNDS) {
+                outRect->intersect(mPrimitiveFields.mClipBounds);
+            }
+        } else {
+            outRect->set(mPrimitiveFields.mClipBounds);
+        }
     }
 
     bool getHasOverlappingRendering() const {
@@ -540,14 +585,13 @@
     }
 
 private:
-
     // Rendering properties
     struct PrimitiveFields {
         PrimitiveFields();
 
         Outline mOutline;
         RevealClip mRevealClip;
-        bool mClipToBounds;
+        int mClippingFlags;
         bool mProjectBackwards;
         bool mProjectionReceiver;
         float mAlpha;
@@ -561,6 +605,7 @@
         int mWidth, mHeight;
         bool mPivotExplicitlySet;
         bool mMatrixOrPivotDirty;
+        Rect mClipBounds;
     } mPrimitiveFields;
 
     SkMatrix* mStaticMatrix;