am 76c30ce3
: Merge "Rework Outline API, remove isolatedZVolume remnants"
* commit '76c30ce3c1d8f1a818502aaea2c42c84d6bd3f92': Rework Outline API, remove isolatedZVolume remnants
This commit is contained in:
@ -9798,6 +9798,13 @@ package android.graphics {
|
||||
method public void setPaint(android.graphics.Paint);
|
||||
}
|
||||
|
||||
public class Outline {
|
||||
ctor public Outline();
|
||||
method public final boolean isValid();
|
||||
method public void set(android.graphics.Outline);
|
||||
method public void setRoundRect(int, int, int, int, float);
|
||||
}
|
||||
|
||||
public class Paint {
|
||||
ctor public Paint();
|
||||
ctor public Paint(int);
|
||||
@ -10507,6 +10514,7 @@ package android.graphics.drawable {
|
||||
method public int getMinimumHeight();
|
||||
method public int getMinimumWidth();
|
||||
method public abstract int getOpacity();
|
||||
method public android.graphics.Outline getOutline();
|
||||
method public boolean getPadding(android.graphics.Rect);
|
||||
method public int[] getState();
|
||||
method public android.graphics.Region getTransparentRegion();
|
||||
@ -29322,7 +29330,6 @@ package android.view {
|
||||
method public int getNextFocusRightId();
|
||||
method public int getNextFocusUpId();
|
||||
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
|
||||
method public final void getOutline(android.graphics.Path);
|
||||
method public int getOverScrollMode();
|
||||
method public android.view.ViewOverlay getOverlay();
|
||||
method public int getPaddingBottom();
|
||||
@ -29586,7 +29593,7 @@ package android.view {
|
||||
method public void setOnLongClickListener(android.view.View.OnLongClickListener);
|
||||
method public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
|
||||
method public void setOnTouchListener(android.view.View.OnTouchListener);
|
||||
method public void setOutline(android.graphics.Path);
|
||||
method public void setOutline(android.graphics.Outline);
|
||||
method public void setOverScrollMode(int);
|
||||
method public void setPadding(int, int, int, int);
|
||||
method public void setPaddingRelative(int, int, int, int);
|
||||
|
@ -17,7 +17,7 @@
|
||||
package android.view;
|
||||
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Outline;
|
||||
|
||||
/**
|
||||
* <p>A display list records a series of graphics related operations and can replay
|
||||
@ -310,16 +310,6 @@ public class RenderNode {
|
||||
nSetClipToBounds(mNativeDisplayList, clipToBounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 isolatedZVolume true if the display list should collect and Z order descendents.
|
||||
*/
|
||||
public void setIsolatedZVolume(boolean isolatedZVolume) {
|
||||
nSetIsolatedZVolume(mNativeDisplayList, isolatedZVolume);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the display list should be drawn immediately after the
|
||||
* closest ancestor display list where isolateZVolume is true. If the
|
||||
@ -346,13 +336,19 @@ public class RenderNode {
|
||||
* Sets the outline, defining the shape that casts a shadow, and the path to
|
||||
* be clipped if setClipToOutline is set.
|
||||
*
|
||||
* Deep copies the native path to simplify reference ownership.
|
||||
*
|
||||
* @param outline Convex, CW Path to store in the DisplayList. May be null.
|
||||
* Deep copies the data into native to simplify reference ownership.
|
||||
*/
|
||||
public void setOutline(Path outline) {
|
||||
long nativePath = (outline == null) ? 0 : outline.mNativePath;
|
||||
nSetOutline(mNativeDisplayList, nativePath);
|
||||
public void setOutline(Outline outline) {
|
||||
if (outline == null) {
|
||||
nSetOutlineEmpty(mNativeDisplayList);
|
||||
} else if (!outline.isValid()) {
|
||||
throw new IllegalArgumentException("Outline must be valid");
|
||||
} else if (outline.mRect != null) {
|
||||
nSetOutlineRoundRect(mNativeDisplayList, outline.mRect.left, outline.mRect.top,
|
||||
outline.mRect.right, outline.mRect.bottom, outline.mRadius);
|
||||
} else if (outline.mPath != null) {
|
||||
nSetOutlineConvexPath(mNativeDisplayList, outline.mPath.mNativePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -855,8 +851,10 @@ public class RenderNode {
|
||||
private static native void nSetClipToBounds(long displayList, boolean clipToBounds);
|
||||
private static native void nSetProjectBackwards(long displayList, boolean shouldProject);
|
||||
private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve);
|
||||
private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume);
|
||||
private static native void nSetOutline(long displayList, long nativePath);
|
||||
private static native void nSetOutlineRoundRect(long displayList, int left, int top,
|
||||
int right, int bottom, float radius);
|
||||
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 nSetAlpha(long displayList, float alpha);
|
||||
private static native void nSetHasOverlappingRendering(long displayList,
|
||||
|
@ -31,6 +31,7 @@ import android.graphics.Insets;
|
||||
import android.graphics.Interpolator;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PixelFormat;
|
||||
@ -2376,15 +2377,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
*/
|
||||
static final int PFLAG3_CLIP_TO_OUTLINE = 0x20;
|
||||
|
||||
/**
|
||||
* Flag indicating that a view's outline has been specifically defined.
|
||||
*/
|
||||
static final int PFLAG3_OUTLINE_DEFINED = 0x40;
|
||||
|
||||
/**
|
||||
* Flag indicating that we're in the process of applying window insets.
|
||||
*/
|
||||
static final int PFLAG3_APPLYING_INSETS = 0x40;
|
||||
static final int PFLAG3_APPLYING_INSETS = 0x80;
|
||||
|
||||
/**
|
||||
* Flag indicating that we're in the process of fitting system windows using the old method.
|
||||
*/
|
||||
static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x80;
|
||||
static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x100;
|
||||
|
||||
/* End of masks for mPrivateFlags3 */
|
||||
|
||||
@ -3335,8 +3341,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
/**
|
||||
* Stores the outline of the view, passed down to the DisplayList level for
|
||||
* defining shadow shape and clipping.
|
||||
*
|
||||
* TODO: once RenderNode is long-lived, remove this and rely on native copy.
|
||||
*/
|
||||
private Path mOutline;
|
||||
private Outline mOutline;
|
||||
|
||||
/**
|
||||
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
|
||||
@ -10801,67 +10809,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the Outline of the View into the Path parameter.
|
||||
* <p>
|
||||
* If the outline is not set, the parameter Path is set to empty.
|
||||
*
|
||||
* @param outline Path into which View's outline will be copied. Must be non-null.
|
||||
*
|
||||
* @see #setOutline(Path)
|
||||
* @see #getClipToOutline()
|
||||
* @see #setClipToOutline(boolean)
|
||||
*/
|
||||
public final void getOutline(@NonNull Path outline) {
|
||||
if (outline == null) {
|
||||
throw new IllegalArgumentException("Path must be non-null");
|
||||
}
|
||||
if (mOutline == null) {
|
||||
outline.reset();
|
||||
} else {
|
||||
outline.set(mOutline);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the outline of the view, which defines the shape of the shadow it
|
||||
* casts, and can used for clipping.
|
||||
* <p>
|
||||
* The outline path of a View must be {@link android.graphics.Path#isConvex() convex}.
|
||||
* <p>
|
||||
* If the outline is not set, or {@link Path#isEmpty()}, shadows will be
|
||||
* cast from the bounds of the View, and clipToOutline will be ignored.
|
||||
* If the outline is not set or is null, shadows will be cast from the
|
||||
* bounds of the View, and clipToOutline will be ignored.
|
||||
*
|
||||
* @param outline The new outline of the view. Must be non-null, and convex.
|
||||
* @param outline The new outline of the view.
|
||||
* Must be {@link android.view.Outline#isValid() valid.}
|
||||
*
|
||||
* @see #getOutline(Path)
|
||||
* @see #getClipToOutline()
|
||||
* @see #setClipToOutline(boolean)
|
||||
*/
|
||||
public void setOutline(@NonNull Path outline) {
|
||||
public void setOutline(@Nullable Outline outline) {
|
||||
if (outline != null && !outline.isValid()) {
|
||||
throw new IllegalArgumentException("Outline must not be invalid");
|
||||
}
|
||||
|
||||
mPrivateFlags3 |= PFLAG3_OUTLINE_DEFINED;
|
||||
|
||||
if (outline == null) {
|
||||
throw new IllegalArgumentException("Path must be non-null");
|
||||
}
|
||||
if (!outline.isConvex()) {
|
||||
throw new IllegalArgumentException("Path must be convex");
|
||||
}
|
||||
// always copy the path since caller may reuse
|
||||
if (mOutline == null) {
|
||||
mOutline = new Path(outline);
|
||||
mOutline = null;
|
||||
} else {
|
||||
// always copy the path since caller may reuse
|
||||
if (mOutline == null) {
|
||||
mOutline = new Outline();
|
||||
}
|
||||
mOutline.set(outline);
|
||||
}
|
||||
|
||||
if (mDisplayList != null) {
|
||||
mDisplayList.setOutline(outline);
|
||||
mDisplayList.setOutline(mOutline);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the outline of the View will be used for clipping.
|
||||
*
|
||||
* @see #getOutline(Path)
|
||||
* @see #setOutline(Path)
|
||||
* @see #setOutline(Outline)
|
||||
*/
|
||||
public final boolean getClipToOutline() {
|
||||
return ((mPrivateFlags3 & PFLAG3_CLIP_TO_OUTLINE) != 0);
|
||||
@ -10879,8 +10865,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
* If the outline of the view is not set or is empty, no clipping will be
|
||||
* performed.
|
||||
*
|
||||
* @see #getOutline(Path)
|
||||
* @see #setOutline(Path)
|
||||
* @see #setOutline(Outline)
|
||||
*/
|
||||
public void setClipToOutline(boolean clipToOutline) {
|
||||
// TODO : Add a fast invalidation here.
|
||||
@ -11460,7 +11445,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
|
||||
// Damage the entire IsolatedZVolume recieving this view's shadow.
|
||||
if (getTranslationZ() != 0) {
|
||||
damageIsolatedZVolume();
|
||||
damageShadowReceiver();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11489,24 +11474,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
|
||||
/**
|
||||
* Damage area of the screen covered by the current isolated Z volume
|
||||
* Damage area of the screen that can be covered by this View's shadow.
|
||||
*
|
||||
* This method will guarantee that any changes to shadows cast by a View
|
||||
* are damaged on the screen for future redraw.
|
||||
*/
|
||||
private void damageIsolatedZVolume() {
|
||||
private void damageShadowReceiver() {
|
||||
final AttachInfo ai = mAttachInfo;
|
||||
if (ai != null) {
|
||||
ViewParent p = getParent();
|
||||
while (p != null) {
|
||||
if (p instanceof ViewGroup) {
|
||||
final ViewGroup vg = (ViewGroup) p;
|
||||
if (vg.hasIsolatedZVolume()) {
|
||||
vg.damageInParent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
p = p.getParent();
|
||||
if (p != null && p instanceof ViewGroup) {
|
||||
final ViewGroup vg = (ViewGroup) p;
|
||||
vg.damageInParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11540,7 +11519,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
damageInParent();
|
||||
}
|
||||
if (invalidateParent && getTranslationZ() != 0) {
|
||||
damageIsolatedZVolume();
|
||||
damageShadowReceiver();
|
||||
}
|
||||
}
|
||||
|
||||
@ -14571,10 +14550,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
displayList.setClipToBounds(
|
||||
(((ViewGroup) mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0);
|
||||
}
|
||||
if (this instanceof ViewGroup) {
|
||||
displayList.setIsolatedZVolume(
|
||||
(((ViewGroup) this).mGroupFlags & ViewGroup.FLAG_ISOLATED_Z_VOLUME) != 0);
|
||||
}
|
||||
displayList.setOutline(mOutline);
|
||||
displayList.setClipToOutline(getClipToOutline());
|
||||
float alpha = 1;
|
||||
@ -15178,6 +15153,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
if (mBackgroundSizeChanged) {
|
||||
background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
|
||||
mBackgroundSizeChanged = false;
|
||||
if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
|
||||
// Outline not currently define, query from background
|
||||
mOutline = background.getOutline();
|
||||
if (mDisplayList != null) {
|
||||
mDisplayList.setOutline(mOutline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to use a display list if requested.
|
||||
|
@ -357,15 +357,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
*/
|
||||
private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
|
||||
|
||||
/**
|
||||
* When true, indicates that all 3d composited descendents are contained within this group, and
|
||||
* will not be interleaved with other 3d composited content.
|
||||
*/
|
||||
static final int FLAG_ISOLATED_Z_VOLUME = 0x1000000;
|
||||
static final int FLAG_IS_TRANSITION_GROUP = 0x1000000;
|
||||
|
||||
static final int FLAG_IS_TRANSITION_GROUP = 0x2000000;
|
||||
|
||||
static final int FLAG_IS_TRANSITION_GROUP_SET = 0x4000000;
|
||||
static final int FLAG_IS_TRANSITION_GROUP_SET = 0x2000000;
|
||||
|
||||
/**
|
||||
* Indicates which types of drawing caches are to be kept in memory.
|
||||
@ -499,7 +493,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
mGroupFlags |= FLAG_ANIMATION_DONE;
|
||||
mGroupFlags |= FLAG_ANIMATION_CACHE;
|
||||
mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
|
||||
mGroupFlags |= FLAG_ISOLATED_Z_VOLUME;
|
||||
|
||||
if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
|
||||
@ -528,9 +521,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
case R.styleable.ViewGroup_clipToPadding:
|
||||
setClipToPadding(a.getBoolean(attr, true));
|
||||
break;
|
||||
case R.styleable.ViewGroup_isolatedZVolume:
|
||||
setIsolatedZVolume(a.getBoolean(attr, true));
|
||||
break;
|
||||
case R.styleable.ViewGroup_animationCache:
|
||||
setAnimationCacheEnabled(a.getBoolean(attr, true));
|
||||
break;
|
||||
@ -3158,43 +3148,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
return child.draw(canvas, this, drawingTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this group's descendents are drawn in their own
|
||||
* independent Z volume. Views drawn in one contained volume will not
|
||||
* interleave with views in another, even if their Z values are interleaved.
|
||||
* The default value is true.
|
||||
* @see #setIsolatedZVolume(boolean)
|
||||
*
|
||||
* @return True if the ViewGroup has an isolated Z volume.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean hasIsolatedZVolume() {
|
||||
return ((mGroupFlags & FLAG_ISOLATED_Z_VOLUME) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, only direct children of a group can interleave drawing order
|
||||
* by interleaving Z values. Set to false on individual groups to enable Z
|
||||
* interleaving of views that aren't direct siblings.
|
||||
*
|
||||
* @return True if the group should be an isolated Z volume with its own Z
|
||||
* ordering space, false if its decendents should inhabit the
|
||||
* inherited Z ordering volume.
|
||||
* @attr ref android.R.styleable#ViewGroup_isolatedZVolume
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setIsolatedZVolume(boolean isolateZVolume) {
|
||||
boolean previousValue = (mGroupFlags & FLAG_ISOLATED_Z_VOLUME) != 0;
|
||||
if (isolateZVolume != previousValue) {
|
||||
setBooleanFlag(FLAG_ISOLATED_Z_VOLUME, isolateZVolume);
|
||||
if (mDisplayList != null) {
|
||||
mDisplayList.setIsolatedZVolume(isolateZVolume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this group's children are clipped to their bounds before drawing.
|
||||
* The default value is true.
|
||||
|
@ -69,7 +69,7 @@ static void android_view_RenderNode_destroyDisplayList(JNIEnv* env,
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DisplayList view properties
|
||||
// RenderProperties
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static void android_view_RenderNode_setCaching(JNIEnv* env,
|
||||
@ -98,11 +98,6 @@ static void android_view_RenderNode_setClipToBounds(JNIEnv* env,
|
||||
displayList->properties().setClipToBounds(clipToBounds);
|
||||
}
|
||||
|
||||
static void android_view_RenderNode_setIsolatedZVolume(JNIEnv* env,
|
||||
jobject clazz, jlong displayListPtr, jboolean shouldIsolate) {
|
||||
// No-op, TODO: Remove Java usage of this method
|
||||
}
|
||||
|
||||
static void android_view_RenderNode_setProjectBackwards(JNIEnv* env,
|
||||
jobject clazz, jlong displayListPtr, jboolean shouldProject) {
|
||||
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
|
||||
@ -115,17 +110,28 @@ static void android_view_RenderNode_setProjectionReceiver(JNIEnv* env,
|
||||
displayList->properties().setProjectionReceiver(shouldRecieve);
|
||||
}
|
||||
|
||||
static void android_view_RenderNode_setOutline(JNIEnv* env,
|
||||
static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
|
||||
jobject clazz, jlong displayListPtr, jint left, jint top,
|
||||
jint right, jint bottom, jfloat radius) {
|
||||
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
|
||||
displayList->properties().outline().setRoundRect(left, top, right, bottom, radius);
|
||||
}
|
||||
static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
|
||||
jobject clazz, jlong displayListPtr, jlong outlinePathPtr) {
|
||||
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
|
||||
SkPath* outline = reinterpret_cast<SkPath*>(outlinePathPtr);
|
||||
displayList->properties().setOutline(outline);
|
||||
SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
|
||||
displayList->properties().outline().setConvexPath(outlinePath);
|
||||
}
|
||||
static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
|
||||
jobject clazz, jlong displayListPtr) {
|
||||
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
|
||||
displayList->properties().outline().setEmpty();
|
||||
}
|
||||
|
||||
static void android_view_RenderNode_setClipToOutline(JNIEnv* env,
|
||||
jobject clazz, jlong displayListPtr, jboolean clipToOutline) {
|
||||
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
|
||||
displayList->properties().setClipToOutline(clipToOutline);
|
||||
displayList->properties().outline().setShouldClip(clipToOutline);
|
||||
}
|
||||
|
||||
static void android_view_RenderNode_setAlpha(JNIEnv* env,
|
||||
@ -381,11 +387,14 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "nSetStaticMatrix", "(JJ)V", (void*) android_view_RenderNode_setStaticMatrix },
|
||||
{ "nSetAnimationMatrix", "(JJ)V", (void*) android_view_RenderNode_setAnimationMatrix },
|
||||
{ "nSetClipToBounds", "(JZ)V", (void*) android_view_RenderNode_setClipToBounds },
|
||||
{ "nSetIsolatedZVolume", "(JZ)V", (void*) android_view_RenderNode_setIsolatedZVolume },
|
||||
{ "nSetProjectBackwards", "(JZ)V", (void*) android_view_RenderNode_setProjectBackwards },
|
||||
{ "nSetProjectionReceiver","(JZ)V", (void*) android_view_RenderNode_setProjectionReceiver },
|
||||
{ "nSetOutline", "(JJ)V", (void*) android_view_RenderNode_setOutline },
|
||||
|
||||
{ "nSetOutlineRoundRect", "(JIIIIF)V", (void*) android_view_RenderNode_setOutlineRoundRect },
|
||||
{ "nSetOutlineConvexPath", "(JJ)V", (void*) android_view_RenderNode_setOutlineConvexPath },
|
||||
{ "nSetOutlineEmpty", "(J)V", (void*) android_view_RenderNode_setOutlineEmpty },
|
||||
{ "nSetClipToOutline", "(JZ)V", (void*) android_view_RenderNode_setClipToOutline },
|
||||
|
||||
{ "nSetAlpha", "(JF)V", (void*) android_view_RenderNode_setAlpha },
|
||||
{ "nSetHasOverlappingRendering", "(JZ)V",
|
||||
(void*) android_view_RenderNode_setHasOverlappingRendering },
|
||||
|
@ -2292,9 +2292,6 @@
|
||||
<!-- Defines whether the ViewGroup will clip its drawing surface so as to exclude
|
||||
the padding area. This property is set to true by default. -->
|
||||
<attr name="clipToPadding" format="boolean" />
|
||||
<!-- Defines whether 3d composited descendents of the ViewGroup will be reordered into their
|
||||
own independent Z volume. This property is set to true by default. -->
|
||||
<attr name="isolatedZVolume" format="boolean" />
|
||||
<!-- Defines the layout animation to use the first time the ViewGroup is laid out.
|
||||
Layout animations can also be started manually after the first layout. -->
|
||||
<attr name="layoutAnimation" format="reference" />
|
||||
|
108
graphics/java/android/graphics/Outline.java
Normal file
108
graphics/java/android/graphics/Outline.java
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package android.graphics;
|
||||
|
||||
/**
|
||||
* Defines an area of content.
|
||||
*
|
||||
* Can be used with a View or Drawable to drive the shape of shadows cast by a
|
||||
* View, and allowing Views to clip inner content.
|
||||
*
|
||||
* @see View#setOutline(Outline)
|
||||
* @see View#setClipToOutline(boolean)
|
||||
*/
|
||||
public class Outline {
|
||||
/** @hide */
|
||||
public Rect mRect;
|
||||
|
||||
/** @hide */
|
||||
public float mRadius;
|
||||
|
||||
/** @hide */
|
||||
public Path mPath;
|
||||
|
||||
/**
|
||||
* Constructs an invalid Outline. Call one of the setter methods to make
|
||||
* the outline valid for use with a View.
|
||||
*/
|
||||
public Outline() {}
|
||||
|
||||
/**
|
||||
* Returns whether the Outline is valid for use with a View.
|
||||
* <p>
|
||||
* Outlines are invalid when constructed until a setter method is called.
|
||||
*/
|
||||
public final boolean isValid() {
|
||||
return mRect != null || mPath != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final boolean canClip() {
|
||||
return mPath == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the contents of this Outline with the contents of src.
|
||||
*/
|
||||
public void set(Outline src) {
|
||||
if (src.mPath != null) {
|
||||
if (mPath == null) {
|
||||
mPath = new Path();
|
||||
}
|
||||
mPath.set(src.mPath);
|
||||
mRect = null;
|
||||
}
|
||||
if (src.mRect != null) {
|
||||
if (mRect == null) {
|
||||
mRect = new Rect();
|
||||
}
|
||||
mRect.set(src.mRect);
|
||||
}
|
||||
mRadius = src.mRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Outline to the rounded rect defined by the input rect, and corner radius.
|
||||
* <p>
|
||||
* Outlines produced by this method support
|
||||
* {@link View#setClipToOutline(boolean) View clipping.}
|
||||
*/
|
||||
public void setRoundRect(int left, int top, int right, int bottom, float radius) {
|
||||
if (mRect == null) mRect = new Rect();
|
||||
mRect.set(left, top, right, bottom);
|
||||
mRadius = radius;
|
||||
mPath = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setConvexPath(Path convexPath) {
|
||||
if (!convexPath.isConvex()) {
|
||||
throw new IllegalArgumentException("path must be convex");
|
||||
}
|
||||
if (mPath == null) mPath = new Path();
|
||||
|
||||
mRect = null;
|
||||
mRadius = -1.0f;
|
||||
mPath.set(convexPath);
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.NinePatch;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
@ -859,6 +860,24 @@ public abstract class Drawable {
|
||||
return Insets.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the outline for this drawable if defined, null if not.
|
||||
* <p>
|
||||
* This method will be called by a View on its background Drawable after
|
||||
* bounds change, if the View's Outline isn't set explicitly. This allows
|
||||
* the background Drawable to provide the shape of the shadow casting
|
||||
* portion of the View. It can also serve to clip the area of the View if
|
||||
* if {@link View#setClipToOutline(boolean)} is set on the View.
|
||||
* <p>
|
||||
* The Outline queried by the View will not be modified, and is treated as
|
||||
* a static shape that only needs to be requeried when the drawable's bounds
|
||||
* change.
|
||||
*
|
||||
* @see View#setOutline(android.view.Outline)
|
||||
* @see View#setClipToOutline(boolean)
|
||||
*/
|
||||
public Outline getOutline() { return null; }
|
||||
|
||||
/**
|
||||
* Make this drawable mutable. This operation cannot be reversed. A mutable
|
||||
* drawable is guaranteed to not share its state with any other drawable.
|
||||
|
@ -24,6 +24,7 @@ import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PixelFormat;
|
||||
@ -133,6 +134,7 @@ public class GradientDrawable extends Drawable {
|
||||
|
||||
private final Path mPath = new Path();
|
||||
private final RectF mRect = new RectF();
|
||||
private Outline mOutline;
|
||||
|
||||
private Paint mLayerPaint; // internal, used if we use saveLayer()
|
||||
private boolean mRectIsDirty; // internal state
|
||||
@ -585,11 +587,8 @@ public class GradientDrawable extends Drawable {
|
||||
// to show it. If we did nothing, Skia would clamp the rad
|
||||
// independently along each axis, giving us a thin ellipse
|
||||
// if the rect were very wide but not very tall
|
||||
float rad = st.mRadius;
|
||||
float r = Math.min(mRect.width(), mRect.height()) * 0.5f;
|
||||
if (rad > r) {
|
||||
rad = r;
|
||||
}
|
||||
float rad = Math.min(st.mRadius,
|
||||
Math.min(mRect.width(), mRect.height()) * 0.5f);
|
||||
canvas.drawRoundRect(mRect, rad, rad, mFillPaint);
|
||||
if (haveStroke) {
|
||||
canvas.drawRoundRect(mRect, rad, rad, mStrokePaint);
|
||||
@ -661,7 +660,7 @@ public class GradientDrawable extends Drawable {
|
||||
if (mRingPath == null) {
|
||||
mRingPath = new Path();
|
||||
} else {
|
||||
mRingPath.reset();
|
||||
mRingPath.reset();
|
||||
}
|
||||
|
||||
final Path ringPath = mRingPath;
|
||||
@ -1242,6 +1241,46 @@ public class GradientDrawable extends Drawable {
|
||||
return mGradientState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Outline getOutline() {
|
||||
final GradientState st = mGradientState;
|
||||
final Rect bounds = getBounds();
|
||||
|
||||
switch (st.mShape) {
|
||||
case RECTANGLE:
|
||||
if (st.mRadiusArray != null) {
|
||||
return null;
|
||||
}
|
||||
float rad = 0;
|
||||
if (st.mRadius > 0.0f) {
|
||||
// clamp the radius based on width & height, matching behavior in draw()
|
||||
rad = Math.min(st.mRadius,
|
||||
Math.min(bounds.width(), bounds.height()) * 0.5f);
|
||||
}
|
||||
if (mOutline == null) {
|
||||
mOutline = new Outline();
|
||||
}
|
||||
mOutline.setRoundRect(bounds.left, bounds.top,
|
||||
bounds.right, bounds.bottom, rad);
|
||||
return mOutline;
|
||||
case LINE: {
|
||||
float halfStrokeWidth = mStrokePaint.getStrokeWidth() * 0.5f;
|
||||
float centerY = bounds.centerY();
|
||||
int top = (int) Math.floor(centerY - halfStrokeWidth);
|
||||
int bottom = (int) Math.ceil(centerY + halfStrokeWidth);
|
||||
|
||||
if (mOutline == null) {
|
||||
mOutline = new Outline();
|
||||
}
|
||||
mOutline.setRoundRect(bounds.left, top, bounds.right, bottom, 0);
|
||||
return mOutline;
|
||||
}
|
||||
default:
|
||||
// TODO: investigate
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable mutate() {
|
||||
if (!mMutated && super.mutate() == this) {
|
||||
|
90
libs/hwui/Outline.h
Normal file
90
libs/hwui/Outline.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 OUTLINE_H
|
||||
#define OUTLINE_H
|
||||
|
||||
#include <SkPath.h>
|
||||
|
||||
#include "Rect.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class Outline {
|
||||
public:
|
||||
Outline()
|
||||
: mShouldClip(false)
|
||||
, mType(kOutlineType_None)
|
||||
, mRadius(0) {}
|
||||
|
||||
void setRoundRect(int left, int top, int right, int bottom, int radius) {
|
||||
mType = kOutlineType_RoundRect;
|
||||
mBounds.set(left, top, right, bottom);
|
||||
mRadius = radius;
|
||||
mPath.reset();
|
||||
mPath.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom),
|
||||
radius, radius);
|
||||
}
|
||||
|
||||
void setConvexPath(const SkPath* outline) {
|
||||
if (!outline) {
|
||||
setEmpty();
|
||||
return;
|
||||
}
|
||||
mType = kOutlineType_ConvexPath;
|
||||
mPath = *outline;
|
||||
mBounds.set(outline->getBounds());
|
||||
}
|
||||
|
||||
void setEmpty() {
|
||||
mType = kOutlineType_None;
|
||||
mPath.reset();
|
||||
}
|
||||
|
||||
void setShouldClip(bool clip) {
|
||||
mShouldClip = clip;
|
||||
}
|
||||
|
||||
|
||||
bool willClip() const {
|
||||
// only round rect outlines can be used for clipping
|
||||
return mShouldClip && (mType == kOutlineType_RoundRect);
|
||||
}
|
||||
|
||||
const SkPath* getPath() {
|
||||
if (mType == kOutlineType_None) return NULL;
|
||||
|
||||
return &mPath;
|
||||
}
|
||||
|
||||
private:
|
||||
enum OutlineType {
|
||||
kOutlineType_None = 0,
|
||||
kOutlineType_ConvexPath = 1,
|
||||
kOutlineType_RoundRect = 2
|
||||
};
|
||||
|
||||
bool mShouldClip;
|
||||
OutlineType mType;
|
||||
Rect mBounds;
|
||||
float mRadius;
|
||||
SkPath mPath;
|
||||
};
|
||||
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
#endif /* OUTLINE_H */
|
@ -128,14 +128,14 @@ void RenderNode::outputViewProperties(const int level) {
|
||||
flags |= SkCanvas::kClipToLayer_SaveFlag;
|
||||
clipToBoundsNeeded = false; // clipping done by save layer
|
||||
}
|
||||
ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
|
||||
(float) 0, (float) 0, (float) properties().mRight - properties().mLeft, (float) properties().mBottom - properties().mTop,
|
||||
ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
|
||||
0, 0, properties().mWidth, properties().mHeight,
|
||||
(int)(properties().mAlpha * 255), flags);
|
||||
}
|
||||
}
|
||||
if (clipToBoundsNeeded) {
|
||||
ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
|
||||
(float) properties().mRight - properties().mLeft, (float) properties().mBottom - properties().mTop);
|
||||
ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "",
|
||||
0, 0, properties().mWidth, properties().mHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,17 +185,20 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler,
|
||||
}
|
||||
|
||||
SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
|
||||
0, 0, properties().mRight - properties().mLeft, properties().mBottom - properties().mTop, properties().mAlpha * 255, saveFlags);
|
||||
0, 0, properties().mWidth, properties().mHeight,
|
||||
properties().mAlpha * 255, saveFlags);
|
||||
handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds);
|
||||
}
|
||||
}
|
||||
if (clipToBoundsNeeded) {
|
||||
ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
|
||||
properties().mRight - properties().mLeft, properties().mBottom - properties().mTop, SkRegion::kIntersect_Op);
|
||||
ClipRectOp* op = new (handler.allocator()) ClipRectOp(
|
||||
0, 0, properties().mWidth, properties().mHeight, SkRegion::kIntersect_Op);
|
||||
handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds);
|
||||
}
|
||||
if (CC_UNLIKELY(properties().mClipToOutline && !properties().mOutline.isEmpty())) {
|
||||
ClipPathOp* op = new (handler.allocator()) ClipPathOp(&properties().mOutline, SkRegion::kIntersect_Op);
|
||||
if (CC_UNLIKELY(properties().mOutline.willClip())) {
|
||||
// TODO: optimize RR case
|
||||
ClipPathOp* op = new (handler.allocator()) ClipPathOp(properties().mOutline.getPath(),
|
||||
SkRegion::kIntersect_Op);
|
||||
handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds);
|
||||
}
|
||||
}
|
||||
@ -443,7 +446,7 @@ void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTransl
|
||||
|
||||
DisplayListOp* shadowOp = new (alloc) DrawShadowOp(
|
||||
shadowMatrixXY, shadowMatrixZ,
|
||||
caster->properties().mAlpha, &(caster->properties().mOutline),
|
||||
caster->properties().mAlpha, caster->properties().mOutline.getPath(),
|
||||
caster->properties().mWidth, caster->properties().mHeight);
|
||||
handler(shadowOp, PROPERTY_SAVECOUNT, properties().mClipToBounds);
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ RenderProperties::RenderProperties()
|
||||
: mClipToBounds(true)
|
||||
, mProjectBackwards(false)
|
||||
, mProjectionReceiver(false)
|
||||
, mClipToOutline(false)
|
||||
, mAlpha(1)
|
||||
, mHasOverlappingRendering(true)
|
||||
, mTranslationX(0), mTranslationY(0), mTranslationZ(0)
|
||||
@ -47,7 +46,6 @@ RenderProperties::RenderProperties()
|
||||
, mStaticMatrix(NULL)
|
||||
, mAnimationMatrix(NULL)
|
||||
, mCaching(false) {
|
||||
mOutline.rewind();
|
||||
}
|
||||
|
||||
RenderProperties::~RenderProperties() {
|
||||
|
@ -13,8 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef RENDERNODEPROPERTIES_H_
|
||||
#define RENDERNODEPROPERTIES_H_
|
||||
#ifndef RENDERNODEPROPERTIES_H
|
||||
#define RENDERNODEPROPERTIES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <cutils/compiler.h>
|
||||
@ -22,7 +22,9 @@
|
||||
|
||||
#include <SkCamera.h>
|
||||
#include <SkMatrix.h>
|
||||
#include <SkPath.h>
|
||||
|
||||
#include "Rect.h"
|
||||
#include "Outline.h"
|
||||
|
||||
#define TRANSLATION 0x0001
|
||||
#define ROTATION 0x0002
|
||||
@ -64,18 +66,6 @@ public:
|
||||
return mProjectionReceiver;
|
||||
}
|
||||
|
||||
void setOutline(const SkPath* outline) {
|
||||
if (!outline) {
|
||||
mOutline.reset();
|
||||
} else {
|
||||
mOutline = *outline;
|
||||
}
|
||||
}
|
||||
|
||||
void setClipToOutline(bool clipToOutline) {
|
||||
mClipToOutline = clipToOutline;
|
||||
}
|
||||
|
||||
void setStaticMatrix(SkMatrix* matrix) {
|
||||
delete mStaticMatrix;
|
||||
mStaticMatrix = new SkMatrix(*matrix);
|
||||
@ -375,14 +365,18 @@ public:
|
||||
mCaching = caching;
|
||||
}
|
||||
|
||||
int getWidth() {
|
||||
int getWidth() const {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
int getHeight() {
|
||||
int getHeight() const {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
Outline& outline() {
|
||||
return mOutline;
|
||||
}
|
||||
|
||||
private:
|
||||
void onTranslationUpdate() {
|
||||
mMatrixDirty = true;
|
||||
@ -396,11 +390,10 @@ private:
|
||||
void updateMatrix();
|
||||
|
||||
// Rendering properties
|
||||
Outline mOutline;
|
||||
bool mClipToBounds;
|
||||
bool mProjectBackwards;
|
||||
bool mProjectionReceiver;
|
||||
SkPath mOutline;
|
||||
bool mClipToOutline;
|
||||
float mAlpha;
|
||||
bool mHasOverlappingRendering;
|
||||
float mTranslationX, mTranslationY, mTranslationZ;
|
||||
@ -436,4 +429,4 @@ private:
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
#endif /* RENDERNODEPROPERTIES_H_ */
|
||||
#endif /* RENDERNODEPROPERTIES_H */
|
||||
|
Reference in New Issue
Block a user