Layout.java revision 2fb503f5102dd32a8ec391b26911528852703b90
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
19105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.emoji.EmojiFactory;
20105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.graphics.Bitmap;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect;
24c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischerimport android.graphics.RectF;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Path;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.util.ArrayUtils;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport junit.framework.Assert;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.*;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.TextKeyListener;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A base class that manages text layout in visual elements on
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the screen.
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>For text that will be edited, use a {@link DynamicLayout},
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * which will be updated as the text changes.
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For text that will not change, use a {@link StaticLayout}.
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class Layout {
4176c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort    private static final boolean DEBUG = false;
4271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt    private static final ParagraphStyle[] NO_PARA_SPANS =
4371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        ArrayUtils.emptyArray(ParagraphStyle.class);
4476c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort
45105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /* package */ static final EmojiFactory EMOJI_FACTORY =
46105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        EmojiFactory.newAvailableInstance();
47105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /* package */ static final int MIN_EMOJI, MAX_EMOJI;
48105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
49105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    static {
50105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (EMOJI_FACTORY != null) {
51105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            MIN_EMOJI = EMOJI_FACTORY.getMinimumAndroidPua();
52105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            MAX_EMOJI = EMOJI_FACTORY.getMaximumAndroidPua();
53105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } else {
54105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            MIN_EMOJI = -1;
55105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            MAX_EMOJI = -1;
56105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
57105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    };
58105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
59c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer    private RectF mEmojiRect;
60c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Return how wide a layout must be in order to display the
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * specified text with one line per paragraph.
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static float getDesiredWidth(CharSequence source,
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        TextPaint paint) {
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getDesiredWidth(source, 0, source.length(), paint);
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Return how wide a layout must be in order to display the
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * specified text slice with one line per paragraph.
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static float getDesiredWidth(CharSequence source,
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        int start, int end,
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        TextPaint paint) {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float need = 0;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TextPaint workPaint = new TextPaint();
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int next;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = start; i <= end; i = next) {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            next = TextUtils.indexOf(source, '\n', i, end);
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (next < 0)
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                next = end;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            // note, omits trailing paragraph char
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float w = measureText(paint, workPaint,
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                  source, i, next, null, true, null);
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (w > need)
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                need = w;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            next++;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return need;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Subclasses of Layout use this constructor to set the display text,
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * width, and other standard properties.
10371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param text the text to render
10471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param paint the default paint for the layout.  Styles can override
10571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * various attributes of the paint.
10671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param width the wrapping width for the text.
10771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param align whether to left, right, or center the text.  Styles can
10871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * override the alignment.
10971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param spacingMult factor by which to scale the font size to get the
11071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * default line spacing
11171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param spacingAdd amount to add to the default line spacing
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected Layout(CharSequence text, TextPaint paint,
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                     int width, Alignment align,
11571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                     float spacingMult, float spacingAdd) {
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (width < 0)
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Layout: " + width + " < 0");
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mText = text;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPaint = paint;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWorkPaint = new TextPaint();
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWidth = width;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAlignment = align;
12471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        mSpacingMult = spacingMult;
12571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        mSpacingAdd = spacingAdd;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSpannedText = text instanceof Spanned;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Replace constructor properties of this Layout with new ones.  Be careful.
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ void replaceWith(CharSequence text, TextPaint paint,
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              int width, Alignment align,
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              float spacingmult, float spacingadd) {
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (width < 0) {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Layout: " + width + " < 0");
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mText = text;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPaint = paint;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWidth = width;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAlignment = align;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSpacingMult = spacingmult;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSpacingAdd = spacingadd;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSpannedText = text instanceof Spanned;
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Draw this Layout on the specified Canvas.
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void draw(Canvas c) {
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        draw(c, null, null, 0);
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
15671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Draw this Layout on the specified canvas, with the highlight path drawn
15771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * between the background and the text.
15871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     *
15971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param c the canvas
16071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param highlight the path of the highlight or cursor; can be null
16171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param highlightPaint the paint for the highlight
16271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param cursorOffsetVertical the amount to temporarily translate the
16371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     *        canvas while rendering the highlight
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
16571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt    public void draw(Canvas c, Path highlight, Paint highlightPaint,
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                     int cursorOffsetVertical) {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dtop, dbottom;
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (sTempRect) {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!c.getClipBounds(sTempRect)) {
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dtop = sTempRect.top;
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dbottom = sTempRect.bottom;
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int top = 0;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int bottom = getLineTop(getLineCount());
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dtop > top) {
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            top = dtop;
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dbottom < bottom) {
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottom = dbottom;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int first = getLineForVertical(top);
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int last = getLineForVertical(bottom);
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int previousLineBottom = getLineTop(first);
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int previousLineEnd = getLineStart(first);
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        TextPaint paint = mPaint;
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence buf = mText;
19771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        int width = mWidth;
19871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        boolean spannedText = mSpannedText;
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        ParagraphStyle[] spans = NO_PARA_SPANS;
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int spanend = 0;
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int textLength = 0;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // First, draw LineBackgroundSpans.
20571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // LineBackgroundSpans know nothing about the alignment or direction of
20671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // the layout or line.  XXX: Should they?
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (spannedText) {
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            textLength = buf.length();
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = first; i <= last; i++) {
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int start = previousLineEnd;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int end = getLineStart(i+1);
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                previousLineEnd = end;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int ltop = previousLineBottom;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int lbottom = getLineTop(i+1);
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                previousLineBottom = lbottom;
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int lbaseline = lbottom - getLineDescent(i);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (start >= spanend) {
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                   Spanned sp = (Spanned) buf;
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                   spanend = sp.nextSpanTransition(start, textLength,
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                   LineBackgroundSpan.class);
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                   spans = sp.getSpans(start, spanend,
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       LineBackgroundSpan.class);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int n = 0; n < spans.length; n++) {
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    LineBackgroundSpan back = (LineBackgroundSpan) spans[n];
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                    back.drawBackground(c, paint, 0, width,
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       ltop, lbaseline, lbottom,
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       buf, start, end,
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       i);
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // reset to their original values
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            spanend = 0;
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            previousLineBottom = getLineTop(first);
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            previousLineEnd = getLineStart(first);
24071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            spans = NO_PARA_SPANS;
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // There can be a highlight even without spans if we are drawing
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // a non-spanned transformation of a spanned editing buffer.
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (highlight != null) {
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cursorOffsetVertical != 0) {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c.translate(0, cursorOffsetVertical);
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            c.drawPath(highlight, highlightPaint);
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cursorOffsetVertical != 0) {
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c.translate(0, -cursorOffsetVertical);
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Alignment align = mAlignment;
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // Next draw the lines, one at a time.
26071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // the baseline is the top of the following line minus the current
26171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // line's descent.
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = first; i <= last; i++) {
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int start = previousLineEnd;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            previousLineEnd = getLineStart(i+1);
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int end = getLineVisibleEnd(i, start, previousLineEnd);
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int ltop = previousLineBottom;
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int lbottom = getLineTop(i+1);
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            previousLineBottom = lbottom;
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int lbaseline = lbottom - getLineDescent(i);
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            boolean isFirstParaLine = false;
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spannedText) {
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (start == 0 || buf.charAt(start - 1) == '\n') {
27671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                    isFirstParaLine = true;
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
27871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                // New batch of paragraph styles, compute the alignment.
27971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                // Last alignment style wins.
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (start >= spanend) {
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Spanned sp = (Spanned) buf;
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    spanend = sp.nextSpanTransition(start, textLength,
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                    ParagraphStyle.class);
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    spans = sp.getSpans(start, spanend, ParagraphStyle.class);
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    align = mAlignment;
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int n = spans.length-1; n >= 0; n--) {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (spans[n] instanceof AlignmentSpan) {
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            align = ((AlignmentSpan) spans[n]).getAlignment();
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break;
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int dir = getParagraphDirection(i);
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int left = 0;
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int right = mWidth;
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            // Draw all leading margin spans.  Adjust left or right according
30171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            // to the paragraph direction of the line.
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spannedText) {
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int length = spans.length;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int n = 0; n < length; n++) {
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (spans[n] instanceof LeadingMarginSpan) {
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        LeadingMarginSpan margin = (LeadingMarginSpan) spans[n];
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (dir == DIR_RIGHT_TO_LEFT) {
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            margin.drawLeadingMargin(c, paint, right, dir, ltop,
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                     lbaseline, lbottom, buf,
31171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                                                     start, end, isFirstParaLine, this);
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                            right -= margin.getLeadingMargin(isFirstParaLine);
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            margin.drawLeadingMargin(c, paint, left, dir, ltop,
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                     lbaseline, lbottom, buf,
31771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                                                     start, end, isFirstParaLine, this);
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                            boolean useMargin = isFirstParaLine;
3207b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                            if (margin instanceof LeadingMarginSpan.LeadingMarginSpan2) {
3217b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                                int count = ((LeadingMarginSpan.LeadingMarginSpan2)margin).getLeadingMarginLineCount();
3227b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                                useMargin = count > i;
3237b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                            }
3247b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                            left += margin.getLeadingMargin(useMargin);
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            // Adjust the point at which to start rendering depending on the
33171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            // alignment of the paragraph.
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int x;
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (align == Alignment.ALIGN_NORMAL) {
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (dir == DIR_LEFT_TO_RIGHT) {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    x = left;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    x = right;
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int max = (int)getLineMax(i, spans, false);
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (align == Alignment.ALIGN_OPPOSITE) {
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (dir == DIR_RIGHT_TO_LEFT) {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        x = left + max;
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        x = right - max;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Alignment.ALIGN_CENTER
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    max = max & ~1;
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int half = (right - left - max) >> 1;
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (dir == DIR_RIGHT_TO_LEFT) {
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        x = right - half;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        x = left + half;
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Directions directions = getLineDirections(i);
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean hasTab = getLineContainsTab(i);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (directions == DIRS_ALL_LEFT_TO_RIGHT &&
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    !spannedText && !hasTab) {
36376c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort                if (DEBUG) {
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Assert.assertTrue(dir == DIR_LEFT_TO_RIGHT);
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Assert.assertNotNull(c);
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
36771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                // XXX: assumes there's nothing additional to be done
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c.drawText(buf, start, end, x, lbaseline, paint);
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                drawText(c, buf, start, end, dir, directions,
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    x, ltop, lbaseline, lbottom, paint, mWorkPaint,
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    hasTab, spans);
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the text that is displayed by this Layout.
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final CharSequence getText() {
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mText;
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the base Paint properties for this layout.
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Do NOT change the paint, which may result in funny
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * drawing for this layout.
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final TextPaint getPaint() {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mPaint;
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the width of this layout.
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final int getWidth() {
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mWidth;
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the width to which this Layout is ellipsizing, or
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #getWidth} if it is not doing anything special.
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsizedWidth() {
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mWidth;
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Increase the width of this layout to the specified width.
41071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Be careful to use this only when you know it is appropriate&mdash;
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * it does not cause the text to reflow to use the full new width.
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final void increaseWidthTo(int wid) {
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (wid < mWidth) {
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException("attempted to reduce Layout width");
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWidth = wid;
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the total height of this layout.
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getHeight() {
42571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        return getLineTop(getLineCount());
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the base alignment of this layout.
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Alignment getAlignment() {
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAlignment;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return what the text height is multiplied by to get the line height.
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final float getSpacingMultiplier() {
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mSpacingMult;
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the number of units of leading that are added to each line.
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final float getSpacingAdd() {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mSpacingAdd;
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the number of lines of text in this layout.
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getLineCount();
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the baseline for the specified line (0&hellip;getLineCount() - 1)
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If bounds is not null, return the top, left, right, bottom extents
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of the specified line in it.
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param line which line to examine (0..getLineCount() - 1)
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param bounds Optional. If not null, it returns the extent of the line
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the Y-coordinate of the baseline
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineBounds(int line, Rect bounds) {
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (bounds != null) {
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bounds.left = 0;     // ???
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bounds.top = getLineTop(line);
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bounds.right = mWidth;   // ???
46771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            bounds.bottom = getLineTop(line + 1);
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getLineBaseline(line);
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
47371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Return the vertical position of the top of the specified line
47471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * (0&hellip;getLineCount()).
47571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * If the specified line is equal to the line count, returns the
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * bottom of the last line.
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getLineTop(int line);
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
48171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Return the descent of the specified line(0&hellip;getLineCount() - 1).
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getLineDescent(int line);
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
48671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Return the text offset of the beginning of the specified line (
48771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * 0&hellip;getLineCount()). If the specified line is equal to the line
48871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * count, returns the length of the text.
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getLineStart(int line);
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
49371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Returns the primary directionality of the paragraph containing the
49471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * specified line, either 1 for left-to-right lines, or -1 for right-to-left
49571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * lines (see {@link #DIR_LEFT_TO_RIGHT}, {@link #DIR_RIGHT_TO_LEFT}).
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getParagraphDirection(int line);
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
500105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * Returns whether the specified line contains one or more
501105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * characters that need to be handled specially, like tabs
502105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * or emoji.
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract boolean getLineContainsTab(int line);
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
50771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Returns the directional run information for the specified line.
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The array alternates counts of characters in left-to-right
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and right-to-left segments of the line.
51071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     *
51171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * <p>NOTE: this is inadequate to support bidirectional text, and will change.
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract Directions getLineDirections(int line);
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the (negative) number of extra pixels of ascent padding in the
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * top line of the Layout.
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getTopPadding();
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the number of extra pixels of descent padding in the
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * bottom line of the Layout.
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getBottomPadding();
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the primary horizontal position for the specified text offset.
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This is the location where a new character would be inserted in
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the paragraph's primary direction.
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public float getPrimaryHorizontal(int offset) {
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getHorizontal(offset, false, true);
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the secondary horizontal position for the specified text offset.
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This is the location where a new character would be inserted in
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the direction other than the paragraph's primary direction.
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public float getSecondaryHorizontal(int offset) {
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getHorizontal(offset, true, true);
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float getHorizontal(int offset, boolean trailing, boolean alt) {
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int line = getLineForOffset(offset);
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getHorizontal(offset, trailing, alt, line);
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float getHorizontal(int offset, boolean trailing, boolean alt,
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                int line) {
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int start = getLineStart(line);
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getLineVisibleEnd(line);
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dir = getParagraphDirection(line);
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean tab = getLineContainsTab(line);
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Directions directions = getLineDirections(line);
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TabStopSpan[] tabs = null;
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (tab && mText instanceof Spanned) {
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class);
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float wid = measureText(mPaint, mWorkPaint, mText, start, offset, end,
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                dir, directions, trailing, alt, tab, tabs);
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (offset > end) {
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dir == DIR_RIGHT_TO_LEFT)
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                wid -= measureText(mPaint, mWorkPaint,
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   mText, end, offset, null, tab, tabs);
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                wid += measureText(mPaint, mWorkPaint,
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   mText, end, offset, null, tab, tabs);
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Alignment align = getParagraphAlignment(line);
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int left = getParagraphLeft(line);
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int right = getParagraphRight(line);
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (align == Alignment.ALIGN_NORMAL) {
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dir == DIR_RIGHT_TO_LEFT)
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return right + wid;
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return left + wid;
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float max = getLineMax(line);
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (align == Alignment.ALIGN_OPPOSITE) {
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dir == DIR_RIGHT_TO_LEFT)
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return left + max + wid;
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return right - max + wid;
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else { /* align == Alignment.ALIGN_CENTER */
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int imax = ((int) max) & ~1;
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dir == DIR_RIGHT_TO_LEFT)
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return right - (((right - left) - imax) / 2) + wid;
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return left + ((right - left) - imax) / 2 + wid;
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the leftmost position that should be exposed for horizontal
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * scrolling on the specified line.
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public float getLineLeft(int line) {
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dir = getParagraphDirection(line);
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Alignment align = getParagraphAlignment(line);
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (align == Alignment.ALIGN_NORMAL) {
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dir == DIR_RIGHT_TO_LEFT)
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return getParagraphRight(line) - getLineMax(line);
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (align == Alignment.ALIGN_OPPOSITE) {
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dir == DIR_RIGHT_TO_LEFT)
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mWidth - getLineMax(line);
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else { /* align == Alignment.ALIGN_CENTER */
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int left = getParagraphLeft(line);
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int right = getParagraphRight(line);
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int max = ((int) getLineMax(line)) & ~1;
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return left + ((right - left) - max) / 2;
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the rightmost position that should be exposed for horizontal
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * scrolling on the specified line.
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public float getLineRight(int line) {
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dir = getParagraphDirection(line);
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Alignment align = getParagraphAlignment(line);
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (align == Alignment.ALIGN_NORMAL) {
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dir == DIR_RIGHT_TO_LEFT)
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mWidth;
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return getParagraphLeft(line) + getLineMax(line);
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (align == Alignment.ALIGN_OPPOSITE) {
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dir == DIR_RIGHT_TO_LEFT)
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return getLineMax(line);
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mWidth;
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else { /* align == Alignment.ALIGN_CENTER */
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int left = getParagraphLeft(line);
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int right = getParagraphRight(line);
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int max = ((int) getLineMax(line)) & ~1;
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return right - ((right - left) - max) / 2;
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the horizontal extent of the specified line, excluding
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * trailing whitespace.
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public float getLineMax(int line) {
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getLineMax(line, null, false);
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the horizontal extent of the specified line, including
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * trailing whitespace.
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public float getLineWidth(int line) {
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getLineMax(line, null, true);
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float getLineMax(int line, Object[] tabs, boolean full) {
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int start = getLineStart(line);
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end;
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (full) {
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            end = getLineEnd(line);
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            end = getLineVisibleEnd(line);
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean tab = getLineContainsTab(line);
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (tabs == null && tab && mText instanceof Spanned) {
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class);
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return measureText(mPaint, mWorkPaint,
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                           mText, start, end, null, tab, tabs);
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the line number corresponding to the specified vertical position.
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If you ask for a position above 0, you get 0; if you ask for a position
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * below the bottom of the text, you get the last line.
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // FIXME: It may be faster to do a linear search for layouts without many lines.
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineForVertical(int vertical) {
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int high = getLineCount(), low = -1, guess;
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (high - low > 1) {
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            guess = (high + low) / 2;
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (getLineTop(guess) > vertical)
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                high = guess;
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                low = guess;
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (low < 0)
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return low;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the line number on which the specified text offset appears.
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If you ask for a position before 0, you get 0; if you ask for a position
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * beyond the end of the text, you get the last line.
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineForOffset(int offset) {
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int high = getLineCount(), low = -1, guess;
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (high - low > 1) {
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            guess = (high + low) / 2;
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (getLineStart(guess) > offset)
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                high = guess;
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                low = guess;
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (low < 0)
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return low;
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the character offset on the specfied line whose position is
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * closest to the specified horizontal position.
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getOffsetForHorizontal(int line, float horiz) {
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int max = getLineEnd(line) - 1;
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int min = getLineStart(line);
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Directions dirs = getLineDirections(line);
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (line == getLineCount() - 1)
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            max++;
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
75212122bf7929aab7417cda5642632b81e4e15eb4eTakako Ishibashi        if (line != getLineCount() - 1)
75312122bf7929aab7417cda5642632b81e4e15eb4eTakako Ishibashi            max = TextUtils.getOffsetBefore(mText, getLineEnd(line));
75412122bf7929aab7417cda5642632b81e4e15eb4eTakako Ishibashi
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int best = min;
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz);
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int here = min;
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < dirs.mDirections.length; i++) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int there = here + dirs.mDirections[i];
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int swap = ((i & 1) == 0) ? 1 : -1;
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (there > max)
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                there = max;
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int high = there - 1 + 1, low = here + 1 - 1, guess;
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (high - low > 1) {
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                guess = (high + low) / 2;
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int adguess = getOffsetAtStartOf(guess);
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (getPrimaryHorizontal(adguess) * swap >= horiz * swap)
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    high = guess;
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                else
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    low = guess;
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (low < here + 1)
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                low = here + 1;
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (low < there) {
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                low = getOffsetAtStartOf(low);
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                float dist = Math.abs(getPrimaryHorizontal(low) - horiz);
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int aft = TextUtils.getOffsetAfter(mText, low);
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (aft < there) {
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    float other = Math.abs(getPrimaryHorizontal(aft) - horiz);
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (other < dist) {
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        dist = other;
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        low = aft;
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (dist < bestdist) {
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    bestdist = dist;
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    best = low;
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float dist = Math.abs(getPrimaryHorizontal(here) - horiz);
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dist < bestdist) {
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bestdist = dist;
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                best = here;
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            here = there;
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float dist = Math.abs(getPrimaryHorizontal(max) - horiz);
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dist < bestdist) {
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bestdist = dist;
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            best = max;
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return best;
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the text offset after the last character on the specified line.
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final int getLineEnd(int line) {
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getLineStart(line + 1);
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the text offset after the last visible character (so whitespace
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is not counted) on the specified line.
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineVisibleEnd(int line) {
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getLineVisibleEnd(line, getLineStart(line), getLineStart(line+1));
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getLineVisibleEnd(int line, int start, int end) {
83876c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort        if (DEBUG) {
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Assert.assertTrue(getLineStart(line) == start && getLineStart(line+1) == end);
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence text = mText;
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char ch;
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (line == getLineCount() - 1) {
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return end;
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (; end > start; end--) {
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ch = text.charAt(end - 1);
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (ch == '\n') {
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return end - 1;
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (ch != ' ' && ch != '\t') {
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return end;
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the vertical position of the bottom of the specified line.
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final int getLineBottom(int line) {
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getLineTop(line + 1);
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the vertical position of the baseline of the specified line.
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final int getLineBaseline(int line) {
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // getLineTop(line+1) == getLineTop(line)
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getLineTop(line+1) - getLineDescent(line);
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the ascent of the text on the specified line.
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The return value is negative to match the Paint.ascent() convention.
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final int getLineAscent(int line) {
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // getLineTop(line+1) - getLineDescent(line) == getLineBaseLine(line)
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getLineTop(line) - (getLineTop(line+1) - getLineDescent(line));
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the text offset that would be reached by moving left
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (possibly onto another line) from the specified offset.
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getOffsetToLeftOf(int offset) {
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int line = getLineForOffset(offset);
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int start = getLineStart(line);
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getLineEnd(line);
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Directions dirs = getLineDirections(line);
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (line != getLineCount() - 1)
89912122bf7929aab7417cda5642632b81e4e15eb4eTakako Ishibashi            end = TextUtils.getOffsetBefore(mText, end);
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float horiz = getPrimaryHorizontal(offset);
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int best = offset;
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float besth = Integer.MIN_VALUE;
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int candidate;
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        candidate = TextUtils.getOffsetBefore(mText, offset);
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (candidate >= start && candidate <= end) {
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float h = getPrimaryHorizontal(candidate);
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (h < horiz && h > besth) {
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                best = candidate;
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                besth = h;
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        candidate = TextUtils.getOffsetAfter(mText, offset);
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (candidate >= start && candidate <= end) {
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float h = getPrimaryHorizontal(candidate);
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (h < horiz && h > besth) {
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                best = candidate;
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                besth = h;
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int here = start;
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < dirs.mDirections.length; i++) {
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int there = here + dirs.mDirections[i];
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (there > end)
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                there = end;
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float h = getPrimaryHorizontal(here);
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (h < horiz && h > besth) {
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                best = here;
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                besth = h;
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            candidate = TextUtils.getOffsetAfter(mText, here);
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (candidate >= start && candidate <= end) {
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                h = getPrimaryHorizontal(candidate);
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (h < horiz && h > besth) {
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    best = candidate;
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    besth = h;
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            candidate = TextUtils.getOffsetBefore(mText, there);
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (candidate >= start && candidate <= end) {
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                h = getPrimaryHorizontal(candidate);
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (h < horiz && h > besth) {
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    best = candidate;
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    besth = h;
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            here = there;
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float h = getPrimaryHorizontal(end);
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (h < horiz && h > besth) {
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            best = end;
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            besth = h;
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (best != offset)
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return best;
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dir = getParagraphDirection(line);
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dir > 0) {
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (line == 0)
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return best;
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return getOffsetForHorizontal(line - 1, 10000);
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (line == getLineCount() - 1)
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return best;
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return getOffsetForHorizontal(line + 1, 10000);
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the text offset that would be reached by moving right
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (possibly onto another line) from the specified offset.
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getOffsetToRightOf(int offset) {
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int line = getLineForOffset(offset);
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int start = getLineStart(line);
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end = getLineEnd(line);
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Directions dirs = getLineDirections(line);
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (line != getLineCount() - 1)
99912122bf7929aab7417cda5642632b81e4e15eb4eTakako Ishibashi            end = TextUtils.getOffsetBefore(mText, end);
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float horiz = getPrimaryHorizontal(offset);
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int best = offset;
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float besth = Integer.MAX_VALUE;
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int candidate;
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        candidate = TextUtils.getOffsetBefore(mText, offset);
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (candidate >= start && candidate <= end) {
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float h = getPrimaryHorizontal(candidate);
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (h > horiz && h < besth) {
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                best = candidate;
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                besth = h;
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        candidate = TextUtils.getOffsetAfter(mText, offset);
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (candidate >= start && candidate <= end) {
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float h = getPrimaryHorizontal(candidate);
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (h > horiz && h < besth) {
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                best = candidate;
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                besth = h;
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int here = start;
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < dirs.mDirections.length; i++) {
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int there = here + dirs.mDirections[i];
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (there > end)
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                there = end;
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float h = getPrimaryHorizontal(here);
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (h > horiz && h < besth) {
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                best = here;
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                besth = h;
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            candidate = TextUtils.getOffsetAfter(mText, here);
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (candidate >= start && candidate <= end) {
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                h = getPrimaryHorizontal(candidate);
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (h > horiz && h < besth) {
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    best = candidate;
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    besth = h;
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            candidate = TextUtils.getOffsetBefore(mText, there);
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (candidate >= start && candidate <= end) {
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                h = getPrimaryHorizontal(candidate);
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (h > horiz && h < besth) {
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    best = candidate;
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    besth = h;
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            here = there;
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float h = getPrimaryHorizontal(end);
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (h > horiz && h < besth) {
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            best = end;
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            besth = h;
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (best != offset)
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return best;
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dir = getParagraphDirection(line);
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dir > 0) {
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (line == getLineCount() - 1)
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return best;
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return getOffsetForHorizontal(line + 1, -10000);
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (line == 0)
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return best;
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return getOffsetForHorizontal(line - 1, -10000);
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int getOffsetAtStartOf(int offset) {
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (offset == 0)
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence text = mText;
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char c = text.charAt(offset);
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\uDC00' && c <= '\uDFFF') {
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c1 = text.charAt(offset - 1);
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c1 >= '\uD800' && c1 <= '\uDBFF')
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                offset -= 1;
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mSpannedText) {
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset,
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                       ReplacementSpan.class);
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < spans.length; i++) {
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int start = ((Spanned) text).getSpanStart(spans[i]);
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int end = ((Spanned) text).getSpanEnd(spans[i]);
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (start < offset && end > offset)
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    offset = start;
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return offset;
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills in the specified Path with a representation of a cursor
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * at the specified offset.  This will often be a vertical line
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * but can be multiple discontinous lines in text with multiple
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * directionalities.
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void getCursorPath(int point, Path dest,
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              CharSequence editingBuffer) {
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dest.reset();
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int line = getLineForOffset(point);
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int top = getLineTop(line);
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int bottom = getLineTop(line+1);
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float h1 = getPrimaryHorizontal(point) - 0.5f;
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float h2 = getSecondaryHorizontal(point) - 0.5f;
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int caps = TextKeyListener.getMetaState(editingBuffer,
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                KeyEvent.META_SHIFT_ON) |
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                   TextKeyListener.getMetaState(editingBuffer,
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                TextKeyListener.META_SELECTING);
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int fn = TextKeyListener.getMetaState(editingBuffer,
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                              KeyEvent.META_ALT_ON);
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dist = 0;
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (caps != 0 || fn != 0) {
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dist = (bottom - top) >> 2;
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (fn != 0)
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                top += dist;
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (caps != 0)
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bottom -= dist;
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (h1 < 0.5f)
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            h1 = 0.5f;
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (h2 < 0.5f)
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            h2 = 0.5f;
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11572fb503f5102dd32a8ec391b26911528852703b90Jozef BABJAK        if (Float.compare(h1, h2) == 0) {
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h1, top);
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h1, bottom);
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h1, top);
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h1, (top + bottom) >> 1);
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h2, (top + bottom) >> 1);
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h2, bottom);
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (caps == 2) {
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h2, bottom);
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h2 - dist, bottom + dist);
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h2, bottom);
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h2 + dist, bottom + dist);
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (caps == 1) {
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h2, bottom);
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h2 - dist, bottom + dist);
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h2 - dist, bottom + dist - 0.5f);
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h2 + dist, bottom + dist - 0.5f);
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h2 + dist, bottom + dist);
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h2, bottom);
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fn == 2) {
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h1, top);
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h1 - dist, top - dist);
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h1, top);
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h1 + dist, top - dist);
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (fn == 1) {
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h1, top);
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h1 - dist, top - dist);
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h1 - dist, top - dist + 0.5f);
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h1 + dist, top - dist + 0.5f);
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.moveTo(h1 + dist, top - dist);
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.lineTo(h1, top);
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void addSelection(int line, int start, int end,
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              int top, int bottom, Path dest) {
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int linestart = getLineStart(line);
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int lineend = getLineEnd(line);
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Directions dirs = getLineDirections(line);
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lineend > linestart && mText.charAt(lineend - 1) == '\n')
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            lineend--;
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int here = linestart;
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < dirs.mDirections.length; i++) {
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int there = here + dirs.mDirections[i];
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (there > lineend)
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                there = lineend;
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (start <= there && end >= here) {
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int st = Math.max(start, here);
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int en = Math.min(end, there);
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (st != en) {
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    float h1 = getHorizontal(st, false, false, line);
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    float h2 = getHorizontal(en, true, false, line);
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    dest.addRect(h1, top, h2, bottom, Path.Direction.CW);
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            here = there;
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fills in the specified Path with a representation of a highlight
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * between the specified offsets.  This will often be a rectangle
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * or a potentially discontinuous set of rectangles.  If the start
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and end are the same, the returned path is empty.
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void getSelectionPath(int start, int end, Path dest) {
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dest.reset();
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start == end)
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (end < start) {
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int temp = end;
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            end = start;
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            start = temp;
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int startline = getLineForOffset(start);
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int endline = getLineForOffset(end);
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int top = getLineTop(startline);
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int bottom = getLineBottom(endline);
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (startline == endline) {
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            addSelection(startline, start, end, top, bottom, dest);
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final float width = mWidth;
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            addSelection(startline, start, getLineEnd(startline),
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         top, getLineBottom(startline), dest);
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT)
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dest.addRect(getLineLeft(startline), top,
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              0, getLineBottom(startline), Path.Direction.CW);
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dest.addRect(getLineRight(startline), top,
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              width, getLineBottom(startline), Path.Direction.CW);
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = startline + 1; i < endline; i++) {
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                top = getLineTop(i);
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bottom = getLineBottom(i);
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dest.addRect(0, top, width, bottom, Path.Direction.CW);
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            top = getLineTop(endline);
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottom = getLineBottom(endline);
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            addSelection(endline, getLineStart(endline), end,
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         top, bottom, dest);
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT)
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dest.addRect(width, top, getLineRight(endline), bottom, Path.Direction.CW);
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dest.addRect(0, top, getLineLeft(endline), bottom, Path.Direction.CW);
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the alignment of the specified paragraph, taking into account
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * markup attached to it.
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Alignment getParagraphAlignment(int line) {
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Alignment align = mAlignment;
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mSpannedText) {
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Spanned sp = (Spanned) mText;
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            AlignmentSpan[] spans = sp.getSpans(getLineStart(line),
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                getLineEnd(line),
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                AlignmentSpan.class);
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int spanLength = spans.length;
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spanLength > 0) {
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                align = spans[spanLength-1].getAlignment();
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return align;
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the left edge of the specified paragraph, inset by left margins.
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final int getParagraphLeft(int line) {
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dir = getParagraphDirection(line);
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int left = 0;
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean par = false;
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int off = getLineStart(line);
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (off == 0 || mText.charAt(off - 1) == '\n')
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            par = true;
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dir == DIR_LEFT_TO_RIGHT) {
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSpannedText) {
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Spanned sp = (Spanned) mText;
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line),
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                        getLineEnd(line),
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                        LeadingMarginSpan.class);
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < spans.length; i++) {
13337b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    boolean margin = par;
13347b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    LeadingMarginSpan span = spans[i];
13357b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    if (span instanceof LeadingMarginSpan.LeadingMarginSpan2) {
13367b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                        int count = ((LeadingMarginSpan.LeadingMarginSpan2)span).getLeadingMarginLineCount();
13377b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                        margin = count >= line;
13387b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    }
13397b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    left += span.getLeadingMargin(margin);
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return left;
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the right edge of the specified paragraph, inset by right margins.
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final int getParagraphRight(int line) {
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int dir = getParagraphDirection(line);
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int right = mWidth;
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean par = false;
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int off = getLineStart(line);
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (off == 0 || mText.charAt(off - 1) == '\n')
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            par = true;
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (dir == DIR_RIGHT_TO_LEFT) {
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSpannedText) {
13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Spanned sp = (Spanned) mText;
13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line),
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                        getLineEnd(line),
13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                        LeadingMarginSpan.class);
13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < spans.length; i++) {
13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    right -= spans[i].getLeadingMargin(par);
13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return right;
13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1377c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer    private void drawText(Canvas canvas,
13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 CharSequence text, int start, int end,
13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 int dir, Directions directions,
13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 float x, int top, int y, int bottom,
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 TextPaint paint,
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 TextPaint workPaint,
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 boolean hasTabs, Object[] parspans) {
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char[] buf;
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!hasTabs) {
13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (directions == DIRS_ALL_LEFT_TO_RIGHT) {
138776c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort                if (DEBUG) {
13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Assert.assertTrue(DIR_LEFT_TO_RIGHT == dir);
13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Styled.drawText(canvas, text, start, end, dir, false, x, top, y, bottom, paint, workPaint, false);
13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            buf = null;
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            buf = TextUtils.obtain(end - start);
13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            TextUtils.getChars(text, start, end, buf, 0);
13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float h = 0;
14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int here = 0;
14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < directions.mDirections.length; i++) {
14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int there = here + directions.mDirections[i];
14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (there > end - start)
14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                there = end - start;
14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int segstart = here;
14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int j = hasTabs ? here : there; j <= there; j++) {
14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (j == there || buf[j] == '\t') {
14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    h += Styled.drawText(canvas, text,
14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                         start + segstart, start + j,
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                         dir, (i & 1) != 0, x + h,
14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                         top, y, bottom, paint, workPaint,
14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                         start + j != end);
14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (j != there && buf[j] == '\t')
14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        h = dir * nextTab(text, start, end, h * dir, parspans);
14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    segstart = j + 1;
1420105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } else if (hasTabs && buf[j] >= 0xD800 && buf[j] <= 0xDFFF && j + 1 < there) {
1421105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    int emoji = Character.codePointAt(buf, j);
1422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1423105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
1424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        Bitmap bm = EMOJI_FACTORY.
1425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            getBitmapFromAndroidPua(emoji);
1426105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1427105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        if (bm != null) {
1428105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            h += Styled.drawText(canvas, text,
1429105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                                                 start + segstart, start + j,
1430105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                                                 dir, (i & 1) != 0, x + h,
1431105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                                                 top, y, bottom, paint, workPaint,
1432105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                                                 start + j != end);
1433105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1434c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            if (mEmojiRect == null) {
1435c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                                mEmojiRect = new RectF();
1436c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            }
1437c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
1438c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            workPaint.set(paint);
1439c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            Styled.measureText(paint, workPaint, text,
1440c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                                               start + j, start + j + 1,
1441c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                                               null);
1442c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
1443c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            float bitmapHeight = bm.getHeight();
1444c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            float textHeight = -workPaint.ascent();
1445c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            float scale = textHeight / bitmapHeight;
1446c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            float width = bm.getWidth() * scale;
1447c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
1448c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            mEmojiRect.set(x + h, y - textHeight,
1449c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                                           x + h + width, y);
1450c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
1451c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            canvas.drawBitmap(bm, null, mEmojiRect, paint);
1452c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            h += width;
1453c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
1454105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            j++;
1455105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            segstart = j + 1;
1456105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        }
1457105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    }
14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            here = there;
14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (hasTabs)
14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            TextUtils.recycle(buf);
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static float measureText(TextPaint paint,
14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     TextPaint workPaint,
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     CharSequence text,
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     int start, int offset, int end,
14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     int dir, Directions directions,
14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     boolean trailing, boolean alt,
14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     boolean hasTabs, Object[] tabs) {
14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char[] buf = null;
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (hasTabs) {
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            buf = TextUtils.obtain(end - start);
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            TextUtils.getChars(text, start, end, buf, 0);
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float h = 0;
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (alt) {
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (dir == DIR_RIGHT_TO_LEFT)
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                trailing = !trailing;
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int here = 0;
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < directions.mDirections.length; i++) {
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (alt)
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                trailing = !trailing;
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int there = here + directions.mDirections[i];
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (there > end - start)
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                there = end - start;
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int segstart = here;
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int j = hasTabs ? here : there; j <= there; j++) {
1500105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                int codept = 0;
1501105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                Bitmap bm = null;
1502105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1503105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                if (hasTabs && j < there) {
1504105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    codept = buf[j];
1505105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
1506105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1507105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                if (codept >= 0xD800 && codept <= 0xDFFF && j + 1 < there) {
1508105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    codept = Character.codePointAt(buf, j);
1509105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1510105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
1511105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
1512105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    }
1513105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
1514105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1515105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                if (j == there || codept == '\t' || bm != null) {
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    float segw;
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (offset < start + j ||
15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                       (trailing && offset <= start + j)) {
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (dir == DIR_LEFT_TO_RIGHT && (i & 1) == 0) {
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            h += Styled.measureText(paint, workPaint, text,
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                    start + segstart, offset,
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                    null);
15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            return h;
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (dir == DIR_RIGHT_TO_LEFT && (i & 1) != 0) {
15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            h -= Styled.measureText(paint, workPaint, text,
15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                    start + segstart, offset,
15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                    null);
15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            return h;
15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    segw = Styled.measureText(paint, workPaint, text,
15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                              start + segstart, start + j,
15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                              null);
15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (offset < start + j ||
15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (trailing && offset <= start + j)) {
15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (dir == DIR_LEFT_TO_RIGHT) {
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            h += segw - Styled.measureText(paint, workPaint,
15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                           text,
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                           start + segstart,
15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                           offset, null);
15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            return h;
15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (dir == DIR_RIGHT_TO_LEFT) {
15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            h -= segw - Styled.measureText(paint, workPaint,
15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                           text,
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                           start + segstart,
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                           offset, null);
15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            return h;
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (dir == DIR_RIGHT_TO_LEFT)
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        h -= segw;
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    else
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        h += segw;
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (j != there && buf[j] == '\t') {
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (offset == start + j)
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            return h;
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        h = dir * nextTab(text, start, end, h * dir, tabs);
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
157012122bf7929aab7417cda5642632b81e4e15eb4eTakako Ishibashi                    if (j != there && bm != null) {
157112122bf7929aab7417cda5642632b81e4e15eb4eTakako Ishibashi                        if (offset == start + j) return h;
1572c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                        workPaint.set(paint);
1573c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                        Styled.measureText(paint, workPaint, text,
1574a82e99a89b7a12bd86d99d60d23a7a37624499b6Eric Fischer                                           j, j + 2, null);
1575c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
1576c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                        float wid = (float) bm.getWidth() *
1577c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                                    -workPaint.ascent() / bm.getHeight();
1578c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
1579105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        if (dir == DIR_RIGHT_TO_LEFT) {
1580c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            h -= wid;
1581105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        } else {
1582c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                            h += wid;
1583105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        }
1584105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1585105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        j++;
1586105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    }
1587105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    segstart = j + 1;
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            here = there;
15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (hasTabs)
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            TextUtils.recycle(buf);
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return h;
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
160171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt    /**
160271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Measure width of a run of text on a single line that is known to all be
160371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * in the same direction as the paragraph base direction. Returns the width,
160471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * and the line metrics in fm if fm is not null.
160571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     *
160671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param paint the paint for the text; will not be modified
160771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param workPaint paint available for modification
160871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param text text
160971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param start start of the line
161071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param end limit of the line
161171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param fm object to return integer metrics in, can be null
161271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param hasTabs true if it is known that the line has tabs
161371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param tabs tab position information
161471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @return the width of the text from start to end
161571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     */
16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static float measureText(TextPaint paint,
16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                           TextPaint workPaint,
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                           CharSequence text,
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                           int start, int end,
16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                           Paint.FontMetricsInt fm,
16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                           boolean hasTabs, Object[] tabs) {
16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        char[] buf = null;
16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (hasTabs) {
16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            buf = TextUtils.obtain(end - start);
16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            TextUtils.getChars(text, start, end, buf, 0);
16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = end - start;
16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
163171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        int lastPos = 0;
163271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        float width = 0;
163371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        int ascent = 0, descent = 0, top = 0, bottom = 0;
16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fm != null) {
16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.ascent = 0;
16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.descent = 0;
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
164071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        for (int pos = hasTabs ? 0 : len; pos <= len; pos++) {
1641105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            int codept = 0;
1642105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Bitmap bm = null;
1643105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
164471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            if (hasTabs && pos < len) {
164571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                codept = buf[pos];
1646105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            }
1647105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
164871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            if (codept >= 0xD800 && codept <= 0xDFFF && pos < len) {
164971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                codept = Character.codePointAt(buf, pos);
1650105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1651105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
1652105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
1653105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
1654105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            }
1655105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
165671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            if (pos == len || codept == '\t' || bm != null) {
16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                workPaint.baselineShift = 0;
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
165971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                width += Styled.measureText(paint, workPaint, text,
166071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                                        start + lastPos, start + pos,
16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        fm);
16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fm != null) {
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (workPaint.baselineShift < 0) {
16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        fm.ascent += workPaint.baselineShift;
16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        fm.top += workPaint.baselineShift;
16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        fm.descent += workPaint.baselineShift;
16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        fm.bottom += workPaint.baselineShift;
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
167371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                if (pos != len) {
1674105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (bm == null) {
167571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // no emoji, must have hit a tab
167671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        width = nextTab(text, start, end, width, tabs);
1677105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    } else {
167871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // This sets up workPaint with the font on the emoji
167971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // text, so that we can extract the ascent and scale.
168071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt
168171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // We can't use the result of the previous call to
168271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // measureText because the emoji might have its own style.
168371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // We have to initialize workPaint here because if the
168471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // text is unstyled measureText might not use workPaint
168571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // at all.
1686c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                        workPaint.set(paint);
1687c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                        Styled.measureText(paint, workPaint, text,
168871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                                           start + pos, start + pos + 1, null);
1689c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
169071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        width += (float) bm.getWidth() *
1691c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer                                    -workPaint.ascent() / bm.getHeight();
1692c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer
169371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // Since we had an emoji, we bump past the second half
169471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        // of the surrogate pair.
169571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        pos++;
1696105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    }
1697105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fm != null) {
170071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                    if (fm.ascent < ascent) {
170171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        ascent = fm.ascent;
17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
170371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                    if (fm.descent > descent) {
170471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        descent = fm.descent;
17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (fm.top < top) {
17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        top = fm.top;
17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
171071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                    if (fm.bottom > bottom) {
171171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                        bottom = fm.bottom;
17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1713105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
171471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                    // No need to take bitmap height into account here,
171571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                    // since it is scaled to match the text height.
17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
171871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt                lastPos = pos + 1;
17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (fm != null) {
172371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            fm.ascent = ascent;
172471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            fm.descent = descent;
17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.top = top;
172671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt            fm.bottom = bottom;
17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (hasTabs)
17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            TextUtils.recycle(buf);
17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
173271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        return width;
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
173571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt    /**
173671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * Returns the position of the next tab stop after h on the line.
173771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     *
173871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param text the text
173971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param start start of the line
174071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param end limit of the line
174171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param h the current horizontal offset
174271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @param tabs the tabs, can be null.  If it is null, any tabs in effect
174371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * on the line will be used.  If there are no tabs, a default offset
174471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * will be used to compute the tab stop.
174571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     * @return the offset of the next tab stop.
174671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt     */
17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static float nextTab(CharSequence text, int start, int end,
17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       float h, Object[] tabs) {
17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float nh = Float.MAX_VALUE;
17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean alltabs = false;
17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (text instanceof Spanned) {
17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (tabs == null) {
17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                tabs = ((Spanned) text).getSpans(start, end, TabStopSpan.class);
17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                alltabs = true;
17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < tabs.length; i++) {
17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!alltabs) {
17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!(tabs[i] instanceof TabStopSpan))
17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        continue;
17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int where = ((TabStopSpan) tabs[i]).getTabStop();
17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (where < nh && where > h)
17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    nh = where;
17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (nh != Float.MAX_VALUE)
17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return nh;
17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ((int) ((h + TAB_INCREMENT) / TAB_INCREMENT)) * TAB_INCREMENT;
17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected final boolean isSpanned() {
17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mSpannedText;
17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ellipsize(int start, int end, int line,
17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                           char[] dest, int destoff) {
17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ellipsisCount = getEllipsisCount(line);
17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ellipsisCount == 0) {
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ellipsisStart = getEllipsisStart(line);
17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int linestart = getLineStart(line);
17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = ellipsisStart; i < ellipsisStart + ellipsisCount; i++) {
17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c;
17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (i == ellipsisStart) {
17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c = '\u2026'; // ellipsis
17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c = '\uFEFF'; // 0-width space
17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int a = i + linestart;
18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (a >= start && a < end) {
18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dest[destoff + a - start] = c;
18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Stores information about bidirectional (left-to-right or right-to-left)
18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * text within the layout of a line.  TODO: This work is not complete
18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * or correct and will be fleshed out in a later revision.
18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static class Directions {
18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private short[] mDirections;
18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
181771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // The values in mDirections are the offsets from the first character
181871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // in the line to the next flip in direction.  Runs at even indices
181971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // are left-to-right, the others are right-to-left.  So, for example,
182071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // a line that starts with a right-to-left run has 0 at mDirections[0],
182171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // since the 'first' (ltr) run is zero length.
182271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        //
182371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // The code currently assumes that each run is adjacent to the previous
182471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // one, progressing in the base line direction.  This isn't sufficient
182571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // to handle nested runs, for example numeric text in an rtl context
182671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt        // in an ltr paragraph.
18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* package */ Directions(short[] dirs) {
18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDirections = dirs;
18299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the offset of the first character to be ellipsized away,
18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * relative to the start of the line.  (So 0 if the beginning of the
18359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * line is ellipsized, not getLineStart().)
18369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getEllipsisStart(int line);
18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the number of characters to be ellipsized away, or 0 if
18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * no ellipsis is to take place.
18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public abstract int getEllipsisCount(int line);
18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static class Ellipsizer implements CharSequence, GetChars {
18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* package */ CharSequence mText;
18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* package */ Layout mLayout;
18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* package */ int mWidth;
18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* package */ TextUtils.TruncateAt mMethod;
18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Ellipsizer(CharSequence s) {
18519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mText = s;
18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public char charAt(int off) {
18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char[] buf = TextUtils.obtain(1);
18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            getChars(off, off + 1, buf, 0);
18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char ret = buf[0];
18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            TextUtils.recycle(buf);
18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ret;
18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void getChars(int start, int end, char[] dest, int destoff) {
18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int line1 = mLayout.getLineForOffset(start);
18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int line2 = mLayout.getLineForOffset(end);
18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            TextUtils.getChars(mText, start, end, dest, destoff);
18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = line1; i <= line2; i++) {
18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLayout.ellipsize(start, end, i, dest, destoff);
18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int length() {
18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mText.length();
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public CharSequence subSequence(int start, int end) {
18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char[] s = new char[end - start];
18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            getChars(start, end, s, 0);
18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new String(s);
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char[] s = new char[length()];
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            getChars(0, length(), s, 0);
18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new String(s);
18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static class SpannedEllipsizer
18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    extends Ellipsizer implements Spanned {
18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Spanned mSpanned;
18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public SpannedEllipsizer(CharSequence display) {
18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(display);
18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSpanned = (Spanned) display;
18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public <T> T[] getSpans(int start, int end, Class<T> type) {
19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSpanned.getSpans(start, end, type);
19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getSpanStart(Object tag) {
19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSpanned.getSpanStart(tag);
19079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getSpanEnd(Object tag) {
19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSpanned.getSpanEnd(tag);
19119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getSpanFlags(Object tag) {
19149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSpanned.getSpanFlags(tag);
19159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int nextSpanTransition(int start, int limit, Class type) {
19189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSpanned.nextSpanTransition(start, limit, type);
19199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public CharSequence subSequence(int start, int end) {
19229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char[] s = new char[end - start];
19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            getChars(start, end, s, 0);
19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SpannableString ss = new SpannableString(new String(s));
19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            TextUtils.copySpansFrom(mSpanned, start, end, Object.class, ss, 0);
19279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ss;
19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private CharSequence mText;
19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private TextPaint mPaint;
19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ TextPaint mWorkPaint;
19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mWidth;
19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Alignment mAlignment = Alignment.ALIGN_NORMAL;
19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mSpacingMult;
19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mSpacingAdd;
19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Rect sTempRect = new Rect();
19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mSpannedText;
19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int DIR_LEFT_TO_RIGHT = 1;
19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int DIR_RIGHT_TO_LEFT = -1;
194320178d62cf669af18467a16d3c4c4237ed42151cDoug Felt
194420178d62cf669af18467a16d3c4c4237ed42151cDoug Felt    /* package */ static final int DIR_REQUEST_LTR = 1;
194520178d62cf669af18467a16d3c4c4237ed42151cDoug Felt    /* package */ static final int DIR_REQUEST_RTL = -1;
194620178d62cf669af18467a16d3c4c4237ed42151cDoug Felt    /* package */ static final int DIR_REQUEST_DEFAULT_LTR = 2;
194720178d62cf669af18467a16d3c4c4237ed42151cDoug Felt    /* package */ static final int DIR_REQUEST_DEFAULT_RTL = -2;
19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public enum Alignment {
19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ALIGN_NORMAL,
19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ALIGN_OPPOSITE,
19529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ALIGN_CENTER,
19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // XXX ALIGN_LEFT,
19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // XXX ALIGN_RIGHT,
19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAB_INCREMENT = 20;
19589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static final Directions DIRS_ALL_LEFT_TO_RIGHT =
19609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       new Directions(new short[] { 32767 });
19619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static final Directions DIRS_ALL_RIGHT_TO_LEFT =
19629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       new Directions(new short[] { 0, 32767 });
19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1965