Styled.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.text;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.CharacterStyle;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.MetricAffectingSpan;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.ReplacementSpan;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This class provides static methods for drawing and measuring styled texts, like
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.text.Spanned} object with {@link android.text.style.ReplacementSpan}.
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Styled
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static float each(Canvas canvas,
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              Spanned text, int start, int end,
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              int dir, boolean reverse,
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              float x, int top, int y, int bottom,
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              Paint.FontMetricsInt fmi,
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              TextPaint paint,
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              TextPaint workPaint,
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              boolean needwid) {
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean havewid = false;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float ret = 0;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharacterStyle[] spans = text.getSpans(start, end, CharacterStyle.class);
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ReplacementSpan replacement = null;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        paint.bgColor = 0;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        paint.baselineShift = 0;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        workPaint.set(paint);
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		if (spans.length > 0) {
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			for (int i = 0; i < spans.length; i++) {
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				CharacterStyle span = spans[i];
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				if (span instanceof ReplacementSpan) {
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project					replacement = (ReplacementSpan)span;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				}
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				else {
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project					span.updateDrawState(workPaint);
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				}
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			}
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		}
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (replacement == null) {
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            CharSequence tmp;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int tmpstart, tmpend;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (reverse) {
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                tmp = TextUtils.getReverse(text, start, end);
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                tmpstart = 0;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                tmpend = end - start;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                tmp = text;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                tmpstart = start;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                tmpend = end;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fmi != null) {
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                workPaint.getFontMetricsInt(fmi);
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (canvas != null) {
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (workPaint.bgColor != 0) {
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int c = workPaint.getColor();
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Paint.Style s = workPaint.getStyle();
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    workPaint.setColor(workPaint.bgColor);
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    workPaint.setStyle(Paint.Style.FILL);
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!havewid) {
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ret = workPaint.measureText(tmp, tmpstart, tmpend);
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        havewid = true;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (dir == Layout.DIR_RIGHT_TO_LEFT)
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        canvas.drawRect(x - ret, top, x, bottom, workPaint);
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    else
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        canvas.drawRect(x, top, x + ret, bottom, workPaint);
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    workPaint.setStyle(s);
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    workPaint.setColor(c);
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (dir == Layout.DIR_RIGHT_TO_LEFT) {
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!havewid) {
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ret = workPaint.measureText(tmp, tmpstart, tmpend);
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        havewid = true;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    canvas.drawText(tmp, tmpstart, tmpend,
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    x - ret, y + workPaint.baselineShift, workPaint);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (needwid) {
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (!havewid) {
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            ret = workPaint.measureText(tmp, tmpstart, tmpend);
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            havewid = true;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    canvas.drawText(tmp, tmpstart, tmpend,
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    x, y + workPaint.baselineShift, workPaint);
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (needwid && !havewid) {
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = workPaint.measureText(tmp, tmpstart, tmpend);
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    havewid = true;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ret = replacement.getSize(workPaint, text, start, end, fmi);
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (canvas != null) {
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (dir == Layout.DIR_RIGHT_TO_LEFT)
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    replacement.draw(canvas, text, start, end,
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     x - ret, top, y, bottom, workPaint);
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                else
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    replacement.draw(canvas, text, start, end,
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     x, top, y, bottom, workPaint);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dir == Layout.DIR_RIGHT_TO_LEFT)
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -ret;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ret;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the advance widths for the characters in the string.
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * See also {@link android.graphics.Paint#getTextWidths(CharSequence, int, int, float[])}.
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param paint The main {@link TextPaint} object.
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param workPaint The {@link TextPaint} object used for temporal workspace.
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text The text to measure
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param start The index of the first char to to measure
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param end The end of the text slice to measure
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param widths Array to receive the advance widths of the characters.
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Must be at least a large as (end - start).
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fmi FontMetrics information. Can be null.
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The actual number of widths returned.
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getTextWidths(TextPaint paint,
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    TextPaint workPaint,
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    Spanned text, int start, int end,
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    float[] widths, Paint.FontMetricsInt fmi) {
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //  Keep workPaint as is so that developers reuse the workspace.
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MetricAffectingSpan[] spans = text.getSpans(start, end, MetricAffectingSpan.class);
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		ReplacementSpan replacement = null;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        workPaint.set(paint);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		for (int i = 0; i < spans.length; i++) {
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			MetricAffectingSpan span = spans[i];
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			if (span instanceof ReplacementSpan) {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				replacement = (ReplacementSpan)span;
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			}
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			else {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				span.updateMeasureState(workPaint);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			}
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		}
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (replacement == null) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            workPaint.getFontMetricsInt(fmi);
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            workPaint.getTextWidths(text, start, end, widths);
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int wid = replacement.getSize(workPaint, text, start, end, fmi);
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (end > start) {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                widths[0] = wid;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = start + 1; i < end; i++)
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    widths[i - start] = 0;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return end - start;
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static float foreach(Canvas canvas,
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 CharSequence text, int start, int end,
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 int dir, boolean reverse,
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 float x, int top, int y, int bottom,
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 Paint.FontMetricsInt fmi,
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 TextPaint paint,
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 TextPaint workPaint,
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 boolean needWidth) {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (! (text instanceof Spanned)) {
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float ret = 0;
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (reverse) {
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                CharSequence tmp = TextUtils.getReverse(text, start, end);
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int tmpend = end - start;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (canvas != null || needWidth)
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = paint.measureText(tmp, 0, tmpend);
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (canvas != null)
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    canvas.drawText(tmp, 0, tmpend,
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    x - ret, y, paint);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (needWidth)
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = paint.measureText(text, start, end);
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (canvas != null)
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    canvas.drawText(text, start, end, x, y, paint);
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fmi != null) {
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                paint.getFontMetricsInt(fmi);
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ret * dir;   //Layout.DIR_RIGHT_TO_LEFT == -1
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float ox = x;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int asc = 0, desc = 0;
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ftop = 0, fbot = 0;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Spanned sp = (Spanned) text;
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Class division;
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (canvas == null)
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            division = MetricAffectingSpan.class;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            division = CharacterStyle.class;
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int next;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = start; i < end; i = next) {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            next = sp.nextSpanTransition(i, end, division);
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            x += each(canvas, sp, i, next, dir, reverse,
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  x, top, y, bottom, fmi, paint, workPaint,
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  needWidth || next != end);
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fmi != null) {
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fmi.ascent < asc)
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    asc = fmi.ascent;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fmi.descent > desc)
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    desc = fmi.descent;
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fmi.top < ftop)
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ftop = fmi.top;
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fmi.bottom > fbot)
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fbot = fmi.bottom;
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fmi != null) {
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (start == end) {
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                paint.getFontMetricsInt(fmi);
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fmi.ascent = asc;
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fmi.descent = desc;
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fmi.top = ftop;
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fmi.bottom = fbot;
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return x - ox;
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static float drawText(Canvas canvas,
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       CharSequence text, int start, int end,
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       int direction, boolean reverse,
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       float x, int top, int y, int bottom,
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       TextPaint paint,
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       TextPaint workPaint,
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       boolean needWidth) {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((direction == Layout.DIR_RIGHT_TO_LEFT && !reverse) ||
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            (reverse && direction == Layout.DIR_LEFT_TO_RIGHT)) {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float ch = foreach(null, text, start, end, Layout.DIR_LEFT_TO_RIGHT,
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         false, 0, 0, 0, 0, null, paint, workPaint,
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         true);
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ch *= direction;  // DIR_RIGHT_TO_LEFT == -1
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            foreach(canvas, text, start, end, -direction,
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reverse, x + ch, top, y, bottom, null, paint,
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    workPaint, true);
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ch;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return foreach(canvas, text, start, end, direction, reverse,
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                       x, top, y, bottom, null, paint, workPaint,
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                       needWidth);
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Draw the specified range of text, specified by start/end, with its origin at (x,y),
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the specified Paint. The origin is interpreted based on the Align setting in the
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Paint.
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This method considers style information in the text
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * correctly draws the text).
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * See also
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link android.graphics.Canvas#drawText(CharSequence, int, int, float, float, Paint)}
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link android.graphics.Canvas#drawRect(float, float, float, float, Paint)}.
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas The target canvas.
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text The text to be drawn
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param start The index of the first character in text to draw
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param end (end - 1) is the index of the last character in text to draw
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param direction The direction of the text. This must be
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link android.text.Layout#DIR_LEFT_TO_RIGHT} or
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link android.text.Layout#DIR_RIGHT_TO_LEFT}.
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param x The x-coordinate of origin for where to draw the text
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param top The top side of the rectangle to be drawn
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param y The y-coordinate of origin for where to draw the text
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param bottom The bottom side of the rectangle to be drawn
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param paint The main {@link TextPaint} object.
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param workPaint The {@link TextPaint} object used for temporal workspace.
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param needWidth If true, this method returns the width of drawn text.
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Width of the drawn text if needWidth is true.
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static float drawText(Canvas canvas,
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 CharSequence text, int start, int end,
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 int direction,
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 float x, int top, int y, int bottom,
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 TextPaint paint,
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 TextPaint workPaint,
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 boolean needWidth) {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // For safety.
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        direction = direction >= 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT;
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Hided "reverse" parameter since it is meaningless for external developers.
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Kept workPaint as is so that developers reuse the workspace.
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return drawText(canvas, text, start, end, direction, false,
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        x, top, y, bottom, paint, workPaint, needWidth);
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the width of the text, considering style information in the text
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * correctly mesures the width of the text).
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param paint The main {@link TextPaint} object.
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param workPaint The {@link TextPaint} object used for temporal workspace.
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param text The text to measure
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param start The index of the first character to start measuring
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param end 1 beyond the index of the last character to measure
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param fmi FontMetrics information. Can be null
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The width of the text
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static float measureText(TextPaint paint,
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    TextPaint workPaint,
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    CharSequence text, int start, int end,
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    Paint.FontMetricsInt fmi) {
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Keep workPaint as is so that developers reuse the workspace.
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return foreach(null, text, start, end,
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                       Layout.DIR_LEFT_TO_RIGHT, false,
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                       0, 0, 0, 0, fmi, paint, workPaint, true);
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
376