Layout.java revision f75c97e023af7d4ad9a8c129d4ea282b1c3b8f94
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 199f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport com.android.internal.util.ArrayUtils; 209f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 21105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.emoji.EmojiFactory; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint; 249f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.graphics.Path; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.TextKeyListener; 279f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.AlignmentSpan; 289f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.LeadingMarginSpan; 29162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunneimport android.text.style.LeadingMarginSpan.LeadingMarginSpan2; 309f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.LineBackgroundSpan; 319f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.ParagraphStyle; 329f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.ReplacementSpan; 339f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.TabStopSpan; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 35c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Feltimport java.util.Arrays; 369f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 389f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt * A base class that manages text layout in visual elements on 399f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt * the screen. 409f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt * <p>For text that will be edited, use a {@link DynamicLayout}, 419f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt * which will be updated as the text changes. 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For text that will not change, use a {@link StaticLayout}. 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class Layout { 4571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt private static final ParagraphStyle[] NO_PARA_SPANS = 4671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt ArrayUtils.emptyArray(ParagraphStyle.class); 4776c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort 48105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project /* package */ static final EmojiFactory EMOJI_FACTORY = 49105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project EmojiFactory.newAvailableInstance(); 50105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project /* package */ static final int MIN_EMOJI, MAX_EMOJI; 51105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 52105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project static { 53105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (EMOJI_FACTORY != null) { 54105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project MIN_EMOJI = EMOJI_FACTORY.getMinimumAndroidPua(); 55105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project MAX_EMOJI = EMOJI_FACTORY.getMaximumAndroidPua(); 56105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } else { 57105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project MIN_EMOJI = -1; 58105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project MAX_EMOJI = -1; 59105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 60e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } 61c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return how wide a layout must be in order to display the 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * specified text with one line per paragraph. 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static float getDesiredWidth(CharSequence source, 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint paint) { 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getDesiredWidth(source, 0, source.length(), paint); 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 709f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return how wide a layout must be in order to display the 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * specified text slice with one line per paragraph. 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static float getDesiredWidth(CharSequence source, 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start, int end, 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint paint) { 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float need = 0; 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint workPaint = new TextPaint(); 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int next; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = start; i <= end; i = next) { 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project next = TextUtils.indexOf(source, '\n', i, end); 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (next < 0) 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project next = end; 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // note, omits trailing paragraph char 89c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt float w = measurePara(paint, workPaint, source, i, next); 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 119e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // Ensure paint doesn't have baselineShift set. 120e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // While normally we don't modify the paint the user passed in, 121e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // we were already doing this in Styled.drawUniformRun with both 122e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // baselineShift and bgColor. We probably should reevaluate bgColor. 123e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (paint != null) { 124e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt paint.bgColor = 0; 125e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt paint.baselineShift = 0; 126e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } 127e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mText = text; 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint = paint; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWorkPaint = new TextPaint(); 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWidth = width; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlignment = align; 13371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt mSpacingMult = spacingMult; 13471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt mSpacingAdd = spacingAdd; 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpannedText = text instanceof Spanned; 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Replace constructor properties of this Layout with new ones. Be careful. 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void replaceWith(CharSequence text, TextPaint paint, 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int width, Alignment align, 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float spacingmult, float spacingadd) { 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (width < 0) { 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Layout: " + width + " < 0"); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mText = text; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint = paint; 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWidth = width; 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlignment = align; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpacingMult = spacingmult; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpacingAdd = spacingadd; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpannedText = text instanceof Spanned; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Draw this Layout on the specified Canvas. 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void draw(Canvas c) { 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project draw(c, null, null, 0); 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Draw this Layout on the specified canvas, with the highlight path drawn 16671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * between the background and the text. 16771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * 16871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param c the canvas 16971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param highlight the path of the highlight or cursor; can be null 17071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param highlightPaint the paint for the highlight 17171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param cursorOffsetVertical the amount to temporarily translate the 17271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * canvas while rendering the highlight 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt public void draw(Canvas c, Path highlight, Paint highlightPaint, 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int cursorOffsetVertical) { 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dtop, dbottom; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (sTempRect) { 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!c.getClipBounds(sTempRect)) { 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dtop = sTempRect.top; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dbottom = sTempRect.bottom; 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top = 0; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottom = getLineTop(getLineCount()); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dtop > top) { 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top = dtop; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dbottom < bottom) { 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom = dbottom; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1969f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 1979f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int first = getLineForVertical(top); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int last = getLineForVertical(bottom); 1999f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int previousLineBottom = getLineTop(first); 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int previousLineEnd = getLineStart(first); 2029f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 20371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt TextPaint paint = mPaint; 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence buf = mText; 20571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt int width = mWidth; 20671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt boolean spannedText = mSpannedText; 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt ParagraphStyle[] spans = NO_PARA_SPANS; 209c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int spanEnd = 0; 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int textLength = 0; 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // First, draw LineBackgroundSpans. 2130c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt // LineBackgroundSpans know nothing about the alignment, margins, or 214c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // direction of the layout or line. XXX: Should they? 215c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // They are evaluated at each line. 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spannedText) { 217c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt Spanned sp = (Spanned) buf; 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project textLength = buf.length(); 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = first; i <= last; i++) { 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = previousLineEnd; 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = getLineStart(i+1); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineEnd = end; 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ltop = previousLineBottom; 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lbottom = getLineTop(i+1); 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineBottom = lbottom; 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lbaseline = lbottom - getLineDescent(i); 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 229c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (start >= spanEnd) { 230c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // These should be infrequent, so we'll use this so that 231c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // we don't have to check as often. 2320c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt spanEnd = sp.nextSpanTransition(start, textLength, 233c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt LineBackgroundSpan.class); 234c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // All LineBackgroundSpans on a line contribute to its 235c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // background. 23674d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer spans = getParagraphSpans(sp, start, end, LineBackgroundSpan.class); 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int n = 0; n < spans.length; n++) { 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LineBackgroundSpan back = (LineBackgroundSpan) spans[n]; 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt back.drawBackground(c, paint, 0, width, 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ltop, lbaseline, lbottom, 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project buf, start, end, 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i); 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // reset to their original values 249c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt spanEnd = 0; 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineBottom = getLineTop(first); 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineEnd = getLineStart(first); 25271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt spans = NO_PARA_SPANS; 2539f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // There can be a highlight even without spans if we are drawing 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // a non-spanned transformation of a spanned editing buffer. 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (highlight != null) { 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cursorOffsetVertical != 0) { 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.translate(0, cursorOffsetVertical); 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt c.drawPath(highlight, highlightPaint); 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cursorOffsetVertical != 0) { 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.translate(0, -cursorOffsetVertical); 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align = mAlignment; 270c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TabStops tabStops = null; 271c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt boolean tabStopsIsInitialized = false; 2729f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 273e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 274c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 27571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // Next draw the lines, one at a time. 27671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // the baseline is the top of the following line minus the current 27771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // line's descent. 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = first; i <= last; i++) { 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = previousLineEnd; 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineEnd = getLineStart(i+1); 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = getLineVisibleEnd(i, start, previousLineEnd); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ltop = previousLineBottom; 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lbottom = getLineTop(i+1); 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineBottom = lbottom; 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lbaseline = lbottom - getLineDescent(i); 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 289c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int dir = getParagraphDirection(i); 290c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int left = 0; 291c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int right = mWidth; 292c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 2939f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (spannedText) { 294c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt Spanned sp = (Spanned) buf; 295c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt boolean isFirstParaLine = (start == 0 || 296c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt buf.charAt(start - 1) == '\n'); 2970c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 298c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // New batch of paragraph styles, collect into spans array. 299c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // Compute the alignment, last alignment style wins. 300c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // Reset tabStops, we'll rebuild if we encounter a line with 301c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // tabs. 302c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // We expect paragraph spans to be relatively infrequent, use 303c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // spanEnd so that we can check less frequently. Since 304c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // paragraph styles ought to apply to entire paragraphs, we can 305c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // just collect the ones present at the start of the paragraph. 306c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // If spanEnd is before the end of the paragraph, that's not 307c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // our problem. 308c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (start >= spanEnd && (i == first || isFirstParaLine)) { 309c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt spanEnd = sp.nextSpanTransition(start, textLength, 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ParagraphStyle.class); 31174d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer spans = getParagraphSpans(sp, start, spanEnd, ParagraphStyle.class); 3129f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project align = mAlignment; 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int n = spans.length-1; n >= 0; n--) { 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spans[n] instanceof AlignmentSpan) { 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project align = ((AlignmentSpan) spans[n]).getAlignment(); 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3200c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 321c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tabStopsIsInitialized = false; 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3239f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 324c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // Draw all leading margin spans. Adjust left or right according 325c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // to the paragraph direction of the line. 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int length = spans.length; 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int n = 0; n < length; n++) { 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spans[n] instanceof LeadingMarginSpan) { 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LeadingMarginSpan margin = (LeadingMarginSpan) spans[n]; 330c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt boolean useFirstLineMargin = isFirstParaLine; 331c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (margin instanceof LeadingMarginSpan2) { 332c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int count = ((LeadingMarginSpan2) margin).getLeadingMarginLineCount(); 333c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int startLine = getLineForOffset(sp.getSpanStart(margin)); 334c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt useFirstLineMargin = i < startLine + count; 335c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) { 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project margin.drawLeadingMargin(c, paint, right, dir, ltop, 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lbaseline, lbottom, buf, 34071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt start, end, isFirstParaLine, this); 341c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt right -= margin.getLeadingMargin(useFirstLineMargin); 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project margin.drawLeadingMargin(c, paint, left, dir, ltop, 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lbaseline, lbottom, buf, 34571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt start, end, isFirstParaLine, this); 346c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt left += margin.getLeadingMargin(useFirstLineMargin); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 352c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt boolean hasTabOrEmoji = getLineContainsTab(i); 353c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // Can't tell if we have tabs for sure, currently 354c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (hasTabOrEmoji && !tabStopsIsInitialized) { 355c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (tabStops == null) { 356c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tabStops = new TabStops(TAB_INCREMENT, spans); 357c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } else { 358c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tabStops.reset(TAB_INCREMENT, spans); 359c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 360c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tabStopsIsInitialized = true; 361c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 362c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int x; 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_NORMAL) { 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_LEFT_TO_RIGHT) { 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = left; 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = right; 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 371c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int max = (int)getLineExtent(i, tabStops, false); 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_OPPOSITE) { 373c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (dir == DIR_LEFT_TO_RIGHT) { 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = right - max; 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 376c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt x = left - max; 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 378c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } else { // Alignment.ALIGN_CENTER 379c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt max = max & ~1; 380c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt x = (right + left - max) >> 1; 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Directions directions = getLineDirections(i); 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (directions == DIRS_ALL_LEFT_TO_RIGHT && 386c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt !spannedText && !hasTabOrEmoji) { 38771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // XXX: assumes there's nothing additional to be done 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.drawText(buf, start, end, x, lbaseline, paint); 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 390c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tl.set(paint, buf, start, end, dir, directions, hasTabOrEmoji, tabStops); 391e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl.draw(c, x, ltop, lbaseline, lbottom); 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 394c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 395e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine.recycle(tl); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 399c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * Return the start position of the line, given the left and right bounds 400c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * of the margins. 4010c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt * 402c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @param line the line index 403c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @param left the left bounds (0, or leading margin if ltr para) 404c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @param right the right bounds (width, minus leading margin if rtl para) 405c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @return the start position of the line (to right of line if rtl para) 406c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt */ 407c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt private int getLineStartPos(int line, int left, int right) { 408c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // Adjust the point at which to start rendering depending on the 409c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // alignment of the paragraph. 410c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt Alignment align = getParagraphAlignment(line); 411c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int dir = getParagraphDirection(line); 412c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 413c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int x; 414c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (align == Alignment.ALIGN_NORMAL) { 415c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (dir == DIR_LEFT_TO_RIGHT) { 416c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt x = left; 417c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } else { 418c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt x = right; 419c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 420c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } else { 421c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TabStops tabStops = null; 422c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (mSpannedText && getLineContainsTab(line)) { 423c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt Spanned spanned = (Spanned) mText; 424c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int start = getLineStart(line); 425c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int spanEnd = spanned.nextSpanTransition(start, spanned.length(), 426c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TabStopSpan.class); 42774d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer TabStopSpan[] tabSpans = getParagraphSpans(spanned, start, spanEnd, TabStopSpan.class); 428c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (tabSpans.length > 0) { 429c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tabStops = new TabStops(TAB_INCREMENT, tabSpans); 430c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 431c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 432c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int max = (int)getLineExtent(line, tabStops, false); 433c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (align == Alignment.ALIGN_OPPOSITE) { 434c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (dir == DIR_LEFT_TO_RIGHT) { 435c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt x = right - max; 436c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } else { 437c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt x = left - max; 438c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 439c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } else { // Alignment.ALIGN_CENTER 440c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt max = max & ~1; 441c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt x = (left + right - max) >> 1; 442c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 443c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 444c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return x; 445c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 446c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 447c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt /** 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the text that is displayed by this Layout. 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final CharSequence getText() { 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mText; 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the base Paint properties for this layout. 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Do NOT change the paint, which may result in funny 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * drawing for this layout. 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final TextPaint getPaint() { 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPaint; 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the width of this layout. 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getWidth() { 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth; 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the width to which this Layout is ellipsizing, or 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #getWidth} if it is not doing anything special. 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getEllipsizedWidth() { 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth; 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Increase the width of this layout to the specified width. 48071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Be careful to use this only when you know it is appropriate— 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * it does not cause the text to reflow to use the full new width. 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final void increaseWidthTo(int wid) { 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (wid < mWidth) { 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new RuntimeException("attempted to reduce Layout width"); 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWidth = wid; 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4909f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the total height of this layout. 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getHeight() { 49571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt return getLineTop(getLineCount()); 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the base alignment of this layout. 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final Alignment getAlignment() { 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mAlignment; 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return what the text height is multiplied by to get the line height. 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final float getSpacingMultiplier() { 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpacingMult; 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the number of units of leading that are added to each line. 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final float getSpacingAdd() { 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpacingAdd; 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the number of lines of text in this layout. 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getLineCount(); 5239f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the baseline for the specified line (0…getLineCount() - 1) 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If bounds is not null, return the top, left, right, bottom extents 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of the specified line in it. 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param line which line to examine (0..getLineCount() - 1) 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param bounds Optional. If not null, it returns the extent of the line 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the Y-coordinate of the baseline 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineBounds(int line, Rect bounds) { 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bounds != null) { 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bounds.left = 0; // ??? 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bounds.top = getLineTop(line); 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bounds.right = mWidth; // ??? 53771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt bounds.bottom = getLineTop(line + 1); 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineBaseline(line); 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 54371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return the vertical position of the top of the specified line 54471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * (0…getLineCount()). 54571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * If the specified line is equal to the line count, returns the 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * bottom of the last line. 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getLineTop(int line); 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 55171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return the descent of the specified line(0…getLineCount() - 1). 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getLineDescent(int line); 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 55671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return the text offset of the beginning of the specified line ( 55771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * 0…getLineCount()). If the specified line is equal to the line 55871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * count, returns the length of the text. 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getLineStart(int line); 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 56371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Returns the primary directionality of the paragraph containing the 56471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * specified line, either 1 for left-to-right lines, or -1 for right-to-left 56571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * lines (see {@link #DIR_LEFT_TO_RIGHT}, {@link #DIR_RIGHT_TO_LEFT}). 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getParagraphDirection(int line); 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 570105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * Returns whether the specified line contains one or more 571105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * characters that need to be handled specially, like tabs 572105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * or emoji. 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract boolean getLineContainsTab(int line); 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 57771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Returns the directional run information for the specified line. 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The array alternates counts of characters in left-to-right 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and right-to-left segments of the line. 58071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * 58171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * <p>NOTE: this is inadequate to support bidirectional text, and will change. 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract Directions getLineDirections(int line); 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the (negative) number of extra pixels of ascent padding in the 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * top line of the Layout. 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getTopPadding(); 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of extra pixels of descent padding in the 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * bottom line of the Layout. 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getBottomPadding(); 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5974e0c5e55e171532760d5f51e0165563827129d4eDoug Felt 5984e0c5e55e171532760d5f51e0165563827129d4eDoug Felt /** 5994e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * Returns true if the character at offset and the preceding character 6004e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * are at different run levels (and thus there's a split caret). 6014e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * @param offset the offset 6024e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * @return true if at a level boundary 603f75c97e023af7d4ad9a8c129d4ea282b1c3b8f94Gilles Debunne * @hide 6044e0c5e55e171532760d5f51e0165563827129d4eDoug Felt */ 605f75c97e023af7d4ad9a8c129d4ea282b1c3b8f94Gilles Debunne public boolean isLevelBoundary(int offset) { 6069f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int line = getLineForOffset(offset); 6074e0c5e55e171532760d5f51e0165563827129d4eDoug Felt Directions dirs = getLineDirections(line); 6084e0c5e55e171532760d5f51e0165563827129d4eDoug Felt if (dirs == DIRS_ALL_LEFT_TO_RIGHT || dirs == DIRS_ALL_RIGHT_TO_LEFT) { 6094e0c5e55e171532760d5f51e0165563827129d4eDoug Felt return false; 6104e0c5e55e171532760d5f51e0165563827129d4eDoug Felt } 6114e0c5e55e171532760d5f51e0165563827129d4eDoug Felt 6124e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int[] runs = dirs.mDirections; 6139f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int lineStart = getLineStart(line); 6144e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int lineEnd = getLineEnd(line); 6154e0c5e55e171532760d5f51e0165563827129d4eDoug Felt if (offset == lineStart || offset == lineEnd) { 6164e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int paraLevel = getParagraphDirection(line) == 1 ? 0 : 1; 6174e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int runIndex = offset == lineStart ? 0 : runs.length - 2; 6184e0c5e55e171532760d5f51e0165563827129d4eDoug Felt return ((runs[runIndex + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK) != paraLevel; 6194e0c5e55e171532760d5f51e0165563827129d4eDoug Felt } 6204e0c5e55e171532760d5f51e0165563827129d4eDoug Felt 6214e0c5e55e171532760d5f51e0165563827129d4eDoug Felt offset -= lineStart; 6229f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < runs.length; i += 2) { 6234e0c5e55e171532760d5f51e0165563827129d4eDoug Felt if (offset == runs[i]) { 6244e0c5e55e171532760d5f51e0165563827129d4eDoug Felt return true; 6259f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6269f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6274e0c5e55e171532760d5f51e0165563827129d4eDoug Felt return false; 6289f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6299f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 6309f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt private boolean primaryIsTrailingPrevious(int offset) { 6319f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int line = getLineForOffset(offset); 6329f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int lineStart = getLineStart(line); 6334e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int lineEnd = getLineEnd(line); 6349f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int[] runs = getLineDirections(line).mDirections; 6359f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 6369f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int levelAt = -1; 6379f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < runs.length; i += 2) { 6389f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int start = lineStart + runs[i]; 6399f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int limit = start + (runs[i+1] & RUN_LENGTH_MASK); 6409f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (limit > lineEnd) { 6419f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt limit = lineEnd; 6429f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6439f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (offset >= start && offset < limit) { 6449f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (offset > start) { 6459f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // Previous character is at same level, so don't use trailing. 6469f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return false; 6479f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6489f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt levelAt = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK; 6499f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt break; 6509f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6519f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6529f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (levelAt == -1) { 6539f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // Offset was limit of line. 6549f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt levelAt = getParagraphDirection(line) == 1 ? 0 : 1; 6559f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6569f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 6579f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // At level boundary, check previous level. 6589f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int levelBefore = -1; 6599f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (offset == lineStart) { 6609f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt levelBefore = getParagraphDirection(line) == 1 ? 0 : 1; 6619f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } else { 6629f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt offset -= 1; 6639f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < runs.length; i += 2) { 6649f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int start = lineStart + runs[i]; 6659f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int limit = start + (runs[i+1] & RUN_LENGTH_MASK); 6669f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (limit > lineEnd) { 6679f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt limit = lineEnd; 6689f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6699f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (offset >= start && offset < limit) { 6709f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt levelBefore = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK; 6719f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt break; 6729f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6739f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6749f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6759f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 6769f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return levelBefore < levelAt; 6779f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6789f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the primary horizontal position for the specified text offset. 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is the location where a new character would be inserted in 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the paragraph's primary direction. 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getPrimaryHorizontal(int offset) { 6859f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt boolean trailing = primaryIsTrailingPrevious(offset); 6869f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getHorizontal(offset, trailing); 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the secondary horizontal position for the specified text offset. 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is the location where a new character would be inserted in 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the direction other than the paragraph's primary direction. 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getSecondaryHorizontal(int offset) { 6959f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt boolean trailing = primaryIsTrailingPrevious(offset); 6969f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getHorizontal(offset, !trailing); 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6999f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt private float getHorizontal(int offset, boolean trailing) { 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int line = getLineForOffset(offset); 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7029f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getHorizontal(offset, trailing, line); 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7059f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt private float getHorizontal(int offset, boolean trailing, int line) { 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = getLineStart(line); 707e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int end = getLineEnd(line); 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dir = getParagraphDirection(line); 709c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt boolean hasTabOrEmoji = getLineContainsTab(line); 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Directions directions = getLineDirections(line); 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 712c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TabStops tabStops = null; 713c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (hasTabOrEmoji && mText instanceof Spanned) { 714c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // Just checking this line should be good enough, tabs should be 715c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // consistent across all lines in a paragraph. 71674d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class); 717c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (tabs.length > 0) { 718c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse 719c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 722e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 723c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tl.set(mPaint, mText, start, end, dir, directions, hasTabOrEmoji, tabStops); 724e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt float wid = tl.measure(offset - start, trailing, null); 725e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine.recycle(tl); 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = getParagraphLeft(line); 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int right = getParagraphRight(line); 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 730c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return getLineStartPos(line, left, right) + wid; 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the leftmost position that should be exposed for horizontal 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * scrolling on the specified line. 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getLineLeft(int line) { 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dir = getParagraphDirection(line); 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align = getParagraphAlignment(line); 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_NORMAL) { 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getParagraphRight(line) - getLineMax(line); 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (align == Alignment.ALIGN_OPPOSITE) { 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth - getLineMax(line); 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { /* align == Alignment.ALIGN_CENTER */ 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = getParagraphLeft(line); 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int right = getParagraphRight(line); 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int max = ((int) getLineMax(line)) & ~1; 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return left + ((right - left) - max) / 2; 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the rightmost position that should be exposed for horizontal 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * scrolling on the specified line. 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getLineRight(int line) { 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dir = getParagraphDirection(line); 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align = getParagraphAlignment(line); 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_NORMAL) { 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth; 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getParagraphLeft(line) + getLineMax(line); 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (align == Alignment.ALIGN_OPPOSITE) { 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineMax(line); 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth; 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { /* align == Alignment.ALIGN_CENTER */ 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = getParagraphLeft(line); 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int right = getParagraphRight(line); 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int max = ((int) getLineMax(line)) & ~1; 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return right - ((right - left) - max) / 2; 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7880c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt * Gets the unsigned horizontal extent of the specified line, including 789c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * leading margin indent, but excluding trailing whitespace. 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getLineMax(int line) { 792c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt float margin = getParagraphLeadingMargin(line); 793c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt float signedExtent = getLineExtent(line, false); 794c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return margin + signedExtent >= 0 ? signedExtent : -signedExtent; 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 798c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * Gets the unsigned horizontal extent of the specified line, including 799c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * leading margin indent and trailing whitespace. 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getLineWidth(int line) { 802c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt float margin = getParagraphLeadingMargin(line); 803c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt float signedExtent = getLineExtent(line, true); 804c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return margin + signedExtent >= 0 ? signedExtent : -signedExtent; 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 807c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt /** 808c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * Like {@link #getLineExtent(int,TabStops,boolean)} but determines the 809c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * tab stops instead of using the ones passed in. 810c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @param line the index of the line 811c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @param full whether to include trailing whitespace 812c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @return the extent of the line 813c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt */ 814c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt private float getLineExtent(int line, boolean full) { 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = getLineStart(line); 816e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int end = full ? getLineEnd(line) : getLineVisibleEnd(line); 817c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 818c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt boolean hasTabsOrEmoji = getLineContainsTab(line); 819c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TabStops tabStops = null; 820c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (hasTabsOrEmoji && mText instanceof Spanned) { 821c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // Just checking this line should be good enough, tabs should be 822c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // consistent across all lines in a paragraph. 82374d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class); 824c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (tabs.length > 0) { 825c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse 826c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 827c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 828c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt Directions directions = getLineDirections(line); 829c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int dir = getParagraphDirection(line); 830c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 831c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TextLine tl = TextLine.obtain(); 832c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops); 833c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt float width = tl.metrics(null); 834c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TextLine.recycle(tl); 835c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return width; 836c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 837c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 838c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt /** 839c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * Returns the signed horizontal extent of the specified line, excluding 840c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * leading margin. If full is false, excludes trailing whitespace. 841c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @param line the index of the line 842c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @param tabStops the tab stops, can be null if we know they're not used. 843c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @param full whether to include trailing whitespace 844c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @return the extent of the text on this line 845c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt */ 846c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt private float getLineExtent(int line, TabStops tabStops, boolean full) { 847c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int start = getLineStart(line); 848c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int end = full ? getLineEnd(line) : getLineVisibleEnd(line); 849c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt boolean hasTabsOrEmoji = getLineContainsTab(line); 850e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt Directions directions = getLineDirections(line); 851c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int dir = getParagraphDirection(line); 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 853e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 854c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tl.set(mPaint, mText, start, end, dir, directions, hasTabsOrEmoji, tabStops); 855e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt float width = tl.metrics(null); 856e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine.recycle(tl); 857e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt return width; 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the line number corresponding to the specified vertical position. 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If you ask for a position above 0, you get 0; if you ask for a position 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * below the bottom of the text, you get the last line. 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // FIXME: It may be faster to do a linear search for layouts without many lines. 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineForVertical(int vertical) { 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int high = getLineCount(), low = -1, guess; 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (high - low > 1) { 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project guess = (high + low) / 2; 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getLineTop(guess) > vertical) 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project high = guess; 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = guess; 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < 0) 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return low; 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the line number on which the specified text offset appears. 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If you ask for a position before 0, you get 0; if you ask for a position 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * beyond the end of the text, you get the last line. 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineForOffset(int offset) { 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int high = getLineCount(), low = -1, guess; 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (high - low > 1) { 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project guess = (high + low) / 2; 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getLineStart(guess) > offset) 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project high = guess; 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = guess; 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < 0) 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return low; 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9089f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt * Get the character offset on the specified line whose position is 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * closest to the specified horizontal position. 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getOffsetForHorizontal(int line, float horiz) { 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int max = getLineEnd(line) - 1; 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int min = getLineStart(line); 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Directions dirs = getLineDirections(line); 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line == getLineCount() - 1) 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project max++; 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int best = min; 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9229f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < dirs.mDirections.length; i += 2) { 9239f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int here = min + dirs.mDirections[i]; 9249f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK); 9259f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int swap = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0 ? -1 : 1; 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (there > max) 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project there = max; 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int high = there - 1 + 1, low = here + 1 - 1, guess; 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (high - low > 1) { 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project guess = (high + low) / 2; 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int adguess = getOffsetAtStartOf(guess); 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getPrimaryHorizontal(adguess) * swap >= horiz * swap) 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project high = guess; 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = guess; 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < here + 1) 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = here + 1; 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < there) { 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = getOffsetAtStartOf(low); 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float dist = Math.abs(getPrimaryHorizontal(low) - horiz); 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int aft = TextUtils.getOffsetAfter(mText, low); 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (aft < there) { 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float other = Math.abs(getPrimaryHorizontal(aft) - horiz); 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (other < dist) { 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dist = other; 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = aft; 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dist < bestdist) { 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bestdist = dist; 9619f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt best = low; 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float dist = Math.abs(getPrimaryHorizontal(here) - horiz); 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dist < bestdist) { 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bestdist = dist; 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project best = here; 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float dist = Math.abs(getPrimaryHorizontal(max) - horiz); 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dist < bestdist) { 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bestdist = dist; 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project best = max; 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return best; 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the text offset after the last character on the specified line. 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getLineEnd(int line) { 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineStart(line + 1); 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9909f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /** 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the text offset after the last visible character (so whitespace 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is not counted) on the specified line. 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineVisibleEnd(int line) { 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineVisibleEnd(line, getLineStart(line), getLineStart(line+1)); 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9979f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getLineVisibleEnd(int line, int start, int end) { 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence text = mText; 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ch; 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line == getLineCount() - 1) { 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return end; 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (; end > start; end--) { 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ch = text.charAt(end - 1); 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch == '\n') { 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return end - 1; 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch != ' ' && ch != '\t') { 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return end; 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the vertical position of the bottom of the specified line. 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getLineBottom(int line) { 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineTop(line + 1); 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the vertical position of the baseline of the specified line. 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getLineBaseline(int line) { 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // getLineTop(line+1) == getLineTop(line) 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineTop(line+1) - getLineDescent(line); 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the ascent of the text on the specified line. 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The return value is negative to match the Paint.ascent() convention. 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getLineAscent(int line) { 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // getLineTop(line+1) - getLineDescent(line) == getLineBaseLine(line) 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineTop(line) - (getLineTop(line+1) - getLineDescent(line)); 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getOffsetToLeftOf(int offset) { 10469f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getOffsetToLeftRightOf(offset, true); 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getOffsetToRightOf(int offset) { 10509f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getOffsetToLeftRightOf(offset, false); 10519f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10539f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt private int getOffsetToLeftRightOf(int caret, boolean toLeft) { 10549f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int line = getLineForOffset(caret); 10559f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int lineStart = getLineStart(line); 10569f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int lineEnd = getLineEnd(line); 1057e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int lineDir = getParagraphDirection(line); 1058e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 1059162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne boolean lineChanged = false; 1060e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt boolean advance = toLeft == (lineDir == DIR_RIGHT_TO_LEFT); 1061162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne // if walking off line, look at the line we're headed to 1062162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne if (advance) { 1063162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne if (caret == lineEnd) { 1064162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne if (line < getLineCount() - 1) { 1065162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne lineChanged = true; 1066162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne ++line; 1067162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne } else { 1068162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne return caret; // at very end, don't move 1069162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne } 1070162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne } 1071162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne } else { 1072e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (caret == lineStart) { 1073e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (line > 0) { 1074162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne lineChanged = true; 1075e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt --line; 1076e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } else { 1077e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt return caret; // at very start, don't move 1078e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1080162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne } 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1082162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne if (lineChanged) { 1083e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt lineStart = getLineStart(line); 1084e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt lineEnd = getLineEnd(line); 1085e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int newDir = getParagraphDirection(line); 1086e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (newDir != lineDir) { 1087e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // unusual case. we want to walk onto the line, but it runs 1088e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // in a different direction than this one, so we fake movement 1089e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // in the opposite direction. 1090e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt toLeft = !toLeft; 1091e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt lineDir = newDir; 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10939f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 10949f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 1095e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt Directions directions = getLineDirections(line); 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1097e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 1098e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // XXX: we don't care about tabs 1099e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl.set(mPaint, mText, lineStart, lineEnd, lineDir, directions, false, null); 1100e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt caret = lineStart + tl.getOffsetToLeftRightOf(caret - lineStart, toLeft); 1101e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl = TextLine.recycle(tl); 1102e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt return caret; 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getOffsetAtStartOf(int offset) { 11069f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // XXX this probably should skip local reorderings and 11079f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // zero-width characters, look at callers 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (offset == 0) 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence text = mText; 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = text.charAt(offset); 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c >= '\uDC00' && c <= '\uDFFF') { 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c1 = text.charAt(offset - 1); 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c1 >= '\uD800' && c1 <= '\uDBFF') 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset -= 1; 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSpannedText) { 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset, 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ReplacementSpan.class); 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < spans.length; i++) { 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = ((Spanned) text).getSpanStart(spans[i]); 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = ((Spanned) text).getSpanEnd(spans[i]); 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start < offset && end > offset) 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset = start; 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return offset; 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Fills in the specified Path with a representation of a cursor 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * at the specified offset. This will often be a vertical line 11404e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * but can be multiple discontinuous lines in text with multiple 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * directionalities. 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void getCursorPath(int point, Path dest, 11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence editingBuffer) { 11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.reset(); 11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int line = getLineForOffset(point); 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top = getLineTop(line); 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottom = getLineTop(line+1); 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float h1 = getPrimaryHorizontal(point) - 0.5f; 1152f75c97e023af7d4ad9a8c129d4ea282b1c3b8f94Gilles Debunne float h2 = isLevelBoundary(point) ? getSecondaryHorizontal(point) - 0.5f : h1; 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1154497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown int caps = TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SHIFT_ON) | 1155497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SELECTING); 1156497a92cc5ba2176b8a8484b0a7da040eac0e887bJeff Brown int fn = TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_ALT_ON); 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dist = 0; 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (caps != 0 || fn != 0) { 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dist = (bottom - top) >> 2; 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fn != 0) 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top += dist; 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (caps != 0) 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom -= dist; 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (h1 < 0.5f) 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project h1 = 0.5f; 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (h2 < 0.5f) 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project h2 = 0.5f; 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (h1 == h2) { 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1, top); 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1, bottom); 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1, top); 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1, (top + bottom) >> 1); 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2, (top + bottom) >> 1); 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 (caps == 2) { 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2, bottom); 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2 - dist, bottom + dist); 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2, bottom); 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2 + dist, bottom + dist); 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (caps == 1) { 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2, bottom); 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2 - dist, bottom + dist); 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2 - dist, bottom + dist - 0.5f); 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2 + dist, bottom + dist - 0.5f); 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2 + dist, bottom + dist); 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2, bottom); 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fn == 2) { 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1, top); 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1 - dist, top - dist); 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1, top); 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1 + dist, top - dist); 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (fn == 1) { 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1, top); 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1 - dist, top - dist); 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1 - dist, top - dist + 0.5f); 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1 + dist, top - dist + 0.5f); 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1 + dist, top - dist); 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1, top); 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void addSelection(int line, int start, int end, 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top, int bottom, Path dest) { 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int linestart = getLineStart(line); 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lineend = getLineEnd(line); 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Directions dirs = getLineDirections(line); 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lineend > linestart && mText.charAt(lineend - 1) == '\n') 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lineend--; 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12269f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < dirs.mDirections.length; i += 2) { 12279f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int here = linestart + dirs.mDirections[i]; 12289f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK); 12299f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (there > lineend) 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project there = lineend; 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start <= there && end >= here) { 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int st = Math.max(start, here); 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int en = Math.min(end, there); 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (st != en) { 12389f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt float h1 = getHorizontal(st, false, line); 12399f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt float h2 = getHorizontal(en, true, line); 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(h1, top, h2, bottom, Path.Direction.CW); 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Fills in the specified Path with a representation of a highlight 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * between the specified offsets. This will often be a rectangle 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or a potentially discontinuous set of rectangles. If the start 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and end are the same, the returned path is empty. 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void getSelectionPath(int start, int end, Path dest) { 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.reset(); 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start == end) 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end < start) { 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int temp = end; 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end = start; 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start = temp; 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int startline = getLineForOffset(start); 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int endline = getLineForOffset(end); 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top = getLineTop(startline); 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottom = getLineBottom(endline); 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (startline == endline) { 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addSelection(startline, start, end, top, bottom, dest); 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float width = mWidth; 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addSelection(startline, start, getLineEnd(startline), 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top, getLineBottom(startline), dest); 12789f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT) 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(getLineLeft(startline), top, 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 0, getLineBottom(startline), Path.Direction.CW); 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(getLineRight(startline), top, 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project width, getLineBottom(startline), Path.Direction.CW); 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = startline + 1; i < endline; i++) { 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top = getLineTop(i); 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom = getLineBottom(i); 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(0, top, width, bottom, Path.Direction.CW); 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top = getLineTop(endline); 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom = getLineBottom(endline); 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addSelection(endline, getLineStart(endline), end, 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top, bottom, dest); 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT) 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(width, top, getLineRight(endline), bottom, Path.Direction.CW); 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(0, top, getLineLeft(endline), bottom, Path.Direction.CW); 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the alignment of the specified paragraph, taking into account 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * markup attached to it. 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final Alignment getParagraphAlignment(int line) { 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align = mAlignment; 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSpannedText) { 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned sp = (Spanned) mText; 131474d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer AlignmentSpan[] spans = getParagraphSpans(sp, getLineStart(line), 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getLineEnd(line), 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AlignmentSpan.class); 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spanLength = spans.length; 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanLength > 0) { 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project align = spans[spanLength-1].getAlignment(); 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return align; 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the left edge of the specified paragraph, inset by left margins. 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getParagraphLeft(int line) { 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = 0; 1332c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int dir = getParagraphDirection(line); 1333c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (dir == DIR_RIGHT_TO_LEFT || !mSpannedText) { 1334c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return left; // leading margin has no impact, or no styles 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1336c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return getParagraphLeadingMargin(line); 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the right edge of the specified paragraph, inset by right margins. 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getParagraphRight(int line) { 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int right = mWidth; 1344c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int dir = getParagraphDirection(line); 1345c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (dir == DIR_LEFT_TO_RIGHT || !mSpannedText) { 1346c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return right; // leading margin has no impact, or no styles 1347c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1348c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return right - getParagraphLeadingMargin(line); 1349c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1351c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt /** 1352c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * Returns the effective leading margin (unsigned) for this line, 1353c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * taking into account LeadingMarginSpan and LeadingMarginSpan2. 1354c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @param line the line index 1355c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @return the leading margin of this line 1356c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt */ 1357c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt private int getParagraphLeadingMargin(int line) { 1358c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (!mSpannedText) { 1359c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return 0; 1360c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1361c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt Spanned spanned = (Spanned) mText; 13620c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 1363c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int lineStart = getLineStart(line); 1364c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int lineEnd = getLineEnd(line); 13650c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt int spanEnd = spanned.nextSpanTransition(lineStart, lineEnd, 1366c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt LeadingMarginSpan.class); 136774d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer LeadingMarginSpan[] spans = getParagraphSpans(spanned, lineStart, spanEnd, 1368c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt LeadingMarginSpan.class); 1369c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (spans.length == 0) { 1370c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return 0; // no leading margin span; 1371c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 13720c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 1373c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int margin = 0; 13740c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 13750c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt boolean isFirstParaLine = lineStart == 0 || 1376c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt spanned.charAt(lineStart - 1) == '\n'; 13770c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 1378c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt for (int i = 0; i < spans.length; i++) { 1379c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt LeadingMarginSpan span = spans[i]; 1380c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt boolean useFirstLineMargin = isFirstParaLine; 1381c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (span instanceof LeadingMarginSpan2) { 1382c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int spStart = spanned.getSpanStart(span); 1383c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int spanLine = getLineForOffset(spStart); 1384c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int count = ((LeadingMarginSpan2)span).getLeadingMarginLineCount(); 13850c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt useFirstLineMargin = line < spanLine + count; 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1387c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt margin += span.getLeadingMargin(useFirstLineMargin); 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1390c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return margin; 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1393e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt /* package */ 1394e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt static float measurePara(TextPaint paint, TextPaint workPaint, 1395c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt CharSequence text, int start, int end) { 1396e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 1397e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt MeasuredText mt = MeasuredText.obtain(); 1398e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 1399e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt try { 1400e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt mt.setPara(text, start, end, DIR_REQUEST_LTR); 1401e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt Directions directions; 1402c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int dir; 1403c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (mt.mEasy) { 1404e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt directions = DIRS_ALL_LEFT_TO_RIGHT; 1405c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt dir = Layout.DIR_LEFT_TO_RIGHT; 1406e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } else { 1407e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt directions = AndroidBidi.directions(mt.mDir, mt.mLevels, 1408e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 0, mt.mChars, 0, mt.mLen); 1409c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt dir = mt.mDir; 1410c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1411c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt char[] chars = mt.mChars; 1412c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int len = mt.mLen; 1413c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt boolean hasTabs = false; 1414c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TabStops tabStops = null; 1415c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt for (int i = 0; i < len; ++i) { 1416c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (chars[i] == '\t') { 1417c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt hasTabs = true; 1418c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (text instanceof Spanned) { 1419c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt Spanned spanned = (Spanned) text; 14200c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt int spanEnd = spanned.nextSpanTransition(start, end, 1421c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TabStopSpan.class); 142274d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer TabStopSpan[] spans = getParagraphSpans(spanned, start, spanEnd, 1423c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TabStopSpan.class); 1424c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (spans.length > 0) { 1425c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tabStops = new TabStops(TAB_INCREMENT, spans); 1426c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1427c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1428c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt break; 1429c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1431c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops); 1432e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt return tl.metrics(null); 1433e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } finally { 1434e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine.recycle(tl); 1435e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt MeasuredText.recycle(mt); 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 143971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt /** 1440c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt * @hide 1441c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt */ 1442c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt /* package */ static class TabStops { 1443c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt private int[] mStops; 1444c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt private int mNumStops; 1445c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt private int mIncrement; 14460c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 1447c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt TabStops(int increment, Object[] spans) { 1448c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt reset(increment, spans); 1449c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 14500c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 1451c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt void reset(int increment, Object[] spans) { 1452c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt this.mIncrement = increment; 1453c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 1454c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int ns = 0; 1455c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (spans != null) { 1456c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int[] stops = this.mStops; 1457c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt for (Object o : spans) { 1458c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (o instanceof TabStopSpan) { 1459c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (stops == null) { 1460c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt stops = new int[10]; 1461c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } else if (ns == stops.length) { 1462c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int[] nstops = new int[ns * 2]; 1463c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt for (int i = 0; i < ns; ++i) { 1464c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt nstops[i] = stops[i]; 1465c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1466c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt stops = nstops; 1467c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1468c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt stops[ns++] = ((TabStopSpan) o).getTabStop(); 1469c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1470c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1471c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (ns > 1) { 1472c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt Arrays.sort(stops, 0, ns); 1473c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1474c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (stops != this.mStops) { 1475c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt this.mStops = stops; 1476c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1477c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1478c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt this.mNumStops = ns; 1479c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 14800c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 1481c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt float nextTab(float h) { 1482c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int ns = this.mNumStops; 1483c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (ns > 0) { 1484c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int[] stops = this.mStops; 1485c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt for (int i = 0; i < ns; ++i) { 1486c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt int stop = stops[i]; 1487c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (stop > h) { 1488c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return stop; 1489c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1490c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1491c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1492c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return nextDefaultStop(h, mIncrement); 1493c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1494c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt 1495c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt public static float nextDefaultStop(float h, int inc) { 1496c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt return ((int) ((h + inc) / inc)) * inc; 1497c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 1498c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt } 14990c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 1500c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt /** 150171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Returns the position of the next tab stop after h on the line. 150271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * 150371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param text the text 150471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param start start of the line 150571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param end limit of the line 150671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param h the current horizontal offset 150771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param tabs the tabs, can be null. If it is null, any tabs in effect 150871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * on the line will be used. If there are no tabs, a default offset 150971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * will be used to compute the tab stop. 151071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @return the offset of the next tab stop. 151171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt */ 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static float nextTab(CharSequence text, int start, int end, 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float h, Object[] tabs) { 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float nh = Float.MAX_VALUE; 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean alltabs = false; 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (text instanceof Spanned) { 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (tabs == null) { 151974d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer tabs = getParagraphSpans((Spanned) text, start, end, TabStopSpan.class); 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project alltabs = true; 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < tabs.length; i++) { 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!alltabs) { 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!(tabs[i] instanceof TabStopSpan)) 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int where = ((TabStopSpan) tabs[i]).getTabStop(); 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where < nh && where > h) 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nh = where; 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nh != Float.MAX_VALUE) 15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return nh; 15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ((int) ((h + TAB_INCREMENT) / TAB_INCREMENT)) * TAB_INCREMENT; 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected final boolean isSpanned() { 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpannedText; 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 154674d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer /** 154774d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * Returns the same as <code>text.getSpans()</code>, except where 154874d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * <code>start</code> and <code>end</code> are the same and are not 154974d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * at the very beginning of the text, in which case an empty array 155074d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * is returned instead. 155174d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * <p> 155274d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * This is needed because of the special case that <code>getSpans()</code> 155374d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * on an empty range returns the spans adjacent to that range, which is 155474d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * primarily for the sake of <code>TextWatchers</code> so they will get 155574d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * notifications when text goes from empty to non-empty. But it also 155674d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * has the unfortunate side effect that if the text ends with an empty 155774d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * paragraph, that paragraph accidentally picks up the styles of the 155874d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * preceding paragraph (even though those styles will not be picked up 155974d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * by new text that is inserted into the empty paragraph). 156074d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * <p> 156174d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * The reason it just checks whether <code>start</code> and <code>end</code> 156274d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * is the same is that the only time a line can contain 0 characters 156374d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * is if it is the final paragraph of the Layout; otherwise any line will 156474d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * contain at least one printing or newline character. The reason for the 156574d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * additional check if <code>start</code> is greater than 0 is that 156674d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * if the empty paragraph is the entire content of the buffer, paragraph 156774d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * styles that are already applied to the buffer will apply to text that 156874d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer * is inserted into it. 156974d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer */ 157074d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer /* package */ static <T> T[] getParagraphSpans(Spanned text, int start, int end, Class<T> type) { 157174d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer if (start == end && start > 0) { 157274d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer return (T[]) ArrayUtils.emptyArray(type); 157374d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer } 157474d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer 157574d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer return text.getSpans(start, end, type); 157674d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer } 157774d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer 15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void ellipsize(int start, int end, int line, 15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] dest, int destoff) { 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ellipsisCount = getEllipsisCount(line); 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ellipsisCount == 0) { 15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ellipsisStart = getEllipsisStart(line); 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int linestart = getLineStart(line); 15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = ellipsisStart; i < ellipsisStart + ellipsisCount; i++) { 15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c; 15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i == ellipsisStart) { 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = '\u2026'; // ellipsis 15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = '\uFEFF'; // 0-width space 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int a = i + linestart; 15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (a >= start && a < end) { 16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest[destoff + a - start] = c; 16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stores information about bidirectional (left-to-right or right-to-left) 16089f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt * text within the layout of a line. 16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static class Directions { 16119f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // Directions represents directional runs within a line of text. 16129f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // Runs are pairs of ints listed in visual order, starting from the 16139f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // leading margin. The first int of each pair is the offset from 16149f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // the first character of the line to the start of the run. The 16159f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // second int represents both the length and level of the run. 16169f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // The length is in the lower bits, accessed by masking with 16179f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // DIR_LENGTH_MASK. The level is in the higher bits, accessed 16189f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // by shifting by DIR_LEVEL_SHIFT and masking by DIR_LEVEL_MASK. 16199f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // To simply test for an RTL direction, test the bit using 16209f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // DIR_RTL_FLAG, if set then the direction is rtl. 16219f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 16229f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ int[] mDirections; 16239f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ Directions(int[] dirs) { 16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDirections = dirs; 16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the offset of the first character to be ellipsized away, 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * relative to the start of the line. (So 0 if the beginning of the 16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * line is ellipsized, not getLineStart().) 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getEllipsisStart(int line); 1634e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of characters to be ellipsized away, or 0 if 16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * no ellipsis is to take place. 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getEllipsisCount(int line); 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static class Ellipsizer implements CharSequence, GetChars { 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ CharSequence mText; 16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ Layout mLayout; 16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ int mWidth; 16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ TextUtils.TruncateAt mMethod; 16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Ellipsizer(CharSequence s) { 16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mText = s; 16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public char charAt(int off) { 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] buf = TextUtils.obtain(1); 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(off, off + 1, buf, 0); 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ret = buf[0]; 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.recycle(buf); 16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void getChars(int start, int end, char[] dest, int destoff) { 16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int line1 = mLayout.getLineForOffset(start); 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int line2 = mLayout.getLineForOffset(end); 16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.getChars(mText, start, end, dest, destoff); 16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = line1; i <= line2; i++) { 16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayout.ellipsize(start, end, i, dest, destoff); 16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int length() { 16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mText.length(); 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16749f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CharSequence subSequence(int start, int end) { 16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] s = new char[end - start]; 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(start, end, s, 0); 16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new String(s); 16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1681162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne @Override 16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] s = new char[length()]; 16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(0, length(), s, 0); 16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new String(s); 16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static class SpannedEllipsizer 16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project extends Ellipsizer implements Spanned { 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Spanned mSpanned; 16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannedEllipsizer(CharSequence display) { 16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(display); 16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanned = (Spanned) display; 16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public <T> T[] getSpans(int start, int end, Class<T> type) { 17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.getSpans(start, end, type); 17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSpanStart(Object tag) { 17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.getSpanStart(tag); 17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSpanEnd(Object tag) { 17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.getSpanEnd(tag); 17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSpanFlags(Object tag) { 17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.getSpanFlags(tag); 17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int nextSpanTransition(int start, int limit, Class type) { 17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.nextSpanTransition(start, limit, type); 17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1719162bf0f1b9fd5d78ffa801917994f6222c6efd85Gilles Debunne @Override 17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CharSequence subSequence(int start, int end) { 17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] s = new char[end - start]; 17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(start, end, s, 0); 17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SpannableString ss = new SpannableString(new String(s)); 17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.copySpansFrom(mSpanned, start, end, Object.class, ss, 0); 17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ss; 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private CharSequence mText; 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextPaint mPaint; 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ TextPaint mWorkPaint; 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mWidth; 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Alignment mAlignment = Alignment.ALIGN_NORMAL; 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSpacingMult; 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSpacingAdd; 1737c4d8eb6fb7c88c5c4da38b0b113c24cc4b78c0b7Romain Guy private static final Rect sTempRect = new Rect(); 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mSpannedText; 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int DIR_LEFT_TO_RIGHT = 1; 17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int DIR_RIGHT_TO_LEFT = -1; 17429f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 174320178d62cf669af18467a16d3c4c4237ed42151cDoug Felt /* package */ static final int DIR_REQUEST_LTR = 1; 174420178d62cf669af18467a16d3c4c4237ed42151cDoug Felt /* package */ static final int DIR_REQUEST_RTL = -1; 174520178d62cf669af18467a16d3c4c4237ed42151cDoug Felt /* package */ static final int DIR_REQUEST_DEFAULT_LTR = 2; 174620178d62cf669af18467a16d3c4c4237ed42151cDoug Felt /* package */ static final int DIR_REQUEST_DEFAULT_RTL = -2; 17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17489f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ static final int RUN_LENGTH_MASK = 0x03ffffff; 17499f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ static final int RUN_LEVEL_SHIFT = 26; 17509f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ static final int RUN_LEVEL_MASK = 0x3f; 17519f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ static final int RUN_RTL_FLAG = 1 << RUN_LEVEL_SHIFT; 17529f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum Alignment { 17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALIGN_NORMAL, 17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALIGN_OPPOSITE, 17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALIGN_CENTER, 17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // XXX ALIGN_LEFT, 17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // XXX ALIGN_RIGHT, 17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TAB_INCREMENT = 20; 17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static final Directions DIRS_ALL_LEFT_TO_RIGHT = 17649f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt new Directions(new int[] { 0, RUN_LENGTH_MASK }); 17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static final Directions DIRS_ALL_RIGHT_TO_LEFT = 17669f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG }); 17670a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne 17680a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne /** 17690a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne * Inform this layout that not all of its lines will be displayed, because a maximum number of 17700a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne * lines has been set on the associated TextView. 17710a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne * 17720a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne * A non positive value means that all lines are displayed. 17730a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne * 17740a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne * @param line line number of the last visible line (line numbers start at 1 for the first line) 17750a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne * @hide 17760a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne */ 17770a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne public void setMaximumVisibleLineCount(int line) {} 17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1779