take the "transparent region" into account for blending

until now it was only used to discard a layer entirely.
we're now reducing the size of the layer if it is still
visible, if possible.

this works for instance when a surfaceView is used and
only the menu bar is displayed over it.

Change-Id: I3f5527c5cd1e69ecc968272c8948f1513ada8c55
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index 9169287..6cf64eb 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -160,6 +160,10 @@
     // the input.
     Rect transform(uint32_t xform, int32_t width, int32_t height) const;
 
+    // this calculates (Region(*this) - exclude).bounds() efficiently
+    Rect reduce(const Rect& exclude) const;
+
+
     // for backward compatibility
     inline int32_t width() const { return getWidth(); }
     inline int32_t height() const { return getHeight(); }
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index 365ea13..b480f3a 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -107,4 +107,35 @@
     return result;
 }
 
+Rect Rect::reduce(const Rect& exclude) const {
+    Rect result;
+
+    uint32_t mask = 0;
+    mask |= (exclude.left   > left)   ? 1 : 0;
+    mask |= (exclude.top    > top)    ? 2 : 0;
+    mask |= (exclude.right  < right)  ? 4 : 0;
+    mask |= (exclude.bottom < bottom) ? 8 : 0;
+
+    if (mask == 0) {
+        // crop entirely covers us
+        result.clear();
+    } else {
+        result = *this;
+        if (!(mask & (mask - 1))) {
+            // power-of-2, i.e.: just one bit is set
+            if (mask & 1) {
+                result.right = exclude.left;
+            } else if (mask & 2) {
+                result.bottom = exclude.top;
+            } else if (mask & 4) {
+                result.left = exclude.right;
+            } else if (mask & 8) {
+                result.top = exclude.bottom;
+            }
+        }
+    }
+
+    return result;
+}
+
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 07f9b8b..c15dfd5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -270,6 +270,16 @@
     return mCurrentTransform;
 }
 
+static Rect reduce(const Rect& win, const Region& exclude) {
+    if (CC_LIKELY(exclude.isEmpty())) {
+        return win;
+    }
+    if (exclude.isRect()) {
+        return win.reduce(exclude.getBounds());
+    }
+    return Region(win).subtract(exclude).getBounds();
+}
+
 Rect Layer::computeBounds() const {
     const Layer::State& s(drawingState());
     Rect win(s.active.w, s.active.h);
@@ -277,8 +287,7 @@
         win.intersect(s.active.crop, &win);
     }
     // subtract the transparent region and snap to the bounds
-    win = Region(win).subtract(s.activeTransparentRegion).getBounds();
-    return win;
+    return reduce(win, s.activeTransparentRegion);
 }
 
 Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
@@ -312,6 +321,9 @@
     // window's bounds
     activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
 
+    // subtract the transparent region and snap to the bounds
+    activeCrop = reduce(activeCrop, s.activeTransparentRegion);
+
     if (!activeCrop.isEmpty()) {
         // Transform the window crop to match the buffer coordinate system,
         // which means using the inverse of the current transform set on the
@@ -669,7 +681,7 @@
         win.intersect(s.active.crop, &win);
     }
     // subtract the transparent region and snap to the bounds
-    win = Region(win).subtract(s.activeTransparentRegion).getBounds();
+    win = reduce(win, s.activeTransparentRegion);
     if (mesh) {
         tr.transform(mesh->mVertices[0], win.left,  win.top);
         tr.transform(mesh->mVertices[1], win.left,  win.bottom);