package org.wikipedia.richtext; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.style.ImageSpan; /** A more mutable ImageSpan better suited to Drawables. */ public class DrawableSpan extends ImageSpan { @Nullable private Drawable drawable; public DrawableSpan(@NonNull Context context, Bitmap bitmap) { super(context, bitmap); init(); } public DrawableSpan(@NonNull Context context, Bitmap bitmap, int verticalAlignment) { super(context, bitmap, verticalAlignment); init(); } public DrawableSpan(Drawable drawable) { super(drawable); init(); } public DrawableSpan(Drawable drawable, int verticalAlignment) { super(drawable, verticalAlignment); init(); } public DrawableSpan(Drawable drawable, String source) { super(drawable, source); init(); } public DrawableSpan(Drawable drawable, String source, int verticalAlignment) { super(drawable, source, verticalAlignment); init(); } public DrawableSpan(@NonNull Context context, Uri uri) { super(context, uri); init(); } public DrawableSpan(@NonNull Context context, Uri uri, int verticalAlignment) { super(context, uri, verticalAlignment); init(); } public DrawableSpan(@NonNull Context context, @DrawableRes int resourceId) { super(context, resourceId); init(); } public DrawableSpan(@NonNull Context context, @DrawableRes int resourceId, int verticalAlignment) { super(context, resourceId, verticalAlignment); init(); } @Override @Nullable public Drawable getDrawable() { return drawable; } // Make vertical alignment consistent across APIs. See https://code.google.com/p/android/issues/detail?id=21397 @Override @SuppressWarnings("checkstyle:parameternumber") public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { if (drawable == null) { return; } canvas.save(); canvas.translate(x, drawY(y, bottom)); drawable.draw(canvas); canvas.restore(); } public void setDrawable(@Nullable Drawable drawable) { this.drawable = drawable; } public void setIntrinsicBounds() { if (drawable != null && drawable.getBounds().isEmpty()) { drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); } } protected int drawY(int y, int bottom) { int ret; if (mVerticalAlignment == ALIGN_BASELINE) { ret = y; } else { ret = bottom; } ret -= drawable == null ? 0 : drawable.getBounds().bottom; return ret; } private void init() { // super.getDrawable() is convoluted: // * May return an original or a new Drawable; does not keep a reference in the latter // case. // * May set the bounds or not. // * May set the bounds differently. // // This is the only seam to change the Drawable state. drawable = super.getDrawable(); setIntrinsicBounds(); } }