summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/RenderNode.java10
-rw-r--r--core/java/android/view/View.java13
-rw-r--r--core/jni/android_view_RenderNode.cpp16
-rw-r--r--libs/hwui/DisplayListOp.h34
-rw-r--r--libs/hwui/OpenGLRenderer.cpp7
-rw-r--r--libs/hwui/OpenGLRenderer.h2
-rw-r--r--libs/hwui/Outline.h1
-rw-r--r--libs/hwui/RenderNode.cpp29
-rw-r--r--libs/hwui/RenderProperties.cpp41
-rw-r--r--libs/hwui/RenderProperties.h29
-rw-r--r--libs/hwui/RevealClip.h78
11 files changed, 231 insertions, 29 deletions
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 60fb7ac..6c8c3c7 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -361,6 +361,14 @@ public class RenderNode {
}
/**
+ * Controls the RenderNode's circular reveal clip.
+ */
+ public void setRevealClip(boolean shouldClip, boolean inverseClip,
+ float x, float y, float radius) {
+ nSetRevealClip(mNativeDisplayList, shouldClip, inverseClip, x, y, radius);
+ }
+
+ /**
* 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.)
*
@@ -856,6 +864,8 @@ public class RenderNode {
private static native void nSetOutlineConvexPath(long displayList, long nativePath);
private static native void nSetOutlineEmpty(long displayList);
private static native void nSetClipToOutline(long displayList, boolean clipToOutline);
+ private static native void nSetRevealClip(long displayList,
+ boolean shouldClip, boolean inverseClip, float x, float y, float radius);
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 6ee99ec..f2b9b96 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -33,7 +33,6 @@ import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Outline;
import android.graphics.Paint;
-import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PorterDuff;
@@ -10884,6 +10883,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Private API to be used for reveal animation
+ *
+ * @hide
+ */
+ public void setRevealClip(boolean shouldClip, boolean inverseClip,
+ float x, float y, float radius) {
+ if (mDisplayList != null) {
+ mDisplayList.setRevealClip(shouldClip, inverseClip, x, y, radius);
+ }
+ }
+
+ /**
* Hit rectangle in parent's coordinates
*
* @param outRect The hit rectangle of the view.
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 5c7e773..3e359d4 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -115,23 +115,38 @@ static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
jint right, jint bottom, jfloat radius) {
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
displayList->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius);
+ displayList->mutateStagingProperties().updateClipPath();
}
+
static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
jobject clazz, jlong displayListPtr, jlong outlinePathPtr) {
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
displayList->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath);
+ displayList->mutateStagingProperties().updateClipPath();
}
+
static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
jobject clazz, jlong displayListPtr) {
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
displayList->mutateStagingProperties().mutableOutline().setEmpty();
+ displayList->mutateStagingProperties().updateClipPath();
}
static void android_view_RenderNode_setClipToOutline(JNIEnv* env,
jobject clazz, jlong displayListPtr, jboolean clipToOutline) {
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
displayList->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
+ displayList->mutateStagingProperties().updateClipPath();
+}
+
+static void android_view_RenderNode_setRevealClip(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jboolean shouldClip, jboolean inverseClip,
+ jfloat x, jfloat y, jfloat radius) {
+ RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+ displayList->mutateStagingProperties().mutableRevealClip().set(
+ shouldClip, inverseClip, x, y, radius);
+ displayList->mutateStagingProperties().updateClipPath();
}
static void android_view_RenderNode_setAlpha(JNIEnv* env,
@@ -396,6 +411,7 @@ static JNINativeMethod gMethods[] = {
{ "nSetOutlineConvexPath", "(JJ)V", (void*) android_view_RenderNode_setOutlineConvexPath },
{ "nSetOutlineEmpty", "(J)V", (void*) android_view_RenderNode_setOutlineEmpty },
{ "nSetClipToOutline", "(JZ)V", (void*) android_view_RenderNode_setClipToOutline },
+ { "nSetRevealClip", "(JZZFFF)V", (void*) android_view_RenderNode_setRevealClip },
{ "nSetAlpha", "(JF)V", (void*) android_view_RenderNode_setAlpha },
{ "nSetHasOverlappingRendering", "(JZ)V",
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 549b786..9e367fc 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -21,6 +21,8 @@
#define LOG_TAG "OpenGLRenderer"
#endif
+#include <SkPath.h>
+#include <SkPathOps.h>
#include <SkXfermode.h>
#include <private/hwui/DrawGlInfo.h>
@@ -1550,20 +1552,27 @@ private:
*/
class DrawShadowOp : public DrawOp {
public:
- DrawShadowOp(const mat4& transformXY, const mat4& transformZ, float alpha, const SkPath* outline,
- float fallbackWidth, float fallbackHeight)
- : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ),
- mAlpha(alpha), mOutline(outline),
- mFallbackWidth(fallbackWidth), mFallbackHeight(fallbackHeight) {}
+ DrawShadowOp(const mat4& transformXY, const mat4& transformZ, float alpha,
+ float fallbackWidth, float fallbackHeight,
+ const SkPath* outline, const SkPath* revealClip)
+ : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ), mAlpha(alpha),
+ mFallbackWidth(fallbackWidth), mFallbackHeight(fallbackHeight),
+ mOutline(outline), mRevealClip(revealClip) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- if (mOutline->isEmpty()) {
- SkPath fakeOutline;
- fakeOutline.addRect(0, 0, mFallbackWidth, mFallbackHeight);
- return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, &fakeOutline);
+ SkPath casterPerimeter;
+ if (!mOutline || mOutline->isEmpty()) {
+ casterPerimeter.addRect(0, 0, mFallbackWidth, mFallbackHeight);
+ } else {
+ casterPerimeter = *mOutline;
+ }
+
+ if (mRevealClip) {
+ // intersect the outline with the convex reveal clip
+ Op(casterPerimeter, *mRevealClip, kIntersect_PathOp, &casterPerimeter);
}
- return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, mOutline);
+ return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, &casterPerimeter);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1576,9 +1585,12 @@ private:
const mat4 mTransformXY;
const mat4 mTransformZ;
const float mAlpha;
- const SkPath* mOutline;
const float mFallbackWidth;
const float mFallbackHeight;
+
+ // these point at convex SkPaths owned by RenderProperties, or null
+ const SkPath* mOutline;
+ const SkPath* mRevealClip;
};
class DrawLayerOp : public DrawOp {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cdd789d..d808735 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1919,6 +1919,7 @@ status_t OpenGLRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty,
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
// compute 3d ordering
+ displayList->updateProperties();
displayList->computeOrdering();
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
status = startFrame();
@@ -3202,7 +3203,7 @@ static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& t
}
status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ,
- float casterAlpha, const SkPath* casterOutline) {
+ float casterAlpha, const SkPath* casterPerimeter) {
if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
// TODO: use quickRejectWithScissor. For now, always force enable scissor.
@@ -3214,7 +3215,7 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c
// tessellate caster outline into a 2d polygon
Vector<Vertex> casterVertices2d;
const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value
- PathTessellator::approximatePathOutlineVertices(*casterOutline,
+ PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
casterRefinementThresholdSquared, casterVertices2d);
if (casterVertices2d.size() == 0) {
@@ -3256,7 +3257,7 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c
// We only have ortho projection, so we can just ignore the Z in caster for
// simple rejection calculation.
Rect localClip = mSnapshot->getLocalClip();
- Rect casterBounds(casterOutline->getBounds());
+ Rect casterBounds(casterPerimeter->getBounds());
casterTransformXY.mapRect(casterBounds);
bool isCasterOpaque = (casterAlpha == 1.0f);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 059c64f..054767e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -210,7 +210,7 @@ public:
virtual status_t drawRects(const float* rects, int count, const SkPaint* paint);
status_t drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ,
- float casterAlpha, const SkPath* casterOutline);
+ float casterAlpha, const SkPath* casterPerimeter);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 4e496e7..530be30 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -58,7 +58,6 @@ public:
mShouldClip = clip;
}
-
bool willClip() const {
// only round rect outlines can be used for clipping
return mShouldClip && (mType == kOutlineType_RoundRect);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index d3daec8..e39e5ae 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -152,18 +152,21 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler,
}
SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
- 0, 0, properties().getWidth(), properties().getHeight(), properties().getAlpha() * 255, saveFlags);
+ 0, 0, properties().getWidth(), properties().getHeight(),
+ properties().getAlpha() * 255, saveFlags);
handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
}
}
if (clipToBoundsNeeded) {
- ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
- properties().getWidth(), properties().getHeight(), SkRegion::kIntersect_Op);
+ ClipRectOp* op = new (handler.allocator()) ClipRectOp(
+ 0, 0, properties().getWidth(), properties().getHeight(), SkRegion::kIntersect_Op);
handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
}
- if (CC_UNLIKELY(properties().getOutline().willClip())) {
- ClipPathOp* op = new (handler.allocator()) ClipPathOp(properties().getOutline().getPath(),
- SkRegion::kIntersect_Op);
+
+ if (CC_UNLIKELY(properties().hasClippingPath())) {
+ // TODO: optimize for round rect/circle clipping
+ const SkPath* path = properties().getClippingPath();
+ ClipPathOp* op = new (handler.allocator()) ClipPathOp(path, SkRegion::kIntersect_Op);
handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
}
}
@@ -408,10 +411,15 @@ void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTransl
mat4 shadowMatrixZ(casterOp->mTransformFromParent);
caster->applyViewPropertyTransforms(shadowMatrixZ, true);
+ const SkPath* outlinePath = caster->properties().getOutline().getPath();
+ const RevealClip& revealClip = caster->properties().getRevealClip();
+ const SkPath* revealClipPath = revealClip.hasConvexClip()
+ ? revealClip.getPath() : NULL; // only pass the reveal clip's path if it's convex
+
DisplayListOp* shadowOp = new (alloc) DrawShadowOp(
- shadowMatrixXY, shadowMatrixZ,
- caster->properties().getAlpha(), caster->properties().getOutline().getPath(),
- caster->properties().getWidth(), caster->properties().getHeight());
+ shadowMatrixXY, shadowMatrixZ, caster->properties().getAlpha(),
+ caster->properties().getWidth(), caster->properties().getHeight(),
+ outlinePath, revealClipPath);
handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
}
@@ -498,7 +506,8 @@ void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level)
setViewProperties<T>(renderer, handler, level + 1);
- bool quickRejected = properties().getClipToBounds() && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
+ bool quickRejected = properties().getClipToBounds()
+ && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
if (!quickRejected) {
Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
buildZSortedChildList(zTranslatedNodes);
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index ca291a6..3975a76 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -22,6 +22,8 @@
#include <SkCanvas.h>
#include <SkMatrix.h>
+#include <SkPath.h>
+#include <SkPathOps.h>
#include "Matrix.h"
@@ -51,13 +53,15 @@ RenderProperties::PrimitiveFields::PrimitiveFields()
RenderProperties::ComputedFields::ComputedFields()
: mTransformMatrix(NULL)
, mTransformCamera(NULL)
- , mTransformMatrix3D(NULL) {
+ , mTransformMatrix3D(NULL)
+ , mClipPath(NULL) {
}
RenderProperties::ComputedFields::~ComputedFields() {
delete mTransformMatrix;
delete mTransformCamera;
delete mTransformMatrix3D;
+ delete mClipPath;
}
RenderProperties::RenderProperties()
@@ -80,6 +84,7 @@ RenderProperties& RenderProperties::operator=(const RenderProperties& other) {
// Update the computed fields
updateMatrix();
+ updateClipPath();
}
return *this;
}
@@ -181,5 +186,39 @@ void RenderProperties::updateMatrix() {
}
}
+void RenderProperties::updateClipPath() {
+ const SkPath* outlineClipPath = mPrimitiveFields.mOutline.willClip()
+ ? mPrimitiveFields.mOutline.getPath() : NULL;
+ const SkPath* revealClipPath = mPrimitiveFields.mRevealClip.getPath();
+
+ if (!outlineClipPath && !revealClipPath) {
+ // mComputedFields.mClipPath doesn't need to be updated, since it won't be used
+ return;
+ }
+
+ if (mComputedFields.mClipPath == NULL) {
+ mComputedFields.mClipPath = new SkPath();
+ }
+ SkPath* clipPath = mComputedFields.mClipPath;
+ mComputedFields.mClipPathOp = SkRegion::kIntersect_Op;
+
+ if (outlineClipPath && revealClipPath) {
+ SkPathOp op = kIntersect_PathOp;
+ if (mPrimitiveFields.mRevealClip.isInverseClip()) {
+ op = kDifference_PathOp; // apply difference step in the Op below, instead of draw time
+ }
+
+ Op(*outlineClipPath, *revealClipPath, op, clipPath);
+ } else if (outlineClipPath) {
+ *clipPath = *outlineClipPath;
+ } else {
+ *clipPath = *revealClipPath;
+ if (mPrimitiveFields.mRevealClip.isInverseClip()) {
+ // apply difference step at draw time
+ mComputedFields.mClipPathOp = SkRegion::kDifference_Op;
+ }
+ }
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 504196d..061e469 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -22,8 +22,10 @@
#include <SkCamera.h>
#include <SkMatrix.h>
+#include <SkRegion.h>
#include "Rect.h"
+#include "RevealClip.h"
#include "Outline.h"
#define TRANSLATION 0x0001
@@ -34,7 +36,6 @@
class SkBitmap;
class SkPaint;
-class SkRegion;
namespace android {
namespace uirenderer {
@@ -415,6 +416,10 @@ public:
return mPrimitiveFields.mOutline;
}
+ const RevealClip& getRevealClip() const {
+ return mPrimitiveFields.mRevealClip;
+ }
+
bool getProjectBackwards() const {
return mPrimitiveFields.mProjectBackwards;
}
@@ -423,10 +428,29 @@ public:
ANDROID_API void updateMatrix();
+ ANDROID_API void updateClipPath();
+
+ // signals that mComputedFields.mClipPath is up to date, and should be used for clipping
+ bool hasClippingPath() const {
+ return mPrimitiveFields.mOutline.willClip() || mPrimitiveFields.mRevealClip.willClip();
+ }
+
+ const SkPath* getClippingPath() const {
+ return hasClippingPath() ? mComputedFields.mClipPath : NULL;
+ }
+
+ SkRegion::Op getClippingPathOp() const {
+ return mComputedFields.mClipPathOp;
+ }
+
Outline& mutableOutline() {
return mPrimitiveFields.mOutline;
}
+ RevealClip& mutableRevealClip() {
+ return mPrimitiveFields.mRevealClip;
+ }
+
private:
void onTranslationUpdate() {
mPrimitiveFields.mMatrixDirty = true;
@@ -442,6 +466,7 @@ private:
PrimitiveFields();
Outline mOutline;
+ RevealClip mRevealClip;
bool mClipToBounds;
bool mProjectBackwards;
bool mProjectionReceiver;
@@ -483,6 +508,8 @@ private:
Matrix4* mTransformMatrix;
Sk3DView* mTransformCamera;
SkMatrix* mTransformMatrix3D;
+ SkPath* mClipPath; // TODO: remove this, create new ops for efficient/special case clipping
+ SkRegion::Op mClipPathOp;
} mComputedFields;
};
diff --git a/libs/hwui/RevealClip.h b/libs/hwui/RevealClip.h
new file mode 100644
index 0000000..ece8498
--- /dev/null
+++ b/libs/hwui/RevealClip.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+#ifndef REVEALCLIP_H
+#define REVEALCLIP_H
+
+#include <SkPath.h>
+
+#include "Rect.h"
+
+namespace android {
+namespace uirenderer {
+
+class RevealClip {
+public:
+ RevealClip()
+ : mShouldClip(false)
+ , mInverseClip(false)
+ , mX(0)
+ , mY(0)
+ , mRadius(0) {}
+
+ void set(bool shouldClip, bool inverseClip, float x, float y, float radius) {
+ mShouldClip = shouldClip;
+ mInverseClip = inverseClip;
+ mX = x;
+ mY = y;
+ mRadius = radius;
+
+ mPath.rewind();
+ if (mShouldClip) {
+ mPath.addCircle(x, y, radius);
+ }
+ }
+
+ bool hasConvexClip() const {
+ return mShouldClip && !mInverseClip;
+ }
+
+ bool isInverseClip() const {
+ return mInverseClip;
+ }
+
+ bool willClip() const {
+ return mShouldClip;
+ }
+
+ const SkPath* getPath() const {
+ if (!mShouldClip) return NULL;
+
+ return &mPath;
+ }
+
+private:
+ bool mShouldClip;
+ bool mInverseClip;
+ float mX;
+ float mY;
+ float mRadius;
+ SkPath mPath;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* REVEALCLIP_H */