diff options
-rw-r--r-- | core/java/android/view/GLES20RecordingCanvas.java | 7 | ||||
-rw-r--r-- | core/java/android/view/RenderNode.java | 72 | ||||
-rw-r--r-- | core/java/android/view/View.java | 46 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 5 | ||||
-rw-r--r-- | core/jni/android_view_RenderNode.cpp | 49 | ||||
-rw-r--r-- | graphics/java/android/graphics/Canvas.java | 3 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 22 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.cpp | 30 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.h | 57 |
9 files changed, 149 insertions, 142 deletions
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java index b2961e5..5e49d8e 100644 --- a/core/java/android/view/GLES20RecordingCanvas.java +++ b/core/java/android/view/GLES20RecordingCanvas.java @@ -17,6 +17,7 @@ package android.view; import android.annotation.NonNull; +import android.annotation.Nullable; import android.util.Pools.SynchronizedPool; /** @@ -41,7 +42,6 @@ class GLES20RecordingCanvas extends GLES20Canvas { static GLES20RecordingCanvas obtain(@NonNull RenderNode node) { if (node == null) throw new IllegalArgumentException("node cannot be null"); - GLES20RecordingCanvas canvas = sPool.acquire(); if (canvas == null) { canvas = new GLES20RecordingCanvas(); @@ -58,4 +58,9 @@ class GLES20RecordingCanvas extends GLES20Canvas { long finishRecording() { return nFinishRecording(mRenderer); } + + @Override + public boolean isRecordingFor(Object o) { + return o == mNode; + } } diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 73c7321..8aba8af 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -17,9 +17,11 @@ package android.view; import android.annotation.NonNull; +import android.annotation.Nullable; import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; +import android.graphics.Rect; /** * <p>A display list records a series of graphics related operations and can replay @@ -294,13 +296,6 @@ public class RenderNode { // RenderProperty Setters /////////////////////////////////////////////////////////////////////////// - /** - * Set the caching property on the display list, which indicates whether the display list - * holds a layer. Layer display lists should avoid creating an alpha layer, since alpha is - * handled in the drawLayer operation directly (and more efficiently). - * - * @param caching true if the display list represents a hardware layer, false otherwise. - */ public boolean setLayerType(int layerType) { return nSetLayerType(mNativeRenderNode, layerType); } @@ -309,6 +304,14 @@ public class RenderNode { return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.mNativePaint : 0); } + public boolean setClipBounds(@Nullable Rect rect) { + if (rect == null) { + return nSetClipBoundsEmpty(mNativeRenderNode); + } else { + return nSetClipBounds(mNativeRenderNode, rect.left, rect.top, rect.right, rect.bottom); + } + } + /** * Set whether the Render node should clip itself to its bounds. This property is controlled by * the view's parent. @@ -702,85 +705,45 @@ public class RenderNode { * @param left The left position, in pixels, of the display list * * @see View#setLeft(int) - * @see #getLeft() */ public boolean setLeft(int left) { return nSetLeft(mNativeRenderNode, left); } /** - * Returns the left position for the display list in pixels. - * - * @see #setLeft(int) - */ - public float getLeft() { - return nGetLeft(mNativeRenderNode); - } - - /** * Sets the top position for the display list. * * @param top The top position, in pixels, of the display list * * @see View#setTop(int) - * @see #getTop() */ public boolean setTop(int top) { return nSetTop(mNativeRenderNode, top); } /** - * Returns the top position for the display list in pixels. - * - * @see #setTop(int) - */ - public float getTop() { - return nGetTop(mNativeRenderNode); - } - - /** * Sets the right position for the display list. * * @param right The right position, in pixels, of the display list * * @see View#setRight(int) - * @see #getRight() */ public boolean setRight(int right) { return nSetRight(mNativeRenderNode, right); } /** - * Returns the right position for the display list in pixels. - * - * @see #setRight(int) - */ - public float getRight() { - return nGetRight(mNativeRenderNode); - } - - /** * Sets the bottom position for the display list. * * @param bottom The bottom position, in pixels, of the display list * * @see View#setBottom(int) - * @see #getBottom() */ public boolean setBottom(int bottom) { return nSetBottom(mNativeRenderNode, bottom); } /** - * Returns the bottom position for the display list in pixels. - * - * @see #setBottom(int) - */ - public float getBottom() { - return nGetBottom(mNativeRenderNode); - } - - /** * Sets the left and top positions for the display list * * @param left The left position of the display list, in pixels @@ -805,7 +768,7 @@ public class RenderNode { * * @see View#offsetLeftAndRight(int) */ - public boolean offsetLeftAndRight(float offset) { + public boolean offsetLeftAndRight(int offset) { return nOffsetLeftAndRight(mNativeRenderNode, offset); } @@ -817,7 +780,7 @@ public class RenderNode { * * @see View#offsetTopAndBottom(int) */ - public boolean offsetTopAndBottom(float offset) { + public boolean offsetTopAndBottom(int offset) { return nOffsetTopAndBottom(mNativeRenderNode, offset); } @@ -860,8 +823,8 @@ public class RenderNode { // Properties - private static native boolean nOffsetTopAndBottom(long renderNode, float offset); - private static native boolean nOffsetLeftAndRight(long renderNode, float offset); + private static native boolean nOffsetTopAndBottom(long renderNode, int offset); + private static native boolean nOffsetLeftAndRight(long renderNode, int offset); private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top, int right, int bottom); private static native boolean nSetBottom(long renderNode, int bottom); @@ -874,6 +837,9 @@ public class RenderNode { private static native boolean nSetLayerType(long renderNode, int layerType); private static native boolean nSetLayerPaint(long renderNode, long paint); private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds); + private static native boolean nSetClipBounds(long renderNode, int left, int top, + int right, int bottom); + private static native boolean nSetClipBoundsEmpty(long renderNode); private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject); private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve); private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top, @@ -902,10 +868,6 @@ public class RenderNode { private static native boolean nHasOverlappingRendering(long renderNode); private static native boolean nGetClipToOutline(long renderNode); private static native float nGetAlpha(long renderNode); - private static native float nGetLeft(long renderNode); - private static native float nGetTop(long renderNode); - private static native float nGetRight(long renderNode); - private static native float nGetBottom(long renderNode); private static native float nGetCameraDistance(long renderNode); private static native float nGetScaleX(long renderNode); private static native float nGetScaleY(long renderNode); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0079cc9..4c1c2f9 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -724,11 +724,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static boolean sIgnoreMeasureCache = false; /** - * Ignore the clipBounds of this view for the children. - */ - static boolean sIgnoreClipBoundsForChildren = false; - - /** * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when * calling setFlags. */ @@ -3558,9 +3553,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // of whether a layout was requested on that View. sIgnoreMeasureCache = targetSdkVersion < KITKAT; - // Older apps may need this to ignore the clip bounds - sIgnoreClipBoundsForChildren = targetSdkVersion < L; - sCompatibilityDone = true; } } @@ -14309,6 +14301,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mClipBounds = null; } } + mRenderNode.setClipBounds(mClipBounds); } /** @@ -14430,7 +14423,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * to be called from anywhere else other than ViewGroup.drawChild(). */ boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { - boolean useDisplayListProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated; + boolean usingRenderNodeProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated; boolean more = false; final boolean childHasIdentityMatrix = hasIdentityMatrix(); final int flags = parent.mGroupFlags; @@ -14471,7 +14464,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mRenderNode.setAnimationMatrix(null); mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; } - if (!useDisplayListProperties && + if (!usingRenderNodeProperties && (flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { final Transformation t = parent.getChildTransformation(); final boolean hasTransform = parent.getChildStaticTransformation(this, t); @@ -14519,7 +14512,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { switch (layerType) { case LAYER_TYPE_SOFTWARE: - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { hasDisplayList = canHaveDisplayList(); } else { buildDrawingCache(true); @@ -14527,7 +14520,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } break; case LAYER_TYPE_HARDWARE: - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { hasDisplayList = canHaveDisplayList(); } break; @@ -14539,8 +14532,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } } - useDisplayListProperties &= hasDisplayList; - if (useDisplayListProperties) { + usingRenderNodeProperties &= hasDisplayList; + if (usingRenderNodeProperties) { renderNode = getDisplayList(); if (!renderNode.isValid()) { // Uncommon, but possible. If a view is removed from the hierarchy during the call @@ -14548,7 +14541,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // try to use it again. renderNode = null; hasDisplayList = false; - useDisplayListProperties = false; + usingRenderNodeProperties = false; } } @@ -14565,17 +14558,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, layerType != LAYER_TYPE_HARDWARE; int restoreTo = -1; - if (!useDisplayListProperties || transformToApply != null) { + if (!usingRenderNodeProperties || transformToApply != null) { restoreTo = canvas.save(); } if (offsetForScroll) { canvas.translate(mLeft - sx, mTop - sy); } else { - if (!useDisplayListProperties) { + if (!usingRenderNodeProperties) { canvas.translate(mLeft, mTop); } if (scalingRequired) { - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { // TODO: Might not need this if we put everything inside the DL restoreTo = canvas.save(); } @@ -14585,7 +14578,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - float alpha = useDisplayListProperties ? 1 : (getAlpha() * getTransitionAlpha()); + float alpha = usingRenderNodeProperties ? 1 : (getAlpha() * getTransitionAlpha()); if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) { if (transformToApply != null || !childHasIdentityMatrix) { @@ -14599,7 +14592,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (transformToApply != null) { if (concatMatrix) { - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { renderNode.setAnimationMatrix(transformToApply.getMatrix()); } else { // Undo the scroll translation, apply the transformation matrix, @@ -14618,7 +14611,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - if (!childHasIdentityMatrix && !useDisplayListProperties) { + if (!childHasIdentityMatrix && !usingRenderNodeProperties) { canvas.translate(-transX, -transY); canvas.concat(getMatrix()); canvas.translate(transX, transY); @@ -14642,7 +14635,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, layerType != LAYER_TYPE_NONE) { layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG; } - if (useDisplayListProperties) { + if (usingRenderNodeProperties) { renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); } else if (layerType == LAYER_TYPE_NONE) { final int scrollX = hasDisplayList ? 0 : sx; @@ -14662,7 +14655,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) == ViewGroup.FLAG_CLIP_CHILDREN && - !useDisplayListProperties && cache == null) { + !usingRenderNodeProperties && cache == null) { if (offsetForScroll) { canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop)); } else { @@ -14674,7 +14667,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } - if (!useDisplayListProperties && hasDisplayList) { + if (!usingRenderNodeProperties && hasDisplayList) { renderNode = getDisplayList(); if (!renderNode.isValid()) { // Uncommon, but possible. If a view is removed from the hierarchy during the call @@ -14687,7 +14680,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (hasNoCache) { boolean layerRendered = false; - if (layerType == LAYER_TYPE_HARDWARE && !useDisplayListProperties) { + if (layerType == LAYER_TYPE_HARDWARE && !usingRenderNodeProperties) { final HardwareLayer layer = getHardwareLayer(); if (layer != null && layer.isValid()) { mLayerPaint.setAlpha((int) (alpha * 255)); @@ -14774,7 +14767,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param canvas The Canvas to which the View is rendered. */ public void draw(Canvas canvas) { - if (mClipBounds != null) { + boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode); + if (mClipBounds != null && !usingRenderNodeProperties) { canvas.clipRect(mClipBounds); } final int privateFlags = mPrivateFlags; diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 1028a0c..c4c3242 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3015,6 +3015,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ @Override protected void dispatchDraw(Canvas canvas) { + boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode); final int childrenCount = mChildrenCount; final View[] children = mChildren; int flags = mGroupFlags; @@ -3059,7 +3060,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager int clipSaveCount = 0; final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK; - boolean hasClipBounds = mClipBounds != null && !sIgnoreClipBoundsForChildren; + boolean hasClipBounds = mClipBounds != null && !usingRenderNodeProperties; boolean clippingNeeded = clipToPadding || hasClipBounds; if (clippingNeeded) { @@ -3087,7 +3088,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Only use the preordered list if not HW accelerated, since the HW pipeline will do the // draw reordering internally - final ArrayList<View> preorderedList = canvas.isHardwareAccelerated() + final ArrayList<View> preorderedList = usingRenderNodeProperties ? null : buildOrderedChildList(); final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 1f3909a..3b6f0eb 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -117,6 +117,17 @@ static jboolean android_view_RenderNode_setClipToBounds(JNIEnv* env, return SET_AND_DIRTY(setClipToBounds, clipToBounds, RenderNode::GENERIC); } +static jboolean android_view_RenderNode_setClipBounds(JNIEnv* env, + jobject clazz, jlong renderNodePtr, jint left, jint top, jint right, jint bottom) { + android::uirenderer::Rect clipBounds(left, top, right, bottom); + return SET_AND_DIRTY(setClipBounds, clipBounds, RenderNode::GENERIC); +} + +static jboolean android_view_RenderNode_setClipBoundsEmpty(JNIEnv* env, + jobject clazz, jlong renderNodePtr) { + return SET_AND_DIRTY(setClipBoundsEmpty,, RenderNode::GENERIC); +} + static jboolean android_view_RenderNode_setProjectBackwards(JNIEnv* env, jobject clazz, jlong renderNodePtr, jboolean shouldProject) { return SET_AND_DIRTY(setProjectBackwards, shouldProject, RenderNode::GENERIC); @@ -282,12 +293,12 @@ static jboolean android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env, } static jboolean android_view_RenderNode_offsetLeftAndRight(JNIEnv* env, - jobject clazz, jlong renderNodePtr, float offset) { + jobject clazz, jlong renderNodePtr, jint offset) { return SET_AND_DIRTY(offsetLeftRight, offset, RenderNode::X); } static jboolean android_view_RenderNode_offsetTopAndBottom(JNIEnv* env, - jobject clazz, jlong renderNodePtr, float offset) { + jobject clazz, jlong renderNodePtr, jint offset) { return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y); } @@ -313,30 +324,6 @@ static jfloat android_view_RenderNode_getAlpha(JNIEnv* env, return renderNode->stagingProperties().getAlpha(); } -static jfloat android_view_RenderNode_getLeft(JNIEnv* env, - jobject clazz, jlong renderNodePtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - return renderNode->stagingProperties().getLeft(); -} - -static jfloat android_view_RenderNode_getTop(JNIEnv* env, - jobject clazz, jlong renderNodePtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - return renderNode->stagingProperties().getTop(); -} - -static jfloat android_view_RenderNode_getRight(JNIEnv* env, - jobject clazz, jlong renderNodePtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - return renderNode->stagingProperties().getRight(); -} - -static jfloat android_view_RenderNode_getBottom(JNIEnv* env, - jobject clazz, jlong renderNodePtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - return renderNode->stagingProperties().getBottom(); -} - static jfloat android_view_RenderNode_getCameraDistance(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); @@ -488,6 +475,8 @@ static JNINativeMethod gMethods[] = { { "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix }, { "nSetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix }, { "nSetClipToBounds", "(JZ)Z", (void*) android_view_RenderNode_setClipToBounds }, + { "nSetClipBounds", "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds }, + { "nSetClipBoundsEmpty", "(J)Z", (void*) android_view_RenderNode_setClipBoundsEmpty }, { "nSetProjectBackwards", "(JZ)Z", (void*) android_view_RenderNode_setProjectBackwards }, { "nSetProjectionReceiver","(JZ)Z", (void*) android_view_RenderNode_setProjectionReceiver }, @@ -518,16 +507,12 @@ static JNINativeMethod gMethods[] = { { "nSetRight", "(JI)Z", (void*) android_view_RenderNode_setRight }, { "nSetBottom", "(JI)Z", (void*) android_view_RenderNode_setBottom }, { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom }, - { "nOffsetLeftAndRight", "(JF)Z", (void*) android_view_RenderNode_offsetLeftAndRight }, - { "nOffsetTopAndBottom", "(JF)Z", (void*) android_view_RenderNode_offsetTopAndBottom }, + { "nOffsetLeftAndRight", "(JI)Z", (void*) android_view_RenderNode_offsetLeftAndRight }, + { "nOffsetTopAndBottom", "(JI)Z", (void*) android_view_RenderNode_offsetTopAndBottom }, { "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering }, { "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline }, { "nGetAlpha", "(J)F", (void*) android_view_RenderNode_getAlpha }, - { "nGetLeft", "(J)F", (void*) android_view_RenderNode_getLeft }, - { "nGetTop", "(J)F", (void*) android_view_RenderNode_getTop }, - { "nGetRight", "(J)F", (void*) android_view_RenderNode_getRight }, - { "nGetBottom", "(J)F", (void*) android_view_RenderNode_getBottom }, { "nGetCameraDistance", "(J)F", (void*) android_view_RenderNode_getCameraDistance }, { "nGetScaleX", "(J)F", (void*) android_view_RenderNode_getScaleX }, { "nGetScaleY", "(J)F", (void*) android_view_RenderNode_getScaleY }, diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index ef4b260..f3af8f6 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -52,6 +52,9 @@ public class Canvas { return mNativeCanvasWrapper; } + /** @hide */ + public boolean isRecordingFor(Object o) { return false; } + // may be null private Bitmap mBitmap; diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index b77b36f..01c7761 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -347,31 +347,35 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) { } } const bool isLayer = properties().layerProperties().type() != kLayerTypeNone; - bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds(); + int clipFlags = properties().getClippingFlags(); if (properties().getAlpha() < 1) { if (isLayer) { + clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer + renderer.setOverrideLayerAlpha(properties().getAlpha()); } else if (!properties().getHasOverlappingRendering()) { renderer.scaleAlpha(properties().getAlpha()); } else { - // TODO: should be able to store the size of a DL at record time and not - // have to pass it into this call. In fact, this information might be in the - // location/size info that we store with the new native transform data. + Rect layerBounds(0, 0, getWidth(), getHeight()); int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag; - if (clipToBoundsNeeded) { + if (clipFlags) { saveFlags |= SkCanvas::kClipToLayer_SaveFlag; - clipToBoundsNeeded = false; // clipping done by saveLayer + properties().getClippingRectForFlags(clipFlags, &layerBounds); + clipFlags = 0; // all clipping done by saveLayer } SaveLayerOp* op = new (handler.allocator()) SaveLayerOp( - 0, 0, properties().getWidth(), properties().getHeight(), + layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom, properties().getAlpha() * 255, saveFlags); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } } - if (clipToBoundsNeeded) { + if (clipFlags) { + Rect clipRect; + properties().getClippingRectForFlags(clipFlags, &clipRect); ClipRectOp* op = new (handler.allocator()) ClipRectOp( - 0, 0, properties().getWidth(), properties().getHeight(), SkRegion::kIntersect_Op); + clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, + SkRegion::kIntersect_Op); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp index 8848b2f..250cadc 100644 --- a/libs/hwui/RenderProperties.cpp +++ b/libs/hwui/RenderProperties.cpp @@ -75,7 +75,7 @@ LayerProperties& LayerProperties::operator=(const LayerProperties& other) { } RenderProperties::PrimitiveFields::PrimitiveFields() - : mClipToBounds(true) + : mClippingFlags(CLIP_TO_BOUNDS) , mProjectBackwards(false) , mProjectionReceiver(false) , mAlpha(1) @@ -146,26 +146,34 @@ void RenderProperties::debugOutputProperties(const int level) const { } } - bool clipToBoundsNeeded = layerProperties().type() != kLayerTypeNone ? false : mPrimitiveFields.mClipToBounds; + const bool isLayer = layerProperties().type() != kLayerTypeNone; + int clipFlags = getClippingFlags(); if (mPrimitiveFields.mAlpha < 1) { - if (layerProperties().type() != kLayerTypeNone) { + if (isLayer) { + clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer + ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha); } else if (!mPrimitiveFields.mHasOverlappingRendering) { ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha); } else { - int flags = SkCanvas::kHasAlphaLayer_SaveFlag; - if (clipToBoundsNeeded) { - flags |= SkCanvas::kClipToLayer_SaveFlag; - clipToBoundsNeeded = false; // clipping done by save layer + Rect layerBounds(0, 0, getWidth(), getHeight()); + int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag; + if (clipFlags) { + saveFlags |= SkCanvas::kClipToLayer_SaveFlag; + getClippingRectForFlags(clipFlags, &layerBounds); + clipFlags = 0; // all clipping done by saveLayer } + ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "", - 0, 0, getWidth(), getHeight(), - (int)(mPrimitiveFields.mAlpha * 255), flags); + (int)layerBounds.left, (int)layerBounds.top, (int)layerBounds.right, (int)layerBounds.bottom, + (int)(mPrimitiveFields.mAlpha * 255), saveFlags); } } - if (clipToBoundsNeeded) { + if (clipFlags) { + Rect clipRect; + getClippingRectForFlags(clipFlags, &clipRect); ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "", - 0, 0, getWidth(), getHeight()); + (int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom); } } diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 227d56e..f50e514 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -58,6 +58,11 @@ enum LayerType { // TODO: LayerTypeSurfaceTexture? Maybe? }; +enum ClippingFlags { + CLIP_TO_BOUNDS = 0x1 << 0, + CLIP_TO_CLIP_BOUNDS = 0x1 << 1, +}; + class ANDROID_API LayerProperties { public: bool setType(LayerType type) { @@ -135,10 +140,35 @@ public: RenderProperties(); virtual ~RenderProperties(); + static bool setFlag(int flag, bool newValue, int* outFlags) { + if (newValue) { + if (!(flag & *outFlags)) { + *outFlags |= flag; + return true; + } + return false; + } else { + if (flag & *outFlags) { + *outFlags &= ~flag; + return true; + } + return false; + } + } + RenderProperties& operator=(const RenderProperties& other); bool setClipToBounds(bool clipToBounds) { - return RP_SET(mPrimitiveFields.mClipToBounds, clipToBounds); + return setFlag(CLIP_TO_BOUNDS, clipToBounds, &mPrimitiveFields.mClippingFlags); + } + + bool setClipBounds(const Rect& clipBounds) { + bool ret = setFlag(CLIP_TO_CLIP_BOUNDS, true, &mPrimitiveFields.mClippingFlags); + return RP_SET(mPrimitiveFields.mClipBounds, clipBounds) || ret; + } + + bool setClipBoundsEmpty() { + return setFlag(CLIP_TO_CLIP_BOUNDS, false, &mPrimitiveFields.mClippingFlags); } bool setProjectBackwards(bool shouldProject) { @@ -433,7 +463,7 @@ public: return false; } - bool offsetLeftRight(float offset) { + bool offsetLeftRight(int offset) { if (offset != 0) { mPrimitiveFields.mLeft += offset; mPrimitiveFields.mRight += offset; @@ -442,7 +472,7 @@ public: return false; } - bool offsetTopBottom(float offset) { + bool offsetTopBottom(int offset) { if (offset != 0) { mPrimitiveFields.mTop += offset; mPrimitiveFields.mBottom += offset; @@ -477,8 +507,23 @@ public: return mComputedFields.mTransformMatrix; } + int getClippingFlags() const { + return mPrimitiveFields.mClippingFlags; + } + bool getClipToBounds() const { - return mPrimitiveFields.mClipToBounds; + return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS; + } + + void getClippingRectForFlags(uint32_t flags, Rect* outRect) const { + if (flags & CLIP_TO_BOUNDS) { + outRect->set(0, 0, getWidth(), getHeight()); + if (flags & CLIP_TO_CLIP_BOUNDS) { + outRect->intersect(mPrimitiveFields.mClipBounds); + } + } else { + outRect->set(mPrimitiveFields.mClipBounds); + } } bool getHasOverlappingRendering() const { @@ -540,14 +585,13 @@ public: } private: - // Rendering properties struct PrimitiveFields { PrimitiveFields(); Outline mOutline; RevealClip mRevealClip; - bool mClipToBounds; + int mClippingFlags; bool mProjectBackwards; bool mProjectionReceiver; float mAlpha; @@ -561,6 +605,7 @@ private: int mWidth, mHeight; bool mPivotExplicitlySet; bool mMatrixOrPivotDirty; + Rect mClipBounds; } mPrimitiveFields; SkMatrix* mStaticMatrix; |