summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Romain Guy <romainguy@google.com> 2012-02-07 17:04:34 -0800
committer Romain Guy <romainguy@google.com> 2012-02-07 17:04:34 -0800
commit967e2bf3ac8943a8e8a374bf86021915445cda67 (patch)
tree1534a056ce117ebd6c0b8e39bd6a2ed2a6eb46c8
parent0afa7e2d95a1ae047ceddf2ca67f05c67ac30770 (diff)
Preliminary support for clipRect(Rect, Op)
This adds basic support for clip regions. It is currently disabled at compile time. Enabling clip regions will require setting up a stencil buffer. Change-Id: I638616a972276e38737f8ac0633692c3845eaa74
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--include/ui/Region.h14
-rw-r--r--libs/hwui/Snapshot.cpp140
-rw-r--r--libs/hwui/Snapshot.h25
-rw-r--r--libs/ui/Region.cpp19
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java57
7 files changed, 246 insertions, 22 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8d32edcdf64d..7658d041cb1f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12734,9 +12734,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* </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 6c9a6203e793..f242f18eb251 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -55,43 +55,51 @@ public:
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 @@ private:
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 @@ const Region Region::operator + (const Point& pt) const {
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 a85362d0fbc0..5f801fbb5043 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -31,6 +31,7 @@ Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
region = NULL;
+ clipRegion = NULL;
}
/**
@@ -52,8 +53,21 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
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 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
// 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::clip(float left, float top, float right, float bottom, SkRegion::
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 @@ bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
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 @@ const Rect& Snapshot::getLocalClip() {
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 c94af7e47b7e..b2bc879760e4 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -181,7 +181,7 @@ public:
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 @@ public:
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 @@ public:
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 8cd047afb8db..6e2e731e3d5a 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -126,6 +126,9 @@ void Region::addRectUnchecked(int l, int t, int r, int b)
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::operationSelf(const Rect& r, int op) {
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 @@ Region& Region::translateSelf(int x, int y) {
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::operation(const Rect& rhs, int op) const {
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 @@ const Region Region::translate(int x, int y) const {
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 @@ Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
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 @@ void Region::boolean_operation(int op, Region& dst,
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 643cb8dd9700..3904c214b54d 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 000000000000..b2a508b0cc16
--- /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();
+ }
+ }
+}