Layout.java revision e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7a
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; 299f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.LineBackgroundSpan; 309f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.ParagraphStyle; 319f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.ReplacementSpan; 329f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport android.text.style.TabStopSpan; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 359f7a4442b89cc06cb8cae6992484e7ae795323abDoug Feltimport junit.framework.Assert; 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 { 4576c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort private static final boolean DEBUG = false; 4671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt private static final ParagraphStyle[] NO_PARA_SPANS = 4771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt ArrayUtils.emptyArray(ParagraphStyle.class); 4876c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort 49105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project /* package */ static final EmojiFactory EMOJI_FACTORY = 50105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project EmojiFactory.newAvailableInstance(); 51105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project /* package */ static final int MIN_EMOJI, MAX_EMOJI; 52105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 53105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project static { 54105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (EMOJI_FACTORY != null) { 55105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project MIN_EMOJI = EMOJI_FACTORY.getMinimumAndroidPua(); 56105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project MAX_EMOJI = EMOJI_FACTORY.getMaximumAndroidPua(); 57105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } else { 58105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project MIN_EMOJI = -1; 59105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project MAX_EMOJI = -1; 60105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 61e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } 62c2d54f46ac13e029e6d53f7471cd9c90fe6bbfe9Eric Fischer 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return how wide a layout must be in order to display the 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * specified text with one line per paragraph. 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static float getDesiredWidth(CharSequence source, 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint paint) { 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getDesiredWidth(source, 0, source.length(), paint); 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 719f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return how wide a layout must be in order to display the 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * specified text slice with one line per paragraph. 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static float getDesiredWidth(CharSequence source, 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start, int end, 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint paint) { 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float need = 0; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint workPaint = new TextPaint(); 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int next; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = start; i <= end; i = next) { 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project next = TextUtils.indexOf(source, '\n', i, end); 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (next < 0) 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project next = end; 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // note, omits trailing paragraph char 90e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt float w = measurePara(paint, workPaint, 91e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt source, i, next, true, null); 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (w > need) 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project need = w; 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project next++; 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return need; 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Subclasses of Layout use this constructor to set the display text, 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * width, and other standard properties. 10571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param text the text to render 10671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param paint the default paint for the layout. Styles can override 10771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * various attributes of the paint. 10871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param width the wrapping width for the text. 10971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param align whether to left, right, or center the text. Styles can 11071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * override the alignment. 11171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param spacingMult factor by which to scale the font size to get the 11271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * default line spacing 11371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param spacingAdd amount to add to the default line spacing 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected Layout(CharSequence text, TextPaint paint, 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int width, Alignment align, 11771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt float spacingMult, float spacingAdd) { 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (width < 0) 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Layout: " + width + " < 0"); 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 121e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // Ensure paint doesn't have baselineShift set. 122e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // While normally we don't modify the paint the user passed in, 123e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // we were already doing this in Styled.drawUniformRun with both 124e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // baselineShift and bgColor. We probably should reevaluate bgColor. 125e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (paint != null) { 126e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt paint.bgColor = 0; 127e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt paint.baselineShift = 0; 128e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } 129e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mText = text; 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint = paint; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWorkPaint = new TextPaint(); 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWidth = width; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlignment = align; 13571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt mSpacingMult = spacingMult; 13671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt mSpacingAdd = spacingAdd; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpannedText = text instanceof Spanned; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Replace constructor properties of this Layout with new ones. Be careful. 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void replaceWith(CharSequence text, TextPaint paint, 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int width, Alignment align, 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float spacingmult, float spacingadd) { 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (width < 0) { 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Layout: " + width + " < 0"); 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mText = text; 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint = paint; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWidth = width; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlignment = align; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpacingMult = spacingmult; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpacingAdd = spacingadd; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpannedText = text instanceof Spanned; 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Draw this Layout on the specified Canvas. 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void draw(Canvas c) { 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project draw(c, null, null, 0); 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 16771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Draw this Layout on the specified canvas, with the highlight path drawn 16871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * between the background and the text. 16971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * 17071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param c the canvas 17171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param highlight the path of the highlight or cursor; can be null 17271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param highlightPaint the paint for the highlight 17371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param cursorOffsetVertical the amount to temporarily translate the 17471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * canvas while rendering the highlight 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt public void draw(Canvas c, Path highlight, Paint highlightPaint, 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int cursorOffsetVertical) { 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dtop, dbottom; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (sTempRect) { 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!c.getClipBounds(sTempRect)) { 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dtop = sTempRect.top; 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dbottom = sTempRect.bottom; 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top = 0; 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottom = getLineTop(getLineCount()); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dtop > top) { 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top = dtop; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dbottom < bottom) { 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom = dbottom; 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1999f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 2009f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int first = getLineForVertical(top); 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int last = getLineForVertical(bottom); 2029f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int previousLineBottom = getLineTop(first); 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int previousLineEnd = getLineStart(first); 2059f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 20671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt TextPaint paint = mPaint; 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence buf = mText; 20871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt int width = mWidth; 20971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt boolean spannedText = mSpannedText; 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt ParagraphStyle[] spans = NO_PARA_SPANS; 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spanend = 0; 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int textLength = 0; 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // First, draw LineBackgroundSpans. 21671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // LineBackgroundSpans know nothing about the alignment or direction of 21771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // the layout or line. XXX: Should they? 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spannedText) { 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project textLength = buf.length(); 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = first; i <= last; i++) { 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = previousLineEnd; 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = getLineStart(i+1); 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineEnd = end; 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ltop = previousLineBottom; 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lbottom = getLineTop(i+1); 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineBottom = lbottom; 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lbaseline = lbottom - getLineDescent(i); 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start >= spanend) { 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned sp = (Spanned) buf; 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spanend = sp.nextSpanTransition(start, textLength, 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LineBackgroundSpan.class); 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spans = sp.getSpans(start, spanend, 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LineBackgroundSpan.class); 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int n = 0; n < spans.length; n++) { 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LineBackgroundSpan back = (LineBackgroundSpan) spans[n]; 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt back.drawBackground(c, paint, 0, width, 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ltop, lbaseline, lbottom, 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project buf, start, end, 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i); 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // reset to their original values 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spanend = 0; 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineBottom = getLineTop(first); 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineEnd = getLineStart(first); 25171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt spans = NO_PARA_SPANS; 2529f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // There can be a highlight even without spans if we are drawing 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // a non-spanned transformation of a spanned editing buffer. 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (highlight != null) { 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cursorOffsetVertical != 0) { 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.translate(0, cursorOffsetVertical); 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt c.drawPath(highlight, highlightPaint); 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cursorOffsetVertical != 0) { 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.translate(0, -cursorOffsetVertical); 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align = mAlignment; 2699f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 270e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 27171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // Next draw the lines, one at a time. 27271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // the baseline is the top of the following line minus the current 27371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // line's descent. 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = first; i <= last; i++) { 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = previousLineEnd; 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineEnd = getLineStart(i+1); 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = getLineVisibleEnd(i, start, previousLineEnd); 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ltop = previousLineBottom; 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lbottom = getLineTop(i+1); 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousLineBottom = lbottom; 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lbaseline = lbottom - getLineDescent(i); 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt boolean isFirstParaLine = false; 2869f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (spannedText) { 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start == 0 || buf.charAt(start - 1) == '\n') { 28871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt isFirstParaLine = true; 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // New batch of paragraph styles, compute the alignment. 29171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // Last alignment style wins. 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start >= spanend) { 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned sp = (Spanned) buf; 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spanend = sp.nextSpanTransition(start, textLength, 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ParagraphStyle.class); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spans = sp.getSpans(start, spanend, ParagraphStyle.class); 2979f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project align = mAlignment; 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int n = spans.length-1; n >= 0; n--) { 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spans[n] instanceof AlignmentSpan) { 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project align = ((AlignmentSpan) spans[n]).getAlignment(); 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3079f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dir = getParagraphDirection(i); 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = 0; 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int right = mWidth; 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // Draw all leading margin spans. Adjust left or right according 31371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // to the paragraph direction of the line. 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spannedText) { 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int length = spans.length; 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int n = 0; n < length; n++) { 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spans[n] instanceof LeadingMarginSpan) { 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LeadingMarginSpan margin = (LeadingMarginSpan) spans[n]; 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) { 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project margin.drawLeadingMargin(c, paint, right, dir, ltop, 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lbaseline, lbottom, buf, 32371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt start, end, isFirstParaLine, this); 3249f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 32571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt right -= margin.getLeadingMargin(isFirstParaLine); 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project margin.drawLeadingMargin(c, paint, left, dir, ltop, 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lbaseline, lbottom, buf, 32971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt start, end, isFirstParaLine, this); 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt boolean useMargin = isFirstParaLine; 3327b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner if (margin instanceof LeadingMarginSpan.LeadingMarginSpan2) { 3337b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner int count = ((LeadingMarginSpan.LeadingMarginSpan2)margin).getLeadingMarginLineCount(); 3347b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner useMargin = count > i; 3357b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner } 3367b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner left += margin.getLeadingMargin(useMargin); 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 34271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // Adjust the point at which to start rendering depending on the 34371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // alignment of the paragraph. 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int x; 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_NORMAL) { 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_LEFT_TO_RIGHT) { 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = left; 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = right; 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int max = (int)getLineMax(i, spans, false); 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_OPPOSITE) { 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) { 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = left + max; 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = right - max; 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Alignment.ALIGN_CENTER 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project max = max & ~1; 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int half = (right - left - max) >> 1; 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) { 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = right - half; 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = left + half; 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Directions directions = getLineDirections(i); 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean hasTab = getLineContainsTab(i); 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (directions == DIRS_ALL_LEFT_TO_RIGHT && 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project !spannedText && !hasTab) { 37576c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort if (DEBUG) { 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Assert.assertTrue(dir == DIR_LEFT_TO_RIGHT); 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Assert.assertNotNull(c); 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 37971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt // XXX: assumes there's nothing additional to be done 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.drawText(buf, start, end, x, lbaseline, paint); 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 382e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl.set(paint, buf, start, end, dir, directions, hasTab, spans); 383e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl.draw(c, x, ltop, lbaseline, lbottom); 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 386e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine.recycle(tl); 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the text that is displayed by this Layout. 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final CharSequence getText() { 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mText; 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the base Paint properties for this layout. 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Do NOT change the paint, which may result in funny 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * drawing for this layout. 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final TextPaint getPaint() { 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mPaint; 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the width of this layout. 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getWidth() { 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth; 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the width to which this Layout is ellipsizing, or 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #getWidth} if it is not doing anything special. 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getEllipsizedWidth() { 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth; 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Increase the width of this layout to the specified width. 42271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Be careful to use this only when you know it is appropriate— 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * it does not cause the text to reflow to use the full new width. 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final void increaseWidthTo(int wid) { 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (wid < mWidth) { 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new RuntimeException("attempted to reduce Layout width"); 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWidth = wid; 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4329f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the total height of this layout. 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getHeight() { 43771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt return getLineTop(getLineCount()); 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the base alignment of this layout. 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final Alignment getAlignment() { 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mAlignment; 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return what the text height is multiplied by to get the line height. 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final float getSpacingMultiplier() { 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpacingMult; 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the number of units of leading that are added to each line. 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final float getSpacingAdd() { 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpacingAdd; 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the number of lines of text in this layout. 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getLineCount(); 4659f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the baseline for the specified line (0…getLineCount() - 1) 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If bounds is not null, return the top, left, right, bottom extents 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of the specified line in it. 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param line which line to examine (0..getLineCount() - 1) 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param bounds Optional. If not null, it returns the extent of the line 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the Y-coordinate of the baseline 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineBounds(int line, Rect bounds) { 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bounds != null) { 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bounds.left = 0; // ??? 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bounds.top = getLineTop(line); 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bounds.right = mWidth; // ??? 47971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt bounds.bottom = getLineTop(line + 1); 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineBaseline(line); 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 48571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return the vertical position of the top of the specified line 48671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * (0…getLineCount()). 48771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * If the specified line is equal to the line count, returns the 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * bottom of the last line. 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getLineTop(int line); 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 49371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return the descent of the specified line(0…getLineCount() - 1). 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getLineDescent(int line); 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 49871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Return the text offset of the beginning of the specified line ( 49971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * 0…getLineCount()). If the specified line is equal to the line 50071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * count, returns the length of the text. 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getLineStart(int line); 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 50571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Returns the primary directionality of the paragraph containing the 50671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * specified line, either 1 for left-to-right lines, or -1 for right-to-left 50771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * lines (see {@link #DIR_LEFT_TO_RIGHT}, {@link #DIR_RIGHT_TO_LEFT}). 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getParagraphDirection(int line); 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 512105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * Returns whether the specified line contains one or more 513105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * characters that need to be handled specially, like tabs 514105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project * or emoji. 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract boolean getLineContainsTab(int line); 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 51971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Returns the directional run information for the specified line. 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The array alternates counts of characters in left-to-right 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and right-to-left segments of the line. 52271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * 52371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * <p>NOTE: this is inadequate to support bidirectional text, and will change. 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract Directions getLineDirections(int line); 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the (negative) number of extra pixels of ascent padding in the 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * top line of the Layout. 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getTopPadding(); 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of extra pixels of descent padding in the 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * bottom line of the Layout. 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getBottomPadding(); 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5394e0c5e55e171532760d5f51e0165563827129d4eDoug Felt 5404e0c5e55e171532760d5f51e0165563827129d4eDoug Felt /** 5414e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * Returns true if the character at offset and the preceding character 5424e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * are at different run levels (and thus there's a split caret). 5434e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * @param offset the offset 5444e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * @return true if at a level boundary 5454e0c5e55e171532760d5f51e0165563827129d4eDoug Felt */ 5464e0c5e55e171532760d5f51e0165563827129d4eDoug Felt private boolean isLevelBoundary(int offset) { 5479f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int line = getLineForOffset(offset); 5484e0c5e55e171532760d5f51e0165563827129d4eDoug Felt Directions dirs = getLineDirections(line); 5494e0c5e55e171532760d5f51e0165563827129d4eDoug Felt if (dirs == DIRS_ALL_LEFT_TO_RIGHT || dirs == DIRS_ALL_RIGHT_TO_LEFT) { 5504e0c5e55e171532760d5f51e0165563827129d4eDoug Felt return false; 5514e0c5e55e171532760d5f51e0165563827129d4eDoug Felt } 5524e0c5e55e171532760d5f51e0165563827129d4eDoug Felt 5534e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int[] runs = dirs.mDirections; 5549f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int lineStart = getLineStart(line); 5554e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int lineEnd = getLineEnd(line); 5564e0c5e55e171532760d5f51e0165563827129d4eDoug Felt if (offset == lineStart || offset == lineEnd) { 5574e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int paraLevel = getParagraphDirection(line) == 1 ? 0 : 1; 5584e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int runIndex = offset == lineStart ? 0 : runs.length - 2; 5594e0c5e55e171532760d5f51e0165563827129d4eDoug Felt return ((runs[runIndex + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK) != paraLevel; 5604e0c5e55e171532760d5f51e0165563827129d4eDoug Felt } 5614e0c5e55e171532760d5f51e0165563827129d4eDoug Felt 5624e0c5e55e171532760d5f51e0165563827129d4eDoug Felt offset -= lineStart; 5639f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < runs.length; i += 2) { 5644e0c5e55e171532760d5f51e0165563827129d4eDoug Felt if (offset == runs[i]) { 5654e0c5e55e171532760d5f51e0165563827129d4eDoug Felt return true; 5669f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 5679f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 5684e0c5e55e171532760d5f51e0165563827129d4eDoug Felt return false; 5699f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 5709f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 5719f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt private boolean primaryIsTrailingPrevious(int offset) { 5729f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int line = getLineForOffset(offset); 5739f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int lineStart = getLineStart(line); 5744e0c5e55e171532760d5f51e0165563827129d4eDoug Felt int lineEnd = getLineEnd(line); 5759f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int[] runs = getLineDirections(line).mDirections; 5769f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 5779f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int levelAt = -1; 5789f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < runs.length; i += 2) { 5799f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int start = lineStart + runs[i]; 5809f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int limit = start + (runs[i+1] & RUN_LENGTH_MASK); 5819f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (limit > lineEnd) { 5829f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt limit = lineEnd; 5839f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 5849f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (offset >= start && offset < limit) { 5859f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (offset > start) { 5869f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // Previous character is at same level, so don't use trailing. 5879f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return false; 5889f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 5899f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt levelAt = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK; 5909f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt break; 5919f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 5929f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 5939f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (levelAt == -1) { 5949f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // Offset was limit of line. 5959f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt levelAt = getParagraphDirection(line) == 1 ? 0 : 1; 5969f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 5979f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 5989f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // At level boundary, check previous level. 5999f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int levelBefore = -1; 6009f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (offset == lineStart) { 6019f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt levelBefore = getParagraphDirection(line) == 1 ? 0 : 1; 6029f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } else { 6039f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt offset -= 1; 6049f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < runs.length; i += 2) { 6059f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int start = lineStart + runs[i]; 6069f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int limit = start + (runs[i+1] & RUN_LENGTH_MASK); 6079f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (limit > lineEnd) { 6089f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt limit = lineEnd; 6099f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6109f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (offset >= start && offset < limit) { 6119f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt levelBefore = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK; 6129f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt break; 6139f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6149f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6159f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6169f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 6179f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return levelBefore < levelAt; 6189f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 6199f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the primary horizontal position for the specified text offset. 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is the location where a new character would be inserted in 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the paragraph's primary direction. 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getPrimaryHorizontal(int offset) { 6269f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt boolean trailing = primaryIsTrailingPrevious(offset); 6279f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getHorizontal(offset, trailing); 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the secondary horizontal position for the specified text offset. 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is the location where a new character would be inserted in 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the direction other than the paragraph's primary direction. 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getSecondaryHorizontal(int offset) { 6369f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt boolean trailing = primaryIsTrailingPrevious(offset); 6379f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getHorizontal(offset, !trailing); 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6409f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt private float getHorizontal(int offset, boolean trailing) { 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int line = getLineForOffset(offset); 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6439f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getHorizontal(offset, trailing, line); 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6469f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt private float getHorizontal(int offset, boolean trailing, int line) { 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = getLineStart(line); 648e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int end = getLineEnd(line); 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dir = getParagraphDirection(line); 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean tab = getLineContainsTab(line); 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Directions directions = getLineDirections(line); 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TabStopSpan[] tabs = null; 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (tab && mText instanceof Spanned) { 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tabs = ((Spanned) mText).getSpans(start, end, TabStopSpan.class); 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 658e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 659e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl.set(mPaint, mText, start, end, dir, directions, tab, tabs); 660e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt float wid = tl.measure(offset - start, trailing, null); 661e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine.recycle(tl); 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align = getParagraphAlignment(line); 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = getParagraphLeft(line); 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int right = getParagraphRight(line); 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_NORMAL) { 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return right + wid; 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return left + wid; 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float max = getLineMax(line); 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_OPPOSITE) { 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return left + max + wid; 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return right - max + wid; 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { /* align == Alignment.ALIGN_CENTER */ 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int imax = ((int) max) & ~1; 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return right - (((right - left) - imax) / 2) + wid; 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return left + ((right - left) - imax) / 2 + wid; 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the leftmost position that should be exposed for horizontal 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * scrolling on the specified line. 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getLineLeft(int line) { 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dir = getParagraphDirection(line); 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align = getParagraphAlignment(line); 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_NORMAL) { 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getParagraphRight(line) - getLineMax(line); 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (align == Alignment.ALIGN_OPPOSITE) { 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth - getLineMax(line); 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { /* align == Alignment.ALIGN_CENTER */ 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = getParagraphLeft(line); 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int right = getParagraphRight(line); 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int max = ((int) getLineMax(line)) & ~1; 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return left + ((right - left) - max) / 2; 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the rightmost position that should be exposed for horizontal 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * scrolling on the specified line. 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getLineRight(int line) { 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dir = getParagraphDirection(line); 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align = getParagraphAlignment(line); 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (align == Alignment.ALIGN_NORMAL) { 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth; 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getParagraphLeft(line) + getLineMax(line); 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (align == Alignment.ALIGN_OPPOSITE) { 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineMax(line); 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mWidth; 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { /* align == Alignment.ALIGN_CENTER */ 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = getParagraphLeft(line); 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int right = getParagraphRight(line); 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int max = ((int) getLineMax(line)) & ~1; 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return right - ((right - left) - max) / 2; 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the horizontal extent of the specified line, excluding 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * trailing whitespace. 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getLineMax(int line) { 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineMax(line, null, false); 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the horizontal extent of the specified line, including 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * trailing whitespace. 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float getLineWidth(int line) { 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineMax(line, null, true); 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float getLineMax(int line, Object[] tabs, boolean full) { 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = getLineStart(line); 763e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int end = full ? getLineEnd(line) : getLineVisibleEnd(line); 764e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt boolean hasTabs = getLineContainsTab(line); 765e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt Directions directions = getLineDirections(line); 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 767e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 768e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl.set(mPaint, mText, start, end, 1, directions, hasTabs, tabs); 769e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt float width = tl.metrics(null); 770e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine.recycle(tl); 771e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt return width; 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the line number corresponding to the specified vertical position. 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If you ask for a position above 0, you get 0; if you ask for a position 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * below the bottom of the text, you get the last line. 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // FIXME: It may be faster to do a linear search for layouts without many lines. 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineForVertical(int vertical) { 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int high = getLineCount(), low = -1, guess; 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (high - low > 1) { 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project guess = (high + low) / 2; 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getLineTop(guess) > vertical) 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project high = guess; 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = guess; 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < 0) 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return low; 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the line number on which the specified text offset appears. 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If you ask for a position before 0, you get 0; if you ask for a position 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * beyond the end of the text, you get the last line. 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineForOffset(int offset) { 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int high = getLineCount(), low = -1, guess; 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (high - low > 1) { 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project guess = (high + low) / 2; 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getLineStart(guess) > offset) 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project high = guess; 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = guess; 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < 0) 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return low; 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8229f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt * Get the character offset on the specified line whose position is 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * closest to the specified horizontal position. 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getOffsetForHorizontal(int line, float horiz) { 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int max = getLineEnd(line) - 1; 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int min = getLineStart(line); 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Directions dirs = getLineDirections(line); 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line == getLineCount() - 1) 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project max++; 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int best = min; 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz); 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8369f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < dirs.mDirections.length; i += 2) { 8379f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int here = min + dirs.mDirections[i]; 8389f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK); 8399f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int swap = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0 ? -1 : 1; 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (there > max) 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project there = max; 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int high = there - 1 + 1, low = here + 1 - 1, guess; 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (high - low > 1) { 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project guess = (high + low) / 2; 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int adguess = getOffsetAtStartOf(guess); 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getPrimaryHorizontal(adguess) * swap >= horiz * swap) 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project high = guess; 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = guess; 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < here + 1) 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = here + 1; 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < there) { 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = getOffsetAtStartOf(low); 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float dist = Math.abs(getPrimaryHorizontal(low) - horiz); 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int aft = TextUtils.getOffsetAfter(mText, low); 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (aft < there) { 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float other = Math.abs(getPrimaryHorizontal(aft) - horiz); 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (other < dist) { 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dist = other; 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = aft; 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dist < bestdist) { 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bestdist = dist; 8759f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt best = low; 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float dist = Math.abs(getPrimaryHorizontal(here) - horiz); 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dist < bestdist) { 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bestdist = dist; 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project best = here; 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float dist = Math.abs(getPrimaryHorizontal(max) - horiz); 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dist < bestdist) { 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bestdist = dist; 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project best = max; 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return best; 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the text offset after the last character on the specified line. 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getLineEnd(int line) { 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineStart(line + 1); 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9049f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /** 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the text offset after the last visible character (so whitespace 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is not counted) on the specified line. 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineVisibleEnd(int line) { 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineVisibleEnd(line, getLineStart(line), getLineStart(line+1)); 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9119f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getLineVisibleEnd(int line, int start, int end) { 91376c0226008ee16633dc94ed4dbeadef2174f6bd9Dave Bort if (DEBUG) { 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Assert.assertTrue(getLineStart(line) == start && getLineStart(line+1) == end); 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence text = mText; 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ch; 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line == getLineCount() - 1) { 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return end; 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (; end > start; end--) { 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ch = text.charAt(end - 1); 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch == '\n') { 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return end - 1; 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch != ' ' && ch != '\t') { 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return end; 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the vertical position of the bottom of the specified line. 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getLineBottom(int line) { 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineTop(line + 1); 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the vertical position of the baseline of the specified line. 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getLineBaseline(int line) { 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // getLineTop(line+1) == getLineTop(line) 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineTop(line+1) - getLineDescent(line); 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the ascent of the text on the specified line. 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The return value is negative to match the Paint.ascent() convention. 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getLineAscent(int line) { 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // getLineTop(line+1) - getLineDescent(line) == getLineBaseLine(line) 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return getLineTop(line) - (getLineTop(line+1) - getLineDescent(line)); 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getOffsetToLeftOf(int offset) { 9649f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getOffsetToLeftRightOf(offset, true); 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getOffsetToRightOf(int offset) { 9689f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt return getOffsetToLeftRightOf(offset, false); 9699f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9719f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt private int getOffsetToLeftRightOf(int caret, boolean toLeft) { 9729f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int line = getLineForOffset(caret); 9739f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int lineStart = getLineStart(line); 9749f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int lineEnd = getLineEnd(line); 975e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int lineDir = getParagraphDirection(line); 976e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 977e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt boolean advance = toLeft == (lineDir == DIR_RIGHT_TO_LEFT); 978e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (caret == (advance ? lineEnd : lineStart)) { 979e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // walking off line, so look at the line we're headed to 980e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (caret == lineStart) { 981e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (line > 0) { 982e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt --line; 983e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } else { 984e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt return caret; // at very start, don't move 985e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } 986e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } else { 987e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (line < getLineCount() - 1) { 988e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt ++line; 989e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } else { 990e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt return caret; // at very end, don't move 9919f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 994e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt lineStart = getLineStart(line); 995e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt lineEnd = getLineEnd(line); 996e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int newDir = getParagraphDirection(line); 997e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (newDir != lineDir) { 998e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // unusual case. we want to walk onto the line, but it runs 999e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // in a different direction than this one, so we fake movement 1000e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // in the opposite direction. 1001e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt toLeft = !toLeft; 1002e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt lineDir = newDir; 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10049f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } 10059f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 1006e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt Directions directions = getLineDirections(line); 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1008e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 1009e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // XXX: we don't care about tabs 1010e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl.set(mPaint, mText, lineStart, lineEnd, lineDir, directions, false, null); 1011e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt caret = lineStart + tl.getOffsetToLeftRightOf(caret - lineStart, toLeft); 1012e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl = TextLine.recycle(tl); 1013e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt return caret; 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getOffsetAtStartOf(int offset) { 10179f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // XXX this probably should skip local reorderings and 10189f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // zero-width characters, look at callers 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (offset == 0) 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence text = mText; 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = text.charAt(offset); 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c >= '\uDC00' && c <= '\uDFFF') { 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c1 = text.charAt(offset - 1); 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c1 >= '\uD800' && c1 <= '\uDBFF') 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset -= 1; 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSpannedText) { 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset, 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ReplacementSpan.class); 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < spans.length; i++) { 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = ((Spanned) text).getSpanStart(spans[i]); 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = ((Spanned) text).getSpanEnd(spans[i]); 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start < offset && end > offset) 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset = start; 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return offset; 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Fills in the specified Path with a representation of a cursor 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * at the specified offset. This will often be a vertical line 10514e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * but can be multiple discontinuous lines in text with multiple 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * directionalities. 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void getCursorPath(int point, Path dest, 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence editingBuffer) { 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.reset(); 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int line = getLineForOffset(point); 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top = getLineTop(line); 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottom = getLineTop(line+1); 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float h1 = getPrimaryHorizontal(point) - 0.5f; 10634e0c5e55e171532760d5f51e0165563827129d4eDoug Felt float h2 = isLevelBoundary(point) ? 10644e0c5e55e171532760d5f51e0165563827129d4eDoug Felt getSecondaryHorizontal(point) - 0.5f : h1; 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int caps = TextKeyListener.getMetaState(editingBuffer, 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project KeyEvent.META_SHIFT_ON) | 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextKeyListener.getMetaState(editingBuffer, 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextKeyListener.META_SELECTING); 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fn = TextKeyListener.getMetaState(editingBuffer, 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project KeyEvent.META_ALT_ON); 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dist = 0; 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (caps != 0 || fn != 0) { 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dist = (bottom - top) >> 2; 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fn != 0) 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top += dist; 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (caps != 0) 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom -= dist; 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (h1 < 0.5f) 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project h1 = 0.5f; 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (h2 < 0.5f) 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project h2 = 0.5f; 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (h1 == h2) { 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1, top); 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1, bottom); 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1, top); 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1, (top + bottom) >> 1); 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2, (top + bottom) >> 1); 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2, bottom); 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (caps == 2) { 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2, bottom); 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2 - dist, bottom + dist); 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2, bottom); 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2 + dist, bottom + dist); 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (caps == 1) { 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2, bottom); 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2 - dist, bottom + dist); 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2 - dist, bottom + dist - 0.5f); 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2 + dist, bottom + dist - 0.5f); 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h2 + dist, bottom + dist); 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h2, bottom); 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fn == 2) { 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1, top); 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1 - dist, top - dist); 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1, top); 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1 + dist, top - dist); 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (fn == 1) { 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1, top); 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1 - dist, top - dist); 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1 - dist, top - dist + 0.5f); 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1 + dist, top - dist + 0.5f); 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.moveTo(h1 + dist, top - dist); 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.lineTo(h1, top); 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void addSelection(int line, int start, int end, 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top, int bottom, Path dest) { 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int linestart = getLineStart(line); 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lineend = getLineEnd(line); 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Directions dirs = getLineDirections(line); 11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lineend > linestart && mText.charAt(lineend - 1) == '\n') 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lineend--; 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11419f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt for (int i = 0; i < dirs.mDirections.length; i += 2) { 11429f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int here = linestart + dirs.mDirections[i]; 11439f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK); 11449f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (there > lineend) 11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project there = lineend; 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start <= there && end >= here) { 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int st = Math.max(start, here); 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int en = Math.min(end, there); 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (st != en) { 11539f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt float h1 = getHorizontal(st, false, line); 11549f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt float h2 = getHorizontal(en, true, line); 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(h1, top, h2, bottom, Path.Direction.CW); 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Fills in the specified Path with a representation of a highlight 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * between the specified offsets. This will often be a rectangle 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or a potentially discontinuous set of rectangles. If the start 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and end are the same, the returned path is empty. 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void getSelectionPath(int start, int end, Path dest) { 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.reset(); 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start == end) 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end < start) { 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int temp = end; 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end = start; 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start = temp; 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int startline = getLineForOffset(start); 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int endline = getLineForOffset(end); 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int top = getLineTop(startline); 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int bottom = getLineBottom(endline); 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (startline == endline) { 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addSelection(startline, start, end, top, bottom, dest); 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float width = mWidth; 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addSelection(startline, start, getLineEnd(startline), 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top, getLineBottom(startline), dest); 11939f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT) 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(getLineLeft(startline), top, 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 0, getLineBottom(startline), Path.Direction.CW); 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(getLineRight(startline), top, 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project width, getLineBottom(startline), Path.Direction.CW); 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = startline + 1; i < endline; i++) { 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top = getLineTop(i); 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom = getLineBottom(i); 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(0, top, width, bottom, Path.Direction.CW); 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top = getLineTop(endline); 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom = getLineBottom(endline); 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project addSelection(endline, getLineStart(endline), end, 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top, bottom, dest); 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT) 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(width, top, getLineRight(endline), bottom, Path.Direction.CW); 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.addRect(0, top, getLineLeft(endline), bottom, Path.Direction.CW); 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the alignment of the specified paragraph, taking into account 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * markup attached to it. 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final Alignment getParagraphAlignment(int line) { 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align = mAlignment; 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSpannedText) { 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned sp = (Spanned) mText; 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AlignmentSpan[] spans = sp.getSpans(getLineStart(line), 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getLineEnd(line), 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AlignmentSpan.class); 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spanLength = spans.length; 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanLength > 0) { 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project align = spans[spanLength-1].getAlignment(); 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return align; 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the left edge of the specified paragraph, inset by left margins. 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getParagraphLeft(int line) { 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dir = getParagraphDirection(line); 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int left = 0; 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean par = false; 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int off = getLineStart(line); 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (off == 0 || mText.charAt(off - 1) == '\n') 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project par = true; 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_LEFT_TO_RIGHT) { 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSpannedText) { 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned sp = (Spanned) mText; 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line), 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getLineEnd(line), 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LeadingMarginSpan.class); 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < spans.length; i++) { 12637b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner boolean margin = par; 12647b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner LeadingMarginSpan span = spans[i]; 12657b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner if (span instanceof LeadingMarginSpan.LeadingMarginSpan2) { 12667b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner int count = ((LeadingMarginSpan.LeadingMarginSpan2)span).getLeadingMarginLineCount(); 12677b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner margin = count >= line; 12687b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner } 12697b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner left += span.getLeadingMargin(margin); 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return left; 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the right edge of the specified paragraph, inset by right margins. 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getParagraphRight(int line) { 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dir = getParagraphDirection(line); 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int right = mWidth; 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean par = false; 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int off = getLineStart(line); 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (off == 0 || mText.charAt(off - 1) == '\n') 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project par = true; 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dir == DIR_RIGHT_TO_LEFT) { 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSpannedText) { 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned sp = (Spanned) mText; 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LeadingMarginSpan[] spans = sp.getSpans(getLineStart(line), 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getLineEnd(line), 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LeadingMarginSpan.class); 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < spans.length; i++) { 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project right -= spans[i].getLeadingMargin(par); 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return right; 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1307e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt /* package */ 1308e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt static float measurePara(TextPaint paint, TextPaint workPaint, 1309e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt CharSequence text, int start, int end, boolean hasTabs, 1310e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt Object[] tabs) { 1311e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 1312e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt MeasuredText mt = MeasuredText.obtain(); 1313e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine tl = TextLine.obtain(); 1314e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt try { 1315e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt mt.setPara(text, start, end, DIR_REQUEST_LTR); 1316e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt Directions directions; 1317e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (mt.mEasy){ 1318e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt directions = DIRS_ALL_LEFT_TO_RIGHT; 1319e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } else { 1320e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt directions = AndroidBidi.directions(mt.mDir, mt.mLevels, 1321e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 0, mt.mChars, 0, mt.mLen); 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1323e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt tl.set(paint, text, start, end, 1, directions, hasTabs, tabs); 1324e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt return tl.metrics(null); 1325e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt } finally { 1326e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt TextLine.recycle(tl); 1327e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt MeasuredText.recycle(mt); 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 133171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt /** 133271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * Returns the position of the next tab stop after h on the line. 133371b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * 133471b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param text the text 133571b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param start start of the line 133671b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param end limit of the line 133771b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param h the current horizontal offset 133871b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @param tabs the tabs, can be null. If it is null, any tabs in effect 133971b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * on the line will be used. If there are no tabs, a default offset 134071b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * will be used to compute the tab stop. 134171b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt * @return the offset of the next tab stop. 134271b8dd71e49016e057c46a257f79162d186a3c3aDoug Felt */ 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static float nextTab(CharSequence text, int start, int end, 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float h, Object[] tabs) { 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float nh = Float.MAX_VALUE; 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean alltabs = false; 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (text instanceof Spanned) { 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (tabs == null) { 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tabs = ((Spanned) text).getSpans(start, end, TabStopSpan.class); 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project alltabs = true; 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < tabs.length; i++) { 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!alltabs) { 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!(tabs[i] instanceof TabStopSpan)) 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int where = ((TabStopSpan) tabs[i]).getTabStop(); 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where < nh && where > h) 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project nh = where; 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (nh != Float.MAX_VALUE) 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return nh; 13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ((int) ((h + TAB_INCREMENT) / TAB_INCREMENT)) * TAB_INCREMENT; 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected final boolean isSpanned() { 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpannedText; 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void ellipsize(int start, int end, int line, 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] dest, int destoff) { 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ellipsisCount = getEllipsisCount(line); 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ellipsisCount == 0) { 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ellipsisStart = getEllipsisStart(line); 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int linestart = getLineStart(line); 13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = ellipsisStart; i < ellipsisStart + ellipsisCount; i++) { 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c; 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i == ellipsisStart) { 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = '\u2026'; // ellipsis 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = '\uFEFF'; // 0-width space 13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int a = i + linestart; 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (a >= start && a < end) { 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest[destoff + a - start] = c; 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Stores information about bidirectional (left-to-right or right-to-left) 14079f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt * text within the layout of a line. 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static class Directions { 14109f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // Directions represents directional runs within a line of text. 14119f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // Runs are pairs of ints listed in visual order, starting from the 14129f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // leading margin. The first int of each pair is the offset from 14139f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // the first character of the line to the start of the run. The 14149f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // second int represents both the length and level of the run. 14159f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // The length is in the lower bits, accessed by masking with 14169f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // DIR_LENGTH_MASK. The level is in the higher bits, accessed 14179f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // by shifting by DIR_LEVEL_SHIFT and masking by DIR_LEVEL_MASK. 14189f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // To simply test for an RTL direction, test the bit using 14199f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // DIR_RTL_FLAG, if set then the direction is rtl. 14209f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 14219f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ int[] mDirections; 14229f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ Directions(int[] dirs) { 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDirections = dirs; 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the offset of the first character to be ellipsized away, 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * relative to the start of the line. (So 0 if the beginning of the 14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * line is ellipsized, not getLineStart().) 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getEllipsisStart(int line); 1433e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the number of characters to be ellipsized away, or 0 if 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * no ellipsis is to take place. 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public abstract int getEllipsisCount(int line); 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static class Ellipsizer implements CharSequence, GetChars { 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ CharSequence mText; 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ Layout mLayout; 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ int mWidth; 14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ TextUtils.TruncateAt mMethod; 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Ellipsizer(CharSequence s) { 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mText = s; 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public char charAt(int off) { 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] buf = TextUtils.obtain(1); 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(off, off + 1, buf, 0); 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ret = buf[0]; 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.recycle(buf); 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void getChars(int start, int end, char[] dest, int destoff) { 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int line1 = mLayout.getLineForOffset(start); 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int line2 = mLayout.getLineForOffset(end); 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.getChars(mText, start, end, dest, destoff); 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = line1; i <= line2; i++) { 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLayout.ellipsize(start, end, i, dest, destoff); 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int length() { 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mText.length(); 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14739f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CharSequence subSequence(int start, int end) { 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] s = new char[end - start]; 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(start, end, s, 0); 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new String(s); 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] s = new char[length()]; 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(0, length(), s, 0); 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new String(s); 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static class SpannedEllipsizer 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project extends Ellipsizer implements Spanned { 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Spanned mSpanned; 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannedEllipsizer(CharSequence display) { 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(display); 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanned = (Spanned) display; 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public <T> T[] getSpans(int start, int end, Class<T> type) { 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.getSpans(start, end, type); 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSpanStart(Object tag) { 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.getSpanStart(tag); 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSpanEnd(Object tag) { 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.getSpanEnd(tag); 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSpanFlags(Object tag) { 15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.getSpanFlags(tag); 15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int nextSpanTransition(int start, int limit, Class type) { 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanned.nextSpanTransition(start, limit, type); 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CharSequence subSequence(int start, int end) { 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] s = new char[end - start]; 15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(start, end, s, 0); 15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SpannableString ss = new SpannableString(new String(s)); 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.copySpansFrom(mSpanned, start, end, Object.class, ss, 0); 15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ss; 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private CharSequence mText; 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextPaint mPaint; 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ TextPaint mWorkPaint; 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mWidth; 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Alignment mAlignment = Alignment.ALIGN_NORMAL; 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSpacingMult; 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mSpacingAdd; 15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static Rect sTempRect = new Rect(); 15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mSpannedText; 15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int DIR_LEFT_TO_RIGHT = 1; 15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int DIR_RIGHT_TO_LEFT = -1; 15399f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 154020178d62cf669af18467a16d3c4c4237ed42151cDoug Felt /* package */ static final int DIR_REQUEST_LTR = 1; 154120178d62cf669af18467a16d3c4c4237ed42151cDoug Felt /* package */ static final int DIR_REQUEST_RTL = -1; 154220178d62cf669af18467a16d3c4c4237ed42151cDoug Felt /* package */ static final int DIR_REQUEST_DEFAULT_LTR = 2; 154320178d62cf669af18467a16d3c4c4237ed42151cDoug Felt /* package */ static final int DIR_REQUEST_DEFAULT_RTL = -2; 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15459f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ static final int RUN_LENGTH_MASK = 0x03ffffff; 15469f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ static final int RUN_LEVEL_SHIFT = 26; 15479f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ static final int RUN_LEVEL_MASK = 0x3f; 15489f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt /* package */ static final int RUN_RTL_FLAG = 1 << RUN_LEVEL_SHIFT; 15499f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt 15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public enum Alignment { 15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALIGN_NORMAL, 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALIGN_OPPOSITE, 15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALIGN_CENTER, 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // XXX ALIGN_LEFT, 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // XXX ALIGN_RIGHT, 15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TAB_INCREMENT = 20; 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static final Directions DIRS_ALL_LEFT_TO_RIGHT = 15619f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt new Directions(new int[] { 0, RUN_LENGTH_MASK }); 15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static final Directions DIRS_ALL_RIGHT_TO_LEFT = 15639f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG }); 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1566