Merge "Preliminary support for clipRect(Rect, Op)"
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8d32edc..7658d04 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12734,9 +12734,9 @@
* </p>
*
* <p>
- * The actual mesurement work of a view is performed in
+ * The actual measurement work of a view is performed in
* {@link #onMeasure(int, int)}, called by this method. Therefore, only
- * {@link #onMeasure(int, int)} can and must be overriden by subclasses.
+ * {@link #onMeasure(int, int)} can and must be overridden by subclasses.
* </p>
*
*
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 6c9a620..f242f18 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -55,43 +55,51 @@
void set(uint32_t w, uint32_t h);
Region& orSelf(const Rect& rhs);
+ Region& xorSelf(const Rect& rhs);
Region& andSelf(const Rect& rhs);
Region& subtractSelf(const Rect& rhs);
// boolean operators, applied on this
Region& orSelf(const Region& rhs);
+ Region& xorSelf(const Region& rhs);
Region& andSelf(const Region& rhs);
Region& subtractSelf(const Region& rhs);
// boolean operators
const Region merge(const Rect& rhs) const;
+ const Region mergeExclusive(const Rect& rhs) const;
const Region intersect(const Rect& rhs) const;
const Region subtract(const Rect& rhs) const;
// boolean operators
const Region merge(const Region& rhs) const;
+ const Region mergeExclusive(const Region& rhs) const;
const Region intersect(const Region& rhs) const;
const Region subtract(const Region& rhs) const;
// these translate rhs first
Region& translateSelf(int dx, int dy);
Region& orSelf(const Region& rhs, int dx, int dy);
+ Region& xorSelf(const Region& rhs, int dx, int dy);
Region& andSelf(const Region& rhs, int dx, int dy);
Region& subtractSelf(const Region& rhs, int dx, int dy);
// these translate rhs first
const Region translate(int dx, int dy) const;
const Region merge(const Region& rhs, int dx, int dy) const;
+ const Region mergeExclusive(const Region& rhs, int dx, int dy) const;
const Region intersect(const Region& rhs, int dx, int dy) const;
const Region subtract(const Region& rhs, int dx, int dy) const;
// convenience operators overloads
inline const Region operator | (const Region& rhs) const;
+ inline const Region operator ^ (const Region& rhs) const;
inline const Region operator & (const Region& rhs) const;
inline const Region operator - (const Region& rhs) const;
inline const Region operator + (const Point& pt) const;
inline Region& operator |= (const Region& rhs);
+ inline Region& operator ^= (const Region& rhs);
inline Region& operator &= (const Region& rhs);
inline Region& operator -= (const Region& rhs);
inline Region& operator += (const Point& pt);
@@ -158,6 +166,9 @@
const Region Region::operator | (const Region& rhs) const {
return merge(rhs);
}
+const Region Region::operator ^ (const Region& rhs) const {
+ return mergeExclusive(rhs);
+}
const Region Region::operator & (const Region& rhs) const {
return intersect(rhs);
}
@@ -172,6 +183,9 @@
Region& Region::operator |= (const Region& rhs) {
return orSelf(rhs);
}
+Region& Region::operator ^= (const Region& rhs) {
+ return xorSelf(rhs);
+}
Region& Region::operator &= (const Region& rhs) {
return andSelf(rhs);
}
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index a85362d..5f801fb 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -31,6 +31,7 @@
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
region = NULL;
+ clipRegion = NULL;
}
/**
@@ -52,8 +53,21 @@
if (saveFlags & SkCanvas::kClip_SaveFlag) {
mClipRectRoot.set(*s->clipRect);
clipRect = &mClipRectRoot;
+#if STENCIL_BUFFER_SIZE
+ if (s->clipRegion) {
+ mClipRegionRoot.merge(*s->clipRegion);
+ clipRegion = &mClipRegionRoot;
+ } else {
+ clipRegion = NULL;
+ }
+#else
+ clipRegion = NULL;
+#endif
} else {
clipRect = s->clipRect;
+#if STENCIL_BUFFER_SIZE
+ clipRegion = s->clipRegion;
+#endif
}
if (s->flags & Snapshot::kFlagFboTarget) {
@@ -68,6 +82,77 @@
// Clipping
///////////////////////////////////////////////////////////////////////////////
+void Snapshot::ensureClipRegion() {
+#if STENCIL_BUFFER_SIZE
+ if (!clipRegion) {
+ clipRegion = &mClipRegionRoot;
+ android::Rect tmp(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+ clipRegion->set(tmp);
+ }
+#endif
+}
+
+void Snapshot::copyClipRectFromRegion() {
+#if STENCIL_BUFFER_SIZE
+ if (!clipRegion->isEmpty()) {
+ android::Rect bounds(clipRegion->bounds());
+ clipRect->set(bounds.left, bounds.top, bounds.right, bounds.bottom);
+
+ if (clipRegion->isRect()) {
+ clipRegion->clear();
+ clipRegion = NULL;
+ }
+ } else {
+ clipRect->setEmpty();
+ clipRegion = NULL;
+ }
+#endif
+}
+
+bool Snapshot::clipRegionOr(float left, float top, float right, float bottom) {
+#if STENCIL_BUFFER_SIZE
+ android::Rect tmp(left, top, right, bottom);
+ clipRegion->orSelf(tmp);
+ copyClipRectFromRegion();
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool Snapshot::clipRegionXor(float left, float top, float right, float bottom) {
+#if STENCIL_BUFFER_SIZE
+ android::Rect tmp(left, top, right, bottom);
+ clipRegion->xorSelf(tmp);
+ copyClipRectFromRegion();
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool Snapshot::clipRegionAnd(float left, float top, float right, float bottom) {
+#if STENCIL_BUFFER_SIZE
+ android::Rect tmp(left, top, right, bottom);
+ clipRegion->andSelf(tmp);
+ copyClipRectFromRegion();
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool Snapshot::clipRegionNand(float left, float top, float right, float bottom) {
+#if STENCIL_BUFFER_SIZE
+ android::Rect tmp(left, top, right, bottom);
+ clipRegion->subtractSelf(tmp);
+ copyClipRectFromRegion();
+ return true;
+#else
+ return false;
+#endif
+}
+
bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
Rect r(left, top, right, bottom);
transform->mapRect(r);
@@ -77,32 +162,46 @@
bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
bool clipped = false;
- // NOTE: The unimplemented operations require support for regions
- // Supporting regions would require using a stencil buffer instead
- // of the scissor. The stencil buffer itself is not too expensive
- // (memory cost excluded) but on fillrate limited devices, managing
- // the stencil might have a negative impact on the framerate.
switch (op) {
- case SkRegion::kDifference_Op:
+ case SkRegion::kDifference_Op: {
+ ensureClipRegion();
+ clipped = clipRegionNand(r.left, r.top, r.right, r.bottom);
break;
- case SkRegion::kIntersect_Op:
- clipped = clipRect->intersect(r);
- if (!clipped) {
- clipRect->setEmpty();
- clipped = true;
+ }
+ case SkRegion::kIntersect_Op: {
+ if (CC_UNLIKELY(clipRegion)) {
+ clipped = clipRegionOr(r.left, r.top, r.right, r.bottom);
+ } else {
+ clipped = clipRect->intersect(r);
+ if (!clipped) {
+ clipRect->setEmpty();
+ clipped = true;
+ }
}
break;
- case SkRegion::kUnion_Op:
- clipped = clipRect->unionWith(r);
+ }
+ case SkRegion::kUnion_Op: {
+ if (CC_UNLIKELY(clipRegion)) {
+ clipped = clipRegionAnd(r.left, r.top, r.right, r.bottom);
+ } else {
+ clipped = clipRect->unionWith(r);
+ }
break;
- case SkRegion::kXOR_Op:
+ }
+ case SkRegion::kXOR_Op: {
+ ensureClipRegion();
+ clipped = clipRegionXor(r.left, r.top, r.right, r.bottom);
break;
- case SkRegion::kReverseDifference_Op:
+ }
+ case SkRegion::kReverseDifference_Op: {
+ // TODO!!!!!!!
break;
- case SkRegion::kReplace_Op:
- clipRect->set(r);
+ }
+ case SkRegion::kReplace_Op: {
+ setClip(r.left, r.top, r.right, r.bottom);
clipped = true;
break;
+ }
}
if (clipped) {
@@ -114,6 +213,10 @@
void Snapshot::setClip(float left, float top, float right, float bottom) {
clipRect->set(left, top, right, bottom);
+ if (clipRegion) {
+ clipRegion->clear();
+ clipRegion = NULL;
+ }
flags |= Snapshot::kFlagClipSet;
}
@@ -129,8 +232,7 @@
void Snapshot::resetClip(float left, float top, float right, float bottom) {
clipRect = &mClipRectRoot;
- clipRect->set(left, top, right, bottom);
- flags |= Snapshot::kFlagClipSet;
+ setClip(left, top, right, bottom);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index c94af7e..b2bc879 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -181,7 +181,7 @@
mat4* transform;
/**
- * Current clip region. The clip is stored in canvas-space coordinates,
+ * Current clip rect. The clip is stored in canvas-space coordinates,
* (screen-space coordinates in the regular case.)
*
* This is a reference to a rect owned by this snapshot or another
@@ -190,6 +190,17 @@
Rect* clipRect;
/**
+ * Current clip region. The clip is stored in canvas-space coordinates,
+ * (screen-space coordinates in the regular case.)
+ *
+ * This is a reference to a region owned by this snapshot or another
+ * snapshot. This pointer must not be freed. See ::mClipRegionRoot.
+ *
+ * This field is used only if STENCIL_BUFFER_SIZE is > 0.
+ */
+ Region* clipRegion;
+
+ /**
* The ancestor layer's dirty region.
*
* This is a reference to a region owned by a layer. This pointer must
@@ -198,10 +209,22 @@
Region* region;
private:
+ void ensureClipRegion();
+ void copyClipRectFromRegion();
+
+ bool clipRegionOr(float left, float top, float right, float bottom);
+ bool clipRegionXor(float left, float top, float right, float bottom);
+ bool clipRegionAnd(float left, float top, float right, float bottom);
+ bool clipRegionNand(float left, float top, float right, float bottom);
+
mat4 mTransformRoot;
Rect mClipRectRoot;
Rect mLocalClip;
+#if STENCIL_BUFFER_SIZE
+ Region mClipRegionRoot;
+#endif
+
}; // class Snapshot
}; // namespace uirenderer
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 8cd047a..6e2e731 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -126,6 +126,9 @@
Region& Region::orSelf(const Rect& r) {
return operationSelf(r, op_or);
}
+Region& Region::xorSelf(const Rect& r) {
+ return operationSelf(r, op_xor);
+}
Region& Region::andSelf(const Rect& r) {
return operationSelf(r, op_and);
}
@@ -143,6 +146,9 @@
Region& Region::orSelf(const Region& rhs) {
return operationSelf(rhs, op_or);
}
+Region& Region::xorSelf(const Region& rhs) {
+ return operationSelf(rhs, op_xor);
+}
Region& Region::andSelf(const Region& rhs) {
return operationSelf(rhs, op_and);
}
@@ -165,6 +171,9 @@
const Region Region::merge(const Rect& rhs) const {
return operation(rhs, op_or);
}
+const Region Region::mergeExclusive(const Rect& rhs) const {
+ return operation(rhs, op_xor);
+}
const Region Region::intersect(const Rect& rhs) const {
return operation(rhs, op_and);
}
@@ -182,6 +191,9 @@
const Region Region::merge(const Region& rhs) const {
return operation(rhs, op_or);
}
+const Region Region::mergeExclusive(const Region& rhs) const {
+ return operation(rhs, op_xor);
+}
const Region Region::intersect(const Region& rhs) const {
return operation(rhs, op_and);
}
@@ -205,6 +217,9 @@
Region& Region::orSelf(const Region& rhs, int dx, int dy) {
return operationSelf(rhs, dx, dy, op_or);
}
+Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
+ return operationSelf(rhs, dx, dy, op_xor);
+}
Region& Region::andSelf(const Region& rhs, int dx, int dy) {
return operationSelf(rhs, dx, dy, op_and);
}
@@ -222,6 +237,9 @@
const Region Region::merge(const Region& rhs, int dx, int dy) const {
return operation(rhs, dx, dy, op_or);
}
+const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_xor);
+}
const Region Region::intersect(const Region& rhs, int dx, int dy) const {
return operation(rhs, dx, dy, op_and);
}
@@ -421,6 +439,7 @@
SkRegion::Op sk_op;
switch (op) {
case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
+ case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 643cb8d..3904c21 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -40,6 +40,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="ClipRegionActivity"
+ android:label="_ClipRegion">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
<activity
android:name="DisplayListLayersActivity"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
new file mode 100644
index 0000000..b2a508b
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Region;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ClipRegionActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final RegionView view = new RegionView(this);
+ setContentView(view);
+ }
+
+ public static class RegionView extends View {
+ public RegionView(Context c) {
+ super(c);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ canvas.save();
+ canvas.clipRect(100.0f, 100.0f, getWidth() - 100.0f, getHeight() - 100.0f,
+ Region.Op.DIFFERENCE);
+ canvas.drawARGB(255, 255, 0, 0);
+ canvas.restore();
+ }
+ }
+}