From a2fe7affd3d077ac163da90996cb2e5e0ca3b8d1 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Tue, 28 Jan 2014 17:25:06 -0800 Subject: [PATCH] Add initial hidden outline APIs Background drawable outline usage and drawable outline calculation still to come. Change-Id: I8c7539f1638f86e1f8eb11f4fe49f705f61d58ba --- core/java/android/view/DisplayList.java | 28 +++++++++++++++++++++------ core/java/android/view/View.java | 34 +++++++++++++++++++++++++++++++++ core/jni/android_view_DisplayList.cpp | 8 ++++++++ libs/hwui/DisplayList.cpp | 10 +++++----- libs/hwui/DisplayList.h | 9 +++++++++ libs/hwui/DisplayListOp.h | 28 ++++++++++++++++----------- libs/hwui/OpenGLRenderer.cpp | 5 +++++ 7 files changed, 100 insertions(+), 22 deletions(-) diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index 5f6e7cf4bf77..8b6335918ab9 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -17,6 +17,7 @@ package android.view; import android.graphics.Matrix; +import android.graphics.Path; import java.util.ArrayList; @@ -151,7 +152,7 @@ public class DisplayList { /** * Indicates that the display list is done drawing. - * + * * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) * * @hide @@ -160,7 +161,7 @@ public class DisplayList { /** * Indicates that the display list needs another drawing pass. - * + * * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) * * @hide @@ -169,9 +170,9 @@ public class DisplayList { /** * Indicates that the display list needs to re-execute its GL functors. - * - * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) - * @see HardwareCanvas#callDrawGLFunction(int) + * + * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) + * @see HardwareCanvas#callDrawGLFunction(long) * * @hide */ @@ -406,7 +407,7 @@ public class DisplayList { * Set whether the display list should collect and Z order all 3d composited descendents, and * draw them in order with the default Z=0 content. * - * @param isolateZVolume true if the display list should collect and Z order descendents. + * @param isolatedZVolume true if the display list should collect and Z order descendents. */ public void setIsolatedZVolume(boolean isolatedZVolume) { if (hasNativeDisplayList()) { @@ -430,6 +431,20 @@ public class DisplayList { } /** + * Sets the outline, defining the shape that casts a shadow. + * + * Deep copies the native path to simplify reference ownership. + * + * @param outline Convex, CW Path to store in the DisplayList. May be null. + */ + public void setOutline(Path outline) { + if (hasNativeDisplayList()) { + long nativePath = (outline == null) ? 0 : outline.mNativePath; + nSetOutline(mFinalizer.mNativeDisplayList, nativePath); + } + } + + /** * 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.) * @@ -1051,6 +1066,7 @@ public class DisplayList { private static native void nSetClipToBounds(long displayList, boolean clipToBounds); private static native void nSetProjectBackwards(long displayList, boolean shouldProject); private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume); + private static native void nSetOutline(long displayList, long nativePath); 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 9576602b1f6a..239eda44f3a2 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -32,6 +32,7 @@ import android.graphics.Interpolator; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PorterDuff; @@ -3295,6 +3296,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private int[] mDrawableState = null; /** + * Stores the outline of the view, passed down to the DisplayList level for shadow shape. + */ + private Path mOutline; + + /** * When this view has focus and the next focus is {@link #FOCUS_LEFT}, * the user may specify which view to go to next. */ @@ -10624,6 +10630,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * @hide + */ + public final void getOutline(Path outline) { + if (mOutline == null) { + outline.reset(); + } else { + outline.set(mOutline); + } + } + + /** + * @hide + */ + public void setOutline(Path path) { + // always copy the path since caller may reuse + if (mOutline == null) { + mOutline = new Path(path); + } else { + mOutline.set(path); + } + + if (mDisplayList != null) { + mDisplayList.setOutline(path); + } + } + + /** * Hit rectangle in parent's coordinates * * @param outRect The hit rectangle of the view. @@ -14266,6 +14299,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, displayList.setIsolatedZVolume( (((ViewGroup) this).mGroupFlags & ViewGroup.FLAG_ISOLATED_Z_VOLUME) != 0); } + displayList.setOutline(mOutline); float alpha = 1; if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp index 61d2a5eec3e4..9379375108be 100644 --- a/core/jni/android_view_DisplayList.cpp +++ b/core/jni/android_view_DisplayList.cpp @@ -117,6 +117,13 @@ static void android_view_DisplayList_setProjectBackwards(JNIEnv* env, displayList->setProjectBackwards(shouldProject); } +static void android_view_DisplayList_setOutline(JNIEnv* env, + jobject clazz, jlong displayListPtr, jlong outlinePathPtr) { + DisplayList* displayList = reinterpret_cast(displayListPtr); + SkPath* outline = reinterpret_cast(outlinePathPtr); + displayList->setOutline(outline); +} + static void android_view_DisplayList_setAlpha(JNIEnv* env, jobject clazz, jlong displayListPtr, float alpha) { DisplayList* displayList = reinterpret_cast(displayListPtr); @@ -385,6 +392,7 @@ static JNINativeMethod gMethods[] = { { "nSetClipToBounds", "(JZ)V", (void*) android_view_DisplayList_setClipToBounds }, { "nSetIsolatedZVolume", "(JZ)V", (void*) android_view_DisplayList_setIsolatedZVolume }, { "nSetProjectBackwards", "(JZ)V", (void*) android_view_DisplayList_setProjectBackwards }, + { "nSetOutline", "(JJ)V", (void*) android_view_DisplayList_setOutline }, { "nSetAlpha", "(JF)V", (void*) android_view_DisplayList_setAlpha }, { "nSetHasOverlappingRendering", "(JZ)V", (void*) android_view_DisplayList_setHasOverlappingRendering }, diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 66a526a7a2e6..fd3dae7dfd71 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -240,6 +240,7 @@ void DisplayList::init() { mClipToBounds = true; mIsolatedZVolume = true; mProjectBackwards = false; + mOutline.rewind(); mAlpha = 1; mHasOverlappingRendering = true; mTranslationX = 0; @@ -654,16 +655,15 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren /* draw shadow with parent matrix applied, passing in the child's total matrix * * TODO: - * -determine and pass background shape (and possibly drawable alpha) * -view must opt-in to shadows - * -consider shadows for other content - * -inform shadow system of ancestor transform (for use in lighting) + * -consider depth in more complex scenarios (neg z, added shadow depth) */ mat4 shadowMatrix(childOp->mTransformFromCompositingAncestor); childOp->mDisplayList->applyViewPropertyTransforms(shadowMatrix); + DisplayList* child = childOp->mDisplayList; + DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, - childOp->mDisplayList->mAlpha, - childOp->mDisplayList->getWidth(), childOp->mDisplayList->getHeight()); + child->mAlpha, &(child->mOutline), child->mWidth, child->mHeight); handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); } diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index 6d9a8c125de4..8622d619629e 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -198,6 +198,14 @@ public: mProjectBackwards = shouldProject; } + void setOutline(const SkPath* outline) { + if (!outline) { + mOutline.reset(); + } else { + mOutline = *outline; + } + } + void setStaticMatrix(SkMatrix* matrix) { delete mStaticMatrix; mStaticMatrix = new SkMatrix(*matrix); @@ -592,6 +600,7 @@ private: bool mClipToBounds; bool mIsolatedZVolume; bool mProjectBackwards; + SkPath mOutline; float mAlpha; bool mHasOverlappingRendering; float mTranslationX, mTranslationY, mTranslationZ; diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 5024880889de..20bc93d39626 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1584,27 +1584,33 @@ private: */ class DrawShadowOp : public DrawOp { public: - DrawShadowOp(const mat4& casterTransform, float casterAlpha, float width, float height) - : DrawOp(NULL), mCasterTransform(casterTransform), mCasterAlpha(casterAlpha), - mWidth(width), mHeight(height) {} + DrawShadowOp(const mat4& transform, float alpha, const SkPath* outline, + float fallbackWidth, float fallbackHeight) + : DrawOp(NULL), mTransform(transform), mAlpha(alpha), mOutline(outline), + mFallbackWidth(fallbackWidth), mFallbackHeight(fallbackHeight) {} virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { - SkPath casterOutline; // TODO: drive with path from view - casterOutline.addRect(0, 0, mWidth, mHeight); - return renderer.drawShadow(mCasterTransform, mCasterAlpha, &casterOutline); + if (!mOutline->isEmpty()) { + return renderer.drawShadow(mTransform, mAlpha, mOutline); + } + + SkPath fakeOutline; + fakeOutline.addRect(0, 0, mFallbackWidth, mFallbackHeight); + return renderer.drawShadow(mTransform, mAlpha, &fakeOutline); } virtual void output(int level, uint32_t logFlags) const { - OP_LOG("DrawShadow of width %.2f, height %.2f", mWidth, mHeight); + OP_LOG("DrawShadow of outline %p", mOutline); } virtual const char* name() { return "DrawShadow"; } private: - const mat4 mCasterTransform; - const float mCasterAlpha; - const float mWidth; - const float mHeight; + const mat4 mTransform; + const float mAlpha; + const SkPath* mOutline; + const float mFallbackWidth; + const float mFallbackHeight; }; class DrawLayerOp : public DrawOp { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 7a1194870d57..b71082572ce2 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -3199,6 +3199,11 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlp PathTessellator::approximatePathOutlineVertices(*casterOutline, casterRefinementThresholdSquared, casterVertices2d); + if (casterVertices2d.size() == 0) { + // empty caster polygon computed from path + return DrawGlInfo::kStatusDone; + } + // map 2d caster poly into 3d const int casterVertexCount = casterVertices2d.size(); Vector3 casterPolygon[casterVertexCount]; -- 2.11.0