1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.text.style;
18 
19 import android.graphics.Canvas;
20 import android.graphics.Paint;
21 import android.graphics.Rect;
22 import android.graphics.drawable.Drawable;
23 
24 import java.lang.ref.WeakReference;
25 
26 /**
27  *
28  */
29 public abstract class DynamicDrawableSpan extends ReplacementSpan {
30     private static final String TAG = "DynamicDrawableSpan";
31 
32     /**
33      * A constant indicating that the bottom of this span should be aligned
34      * with the bottom of the surrounding text, i.e., at the same level as the
35      * lowest descender in the text.
36      */
37     public static final int ALIGN_BOTTOM = 0;
38 
39     /**
40      * A constant indicating that the bottom of this span should be aligned
41      * with the baseline of the surrounding text.
42      */
43     public static final int ALIGN_BASELINE = 1;
44 
45     protected final int mVerticalAlignment;
46 
DynamicDrawableSpan()47     public DynamicDrawableSpan() {
48         mVerticalAlignment = ALIGN_BOTTOM;
49     }
50 
51     /**
52      * @param verticalAlignment one of {@link #ALIGN_BOTTOM} or {@link #ALIGN_BASELINE}.
53      */
DynamicDrawableSpan(int verticalAlignment)54     protected DynamicDrawableSpan(int verticalAlignment) {
55         mVerticalAlignment = verticalAlignment;
56     }
57 
58     /**
59      * Returns the vertical alignment of this span, one of {@link #ALIGN_BOTTOM} or
60      * {@link #ALIGN_BASELINE}.
61      */
getVerticalAlignment()62     public int getVerticalAlignment() {
63         return mVerticalAlignment;
64     }
65 
66     /**
67      * Your subclass must implement this method to provide the bitmap
68      * to be drawn.  The dimensions of the bitmap must be the same
69      * from each call to the next.
70      */
getDrawable()71     public abstract Drawable getDrawable();
72 
73     @Override
getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm)74     public int getSize(Paint paint, CharSequence text,
75                          int start, int end,
76                          Paint.FontMetricsInt fm) {
77         Drawable d = getCachedDrawable();
78         Rect rect = d.getBounds();
79 
80         if (fm != null) {
81             fm.ascent = -rect.bottom;
82             fm.descent = 0;
83 
84             fm.top = fm.ascent;
85             fm.bottom = 0;
86         }
87 
88         return rect.right;
89     }
90 
91     @Override
draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint)92     public void draw(Canvas canvas, CharSequence text,
93                      int start, int end, float x,
94                      int top, int y, int bottom, Paint paint) {
95         Drawable b = getCachedDrawable();
96         canvas.save();
97 
98         int transY = bottom - b.getBounds().bottom;
99         if (mVerticalAlignment == ALIGN_BASELINE) {
100             transY -= paint.getFontMetricsInt().descent;
101         }
102 
103         canvas.translate(x, transY);
104         b.draw(canvas);
105         canvas.restore();
106     }
107 
getCachedDrawable()108     private Drawable getCachedDrawable() {
109         WeakReference<Drawable> wr = mDrawableRef;
110         Drawable d = null;
111 
112         if (wr != null)
113             d = wr.get();
114 
115         if (d == null) {
116             d = getDrawable();
117             mDrawableRef = new WeakReference<Drawable>(d);
118         }
119 
120         return d;
121     }
122 
123     private WeakReference<Drawable> mDrawableRef;
124 }
125 
126