diff options
-rw-r--r-- | core/java/android/view/RenderNode.java | 10 | ||||
-rw-r--r-- | core/java/android/view/View.java | 13 | ||||
-rw-r--r-- | core/jni/android_view_RenderNode.cpp | 16 | ||||
-rw-r--r-- | libs/hwui/DisplayListOp.h | 34 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/Outline.h | 1 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 29 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.cpp | 41 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.h | 29 | ||||
-rw-r--r-- | libs/hwui/RevealClip.h | 78 |
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 */ |