Styled.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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
17package android.text;
18
19import android.graphics.Paint;
20import android.graphics.Canvas;
21import android.graphics.Path;
22import android.graphics.RectF;
23import android.graphics.Typeface;
24import android.graphics.MaskFilter;
25import android.graphics.Rasterizer;
26import android.graphics.LayerRasterizer;
27import android.text.style.*;
28
29/* package */ class Styled
30{
31    private static float each(Canvas canvas,
32                              Spanned text, int start, int end,
33                              int dir, boolean reverse,
34                              float x, int top, int y, int bottom,
35                              Paint.FontMetricsInt fm,
36                              TextPaint realPaint,
37                              TextPaint paint,
38                              boolean needwid) {
39
40        boolean havewid = false;
41        float ret = 0;
42        CharacterStyle[] spans = text.getSpans(start, end, CharacterStyle.class);
43
44        ReplacementSpan replacement = null;
45
46        realPaint.bgColor = 0;
47        realPaint.baselineShift = 0;
48        paint.set(realPaint);
49
50		if (spans.length > 0) {
51			for (int i = 0; i < spans.length; i++) {
52				CharacterStyle span = spans[i];
53
54				if (span instanceof ReplacementSpan) {
55					replacement = (ReplacementSpan)span;
56				}
57				else {
58					span.updateDrawState(paint);
59				}
60			}
61		}
62
63        if (replacement == null) {
64            CharSequence tmp;
65            int tmpstart, tmpend;
66
67            if (reverse) {
68                tmp = TextUtils.getReverse(text, start, end);
69                tmpstart = 0;
70                tmpend = end - start;
71            } else {
72                tmp = text;
73                tmpstart = start;
74                tmpend = end;
75            }
76
77            if (fm != null) {
78                paint.getFontMetricsInt(fm);
79            }
80
81            if (canvas != null) {
82                if (paint.bgColor != 0) {
83                    int c = paint.getColor();
84                    Paint.Style s = paint.getStyle();
85                    paint.setColor(paint.bgColor);
86                    paint.setStyle(Paint.Style.FILL);
87
88                    if (!havewid) {
89                        ret = paint.measureText(tmp, tmpstart, tmpend);
90                        havewid = true;
91                    }
92
93                    if (dir == Layout.DIR_RIGHT_TO_LEFT)
94                        canvas.drawRect(x - ret, top, x, bottom, paint);
95                    else
96                        canvas.drawRect(x, top, x + ret, bottom, paint);
97
98                    paint.setStyle(s);
99                    paint.setColor(c);
100                }
101
102                if (dir == Layout.DIR_RIGHT_TO_LEFT) {
103                    if (!havewid) {
104                        ret = paint.measureText(tmp, tmpstart, tmpend);
105                        havewid = true;
106                    }
107
108                    canvas.drawText(tmp, tmpstart, tmpend,
109                                    x - ret, y + paint.baselineShift, paint);
110                } else {
111                    if (needwid) {
112                        if (!havewid) {
113                            ret = paint.measureText(tmp, tmpstart, tmpend);
114                            havewid = true;
115                        }
116                    }
117
118                    canvas.drawText(tmp, tmpstart, tmpend,
119                                    x, y + paint.baselineShift, paint);
120                }
121            } else {
122                if (needwid && !havewid) {
123                    ret = paint.measureText(tmp, tmpstart, tmpend);
124                    havewid = true;
125                }
126            }
127        } else {
128            ret = replacement.getSize(paint, text, start, end, fm);
129
130            if (canvas != null) {
131                if (dir == Layout.DIR_RIGHT_TO_LEFT)
132                    replacement.draw(canvas, text, start, end,
133                                     x - ret, top, y, bottom, paint);
134                else
135                    replacement.draw(canvas, text, start, end,
136                                     x, top, y, bottom, paint);
137            }
138        }
139
140        if (dir == Layout.DIR_RIGHT_TO_LEFT)
141            return -ret;
142        else
143            return ret;
144    }
145
146    public static int getTextWidths(TextPaint realPaint,
147                                    TextPaint paint,
148                              Spanned text, int start, int end,
149                              float[] widths, Paint.FontMetricsInt fm) {
150
151        MetricAffectingSpan[] spans = text.getSpans(start, end, MetricAffectingSpan.class);
152
153		ReplacementSpan replacement = null;
154        paint.set(realPaint);
155
156		for (int i = 0; i < spans.length; i++) {
157			MetricAffectingSpan span = spans[i];
158			if (span instanceof ReplacementSpan) {
159				replacement = (ReplacementSpan)span;
160			}
161			else {
162				span.updateMeasureState(paint);
163			}
164		}
165
166        if (replacement == null) {
167            paint.getFontMetricsInt(fm);
168            paint.getTextWidths(text, start, end, widths);
169        } else {
170            int wid = replacement.getSize(paint, text, start, end, fm);
171
172            if (end > start) {
173                widths[0] = wid;
174
175                for (int i = start + 1; i < end; i++)
176                    widths[i - start] = 0;
177            }
178        }
179        return end - start;
180    }
181
182    private static float foreach(Canvas canvas,
183                                 CharSequence text, int start, int end,
184                                 int dir, boolean reverse,
185                                 float x, int top, int y, int bottom,
186                                 Paint.FontMetricsInt fm,
187                                 TextPaint paint,
188                                 TextPaint workPaint,
189                                 boolean needwid) {
190        if (! (text instanceof Spanned)) {
191            float ret = 0;
192
193            if (reverse) {
194                CharSequence tmp = TextUtils.getReverse(text, start, end);
195                int tmpend = end - start;
196
197                if (canvas != null || needwid)
198                    ret = paint.measureText(tmp, 0, tmpend);
199
200                if (canvas != null)
201                    canvas.drawText(tmp, 0, tmpend,
202                                    x - ret, y, paint);
203            } else {
204                if (needwid)
205                    ret = paint.measureText(text, start, end);
206
207                if (canvas != null)
208                    canvas.drawText(text, start, end, x, y, paint);
209            }
210
211            if (fm != null) {
212                paint.getFontMetricsInt(fm);
213            }
214
215            return ret * dir;   //Layout.DIR_RIGHT_TO_LEFT == -1
216        }
217
218        float ox = x;
219        int asc = 0, desc = 0;
220        int ftop = 0, fbot = 0;
221
222        Spanned sp = (Spanned) text;
223        Class division;
224
225        if (canvas == null)
226            division = MetricAffectingSpan.class;
227        else
228            division = CharacterStyle.class;
229
230        int next;
231        for (int i = start; i < end; i = next) {
232            next = sp.nextSpanTransition(i, end, division);
233
234            x += each(canvas, sp, i, next, dir, reverse,
235                  x, top, y, bottom, fm, paint, workPaint,
236                  needwid || next != end);
237
238            if (fm != null) {
239                if (fm.ascent < asc)
240                    asc = fm.ascent;
241                if (fm.descent > desc)
242                    desc = fm.descent;
243
244                if (fm.top < ftop)
245                    ftop = fm.top;
246                if (fm.bottom > fbot)
247                    fbot = fm.bottom;
248            }
249        }
250
251        if (fm != null) {
252            if (start == end) {
253                paint.getFontMetricsInt(fm);
254            } else {
255                fm.ascent = asc;
256                fm.descent = desc;
257                fm.top = ftop;
258                fm.bottom = fbot;
259            }
260        }
261
262        return x - ox;
263    }
264
265    public static float drawText(Canvas canvas,
266                                 CharSequence text, int start, int end,
267                                 int dir, boolean reverse,
268                                 float x, int top, int y, int bottom,
269                                 TextPaint paint,
270                                 TextPaint workPaint,
271                                 boolean needwid) {
272        if ((dir == Layout.DIR_RIGHT_TO_LEFT && !reverse)||(reverse && dir == Layout.DIR_LEFT_TO_RIGHT)) {
273            float ch = foreach(null, text, start, end, Layout.DIR_LEFT_TO_RIGHT,
274                         false, 0, 0, 0, 0, null, paint, workPaint,
275                         true);
276
277            ch *= dir;  // DIR_RIGHT_TO_LEFT == -1
278            foreach(canvas, text, start, end, -dir,
279                    reverse, x + ch, top, y, bottom, null, paint,
280                    workPaint, true);
281
282            return ch;
283        }
284
285        return foreach(canvas, text, start, end, dir, reverse,
286                       x, top, y, bottom, null, paint, workPaint,
287                       needwid);
288    }
289
290    public static float measureText(TextPaint paint,
291                                    TextPaint workPaint,
292                                    CharSequence text, int start, int end,
293                                    Paint.FontMetricsInt fm) {
294        return foreach(null, text, start, end,
295                       Layout.DIR_LEFT_TO_RIGHT, false,
296                       0, 0, 0, 0, fm, paint, workPaint, true);
297    }
298}
299