Clean up Outline API, method on drawable
bug:15025466
bug:15089680
Change-Id: I8d3b64a0d9dbdbaf679042c8b384d2050323a8e6
diff --git a/api/current.txt b/api/current.txt
index ebd3605..5b36763 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10196,10 +10196,10 @@
ctor public Outline();
ctor public Outline(android.graphics.Outline);
method public boolean canClip();
- method public boolean isValid();
- method public void reset();
+ method public boolean isEmpty();
method public void set(android.graphics.Outline);
method public void setConvexPath(android.graphics.Path);
+ method public void setEmpty();
method public void setOval(int, int, int, int);
method public void setOval(android.graphics.Rect);
method public void setRect(int, int, int, int);
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index b2839cb..cf125bc 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -366,10 +366,8 @@
* Deep copies the data into native to simplify reference ownership.
*/
public void setOutline(Outline outline) {
- if (outline == null) {
+ if (outline == null || outline.isEmpty()) {
nSetOutlineEmpty(mNativeRenderNode);
- } else if (!outline.isValid()) {
- throw new IllegalArgumentException("Outline must be valid");
} else if (outline.mRect != null) {
nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
outline.mRect.right, outline.mRect.bottom, outline.mRadius);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6dc7286..0f21c1d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10680,24 +10680,30 @@
}
/**
- * Sets the outline of the view, which defines the shape of the shadow it
- * casts.
+ * Sets the {@link Outline} of the view, which defines the shape of the shadow it
+ * casts, and enables outline clipping.
* <p>
- * If the outline is not set or is null, shadows will be cast from the
+ * By default, a View queries its Outline from its background drawable, via
+ * {@link Drawable#getOutline(Outline)}. Manually setting the Outline with this method allows
+ * this behavior to be overridden.
+ * <p>
+ * If the outline is empty or is null, shadows will be cast from the
* bounds of the View.
+ * <p>
+ * Only outlines that return true from {@link Outline#canClip()} may be used for clipping.
*
* @param outline The new outline of the view.
- * Must be {@link android.graphics.Outline#isValid() valid.}
+ *
+ * @see #setClipToOutline(boolean)
+ * @see #getClipToOutline()
*/
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) {
- mOutline = null;
+ if (outline == null || outline.isEmpty()) {
+ if (mOutline != null) {
+ mOutline.setEmpty();
+ }
} else {
// always copy the path since caller may reuse
if (mOutline == null) {
@@ -10708,12 +10714,30 @@
mRenderNode.setOutline(mOutline);
}
+ /**
+ * Returns whether the Outline should be used to clip the contents of the View.
+ * <p>
+ * Note that this flag will only be respected if the View's Outline returns true from
+ * {@link Outline#canClip()}.
+ *
+ * @see #setOutline(Outline)
+ * @see #setClipToOutline(boolean)
+ */
public final boolean getClipToOutline() {
return mRenderNode.getClipToOutline();
}
+ /**
+ * Sets whether the View's Outline should be used to clip the contents of the View.
+ * <p>
+ * Note that this flag will only be respected if the View's Outline returns true from
+ * {@link Outline#canClip()}.
+ *
+ * @see #setOutline(Outline)
+ * @see #getClipToOutline()
+ */
public void setClipToOutline(boolean clipToOutline) {
- // TODO: add a fast invalidation here
+ damageInParent();
if (getClipToOutline() != clipToOutline) {
mRenderNode.setClipToOutline(clipToOutline);
}
@@ -10726,10 +10750,10 @@
mOutline = new Outline();
} else {
//invalidate outline, to ensure background calculates it
- mOutline.reset();
+ mOutline.setEmpty();
}
if (mBackground.getOutline(mOutline)) {
- if (!mOutline.isValid()) {
+ if (mOutline.isEmpty()) {
throw new IllegalStateException("Background drawable failed to build outline");
}
mRenderNode.setOutline(mOutline);
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index c6ba75c..d87c3cb 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -23,9 +23,9 @@
/**
* Defines a simple shape, used for bounding graphical regions.
- *
+ * <p>
* Can be used with a View, or computed by a Drawable, to drive the shape of shadows cast by a
- * View.
+ * View, or to clip the contents of the View.
*
* @see View#setOutline(Outline)
* @see Drawable#getOutline(Outline)
@@ -41,7 +41,7 @@
public Path mPath;
/**
- * Constructs an invalid Outline. Call one of the setter methods to make
+ * Constructs an empty Outline. Call one of the setter methods to make
* the outline valid for use with a View.
*/
public Outline() {}
@@ -49,23 +49,31 @@
/**
* Constructs an Outline with a copy of the data in src.
*/
- public Outline(@Nullable Outline src) {
+ public Outline(@NonNull Outline src) {
set(src);
}
- public void reset() {
+ /**
+ * Sets the outline to be empty.
+ *
+ * @see #isEmpty()
+ */
+ public void setEmpty() {
mRadius = 0;
mRect = null;
mPath = null;
}
/**
- * Returns whether the Outline is valid for use with a View.
+ * Returns whether the Outline is empty.
* <p>
- * Outlines are invalid when constructed until a setter method is called.
+ * Outlines are empty when constructed, or if {@link #setEmpty()} is called,
+ * until a setter method is called
+ *
+ * @see #setEmpty()
*/
- public boolean isValid() {
- return mRect != null || mPath != null;
+ public boolean isEmpty() {
+ return mRect == null && mPath == null;
}
/**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index c78096a..951add9 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.annotation.NonNull;
import android.graphics.Insets;
import android.graphics.Xfermode;
import android.os.Trace;
@@ -817,11 +818,12 @@
/**
* Return in padding the insets suggested by this Drawable for placing
* content inside the drawable's bounds. Positive values move toward the
- * center of the Drawable (set Rect.inset). Returns true if this drawable
- * actually has a padding, else false. When false is returned, the padding
- * is always set to 0.
+ * center of the Drawable (set Rect.inset).
+ *
+ * @return true if this drawable actually has a padding, else false. When false is returned,
+ * the padding is always set to 0.
*/
- public boolean getPadding(Rect padding) {
+ public boolean getPadding(@NonNull Rect padding) {
padding.set(0, 0, 0, 0);
return false;
}
@@ -842,13 +844,16 @@
* This method will be called by a View on its background Drawable after bounds change, or its
* Drawable is invalidated, if the View's Outline isn't set explicitly. This allows the
* background Drawable to define the shape of the shadow cast by the View.
- *
+ * <p>
* The default behavior defines the outline to be the bounding rectangle. Subclasses that wish
* to convey a different shape must override this method.
*
+ * @return true if this drawable actually has an outline, else false. The outline must be
+ * populated by the drawable if true is returned.
+ *
* @see View#setOutline(android.graphics.Outline)
*/
- public boolean getOutline(Outline outline) {
+ public boolean getOutline(@NonNull Outline outline) {
outline.setRect(getBounds());
return true;
}