Merge "Refactor Drawable outline production, flesh out Outline methods"

This commit is contained in:
Chris Craik
2014-04-25 16:22:26 +00:00
committed by Android (Google) Code Review
5 changed files with 115 additions and 108 deletions

View File

@@ -16,18 +16,19 @@
package android.graphics;
import android.graphics.drawable.Drawable;
import android.view.View;
/**
* Defines an area of content.
*
* Can be used with a View or Drawable to drive the shape of shadows cast by a
* Can be used with a View, or computed by a 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)
* @see Drawable#getOutline(Outline)
*/
public class Outline {
public final class Outline {
/** @hide */
public Rect mRect;
@@ -43,22 +44,29 @@ public class Outline {
*/
public Outline() {}
/**
* Constructs an Outline with a copy of the data in src.
*/
public Outline(Outline src) {
set(src);
}
/** @hide */
public void markInvalid() {
mRadius = 0;
mRect = null;
mPath = null;
}
/**
* 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() {
public 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.
*/
@@ -81,9 +89,20 @@ public class Outline {
/**
* 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 setRect(int left, int top, int right, int bottom) {
setRoundRect(left, top, right, bottom, 0.0f);
}
/**
* Convenience for {@link #setRect(int, int, int, int)}
*/
public void setRect(Rect rect) {
setRect(rect.left, rect.top, rect.right, rect.bottom);
}
/**
* Sets the Outline to the rounded rect defined by the input rect, and corner radius.
*/
public void setRoundRect(int left, int top, int right, int bottom, float radius) {
if (mRect == null) mRect = new Rect();
@@ -92,10 +111,17 @@ public class Outline {
mPath = null;
}
/**
* Convenience for {@link #setRoundRect(int, int, int, int, float)}
* @param rect
* @param radius
*/
public void setRoundRect(Rect rect, float radius) {
setRoundRect(rect.left, rect.top, rect.right, rect.bottom, radius);
}
/**
* Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}.
*
* @hide
*/
public void setConvexPath(Path convexPath) {
if (!convexPath.isConvex()) {

View File

@@ -864,22 +864,21 @@ public abstract class Drawable {
}
/**
* Returns the outline for this drawable if defined, null if not.
* Called to get the drawable to populate the Outline.
* <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.
* 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.
*
* @see View#setOutline(android.view.Outline)
* @see View#setClipToOutline(boolean)
* The default behavior defines the outline to be the bounding rectangle. Subclasses that wish
* to convey a different shape must override this method.
*
* @see View#setOutline(android.graphics.Outline)
*/
public Outline getOutline() { return null; }
public boolean getOutline(Outline outline) {
outline.setRect(getBounds());
return true;
}
/**
* Make this drawable mutable. This operation cannot be reversed. A mutable

View File

@@ -139,8 +139,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
private boolean mMutated;
@@ -573,15 +572,11 @@ public class GradientDrawable extends Drawable {
mStrokePaint.setColorFilter(mColorFilter);
}
}
switch (st.mShape) {
case RECTANGLE:
if (st.mRadiusArray != null) {
if (mPathIsDirty || mRectIsDirty) {
mPath.reset();
mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW);
mPathIsDirty = mRectIsDirty = false;
}
buildPathIfDirty();
canvas.drawPath(mPath, mFillPaint);
if (haveStroke) {
canvas.drawPath(mPath, mStrokePaint);
@@ -638,7 +633,16 @@ public class GradientDrawable extends Drawable {
}
}
}
private void buildPathIfDirty() {
final GradientState st = mGradientState;
if (mPathIsDirty || mRectIsDirty) {
mPath.reset();
mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW);
mPathIsDirty = mRectIsDirty = false;
}
}
private Path buildRing(GradientState st) {
if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
mPathIsDirty = false;
@@ -1428,42 +1432,39 @@ public class GradientDrawable extends Drawable {
}
@Override
public Outline getOutline() {
public boolean getOutline(Outline outline) {
final GradientState st = mGradientState;
final Rect bounds = getBounds();
switch (st.mShape) {
case RECTANGLE:
if (st.mRadiusArray != null) {
return null;
buildPathIfDirty();
outline.setConvexPath(mPath);
return true;
}
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,
outline.setRoundRect(bounds.left, bounds.top,
bounds.right, bounds.bottom, rad);
return mOutline;
return true;
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;
outline.setRect(bounds.left, top, bounds.right, bottom);
return true;
}
default:
// TODO: investigate
return null;
return false;
}
}