MeasuredParagraph.java revision 9d3bd08ebab564ed9231c8ee112e8085cda74ce8
19d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka/* 29d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Copyright (C) 2010 The Android Open Source Project 39d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 49d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License"); 59d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * you may not use this file except in compliance with the License. 69d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * You may obtain a copy of the License at 79d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 89d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * http://www.apache.org/licenses/LICENSE-2.0 99d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Unless required by applicable law or agreed to in writing, software 119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS, 129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * See the License for the specific language governing permissions and 149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * limitations under the License. 159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakapackage android.text; 189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.annotation.FloatRange; 209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.annotation.IntRange; 219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.annotation.NonNull; 229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.annotation.Nullable; 239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.graphics.Paint; 249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.AutoGrowArray.ByteArray; 259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.AutoGrowArray.FloatArray; 269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.AutoGrowArray.IntArray; 279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.Layout.Directions; 289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.style.MetricAffectingSpan; 299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.style.ReplacementSpan; 309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.util.Pools.SynchronizedPool; 319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport dalvik.annotation.optimization.CriticalNative; 339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport libcore.util.NativeAllocationRegistry; 359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport java.util.Arrays; 379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka/** 399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * MeasuredParagraph provides text information for rendering purpose. 409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * The first motivation of this class is identify the text directions and retrieving individual 429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * character widths. However retrieving character widths is slower than identifying text directions. 439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Thus, this class provides several builder methods for specific purposes. 449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * - buildForBidi: 469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Compute only text directions. 479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * - buildForMeasurement: 489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Compute text direction and all character widths. 499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * - buildForStaticLayout: 509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is bit special. StaticLayout also needs to know text direction and character widths for 519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * line breaking, but all things are done in native code. Similarly, text measurement is done 529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * in native code. So instead of storing result to Java array, this keeps the result in native 539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * code since there is no good reason to move the results to Java layer. 549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * In addition to the character widths, some additional information is computed for each purposes, 569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * e.g. whole text length for measurement or font metrics for static layout. 579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * MeasuredParagraph is NOT a thread safe object. 599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @hide 609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakapublic class MeasuredParagraph { 629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static final char OBJECT_REPLACEMENT_CHARACTER = '\uFFFC'; 639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( 659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MeasuredParagraph.class.getClassLoader(), nGetReleaseFunc(), 1024); 669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private MeasuredParagraph() {} // Use build static functions instead. 689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static final SynchronizedPool<MeasuredParagraph> sPool = new SynchronizedPool<>(1); 709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static @NonNull MeasuredParagraph obtain() { // Use build static functions instead. 729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = sPool.acquire(); 739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt != null ? mt : new MeasuredParagraph(); 749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Recycle the MeasuredParagraph. 789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Do not call any methods after you call this method. 809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public void recycle() { 829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka release(); 839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka sPool.release(this); 849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The casted original text. 879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // 889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // This may be null if the passed text is not a Spanned. 899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable Spanned mSpanned; 909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The start offset of the target range in the original text (mSpanned); 929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @IntRange(from = 0) int mTextStart; 939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The length of the target range in the original text. 959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @IntRange(from = 0) int mTextLength; 969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The copied character buffer for measuring text. 989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // 999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The length of this array is mTextLength. 1009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable char[] mCopiedBuffer; 1019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The whole paragraph direction. 1039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Layout.Direction int mParaDir; 1049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // True if the text is LTR direction and doesn't contain any bidi characters. 1069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private boolean mLtrWithoutBidi; 1079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The bidi level for individual characters. 1099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // 1109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // This is empty if mLtrWithoutBidi is true. 1119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @NonNull ByteArray mLevels = new ByteArray(); 1129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The whole width of the text. 1149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getWholeWidth comments. 1159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @FloatRange(from = 0.0f) float mWholeWidth; 1169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Individual characters' widths. 1189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getWidths comments. 1199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable FloatArray mWidths = new FloatArray(); 1209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The span end positions. 1229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getSpanEndCache comments. 1239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable IntArray mSpanEndCache = new IntArray(4); 1249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The font metrics. 1269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getFontMetrics comments. 1279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable IntArray mFontMetrics = new IntArray(4 * 4); 1289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The native MeasuredParagraph. 1309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getNativePtr comments. 1319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Do not modify these members directly. Use bindNativeObject/unbindNativeObject instead. 1329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private /* Maybe Zero */ long mNativePtr = 0; 1339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable Runnable mNativeObjectCleaner; 1349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Associate the native object to this Java object. 1369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void bindNativeObject(/* Non Zero*/ long nativePtr) { 1379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mNativePtr = nativePtr; 1389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mNativeObjectCleaner = sRegistry.registerNativeAllocation(this, nativePtr); 1399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Decouple the native object from this Java object and release the native object. 1429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void unbindNativeObject() { 1439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mNativePtr != 0) { 1449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mNativeObjectCleaner.run(); 1459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mNativePtr = 0; 1469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Following two objects are for avoiding object allocation. 1509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @NonNull TextPaint mCachedPaint = new TextPaint(); 1519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable Paint.FontMetricsInt mCachedFm; 1529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 1549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Releases internal buffers. 1559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 1569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public void release() { 1579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka reset(); 1589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.clearWithReleasingLargeArray(); 1599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.clearWithReleasingLargeArray(); 1609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.clearWithReleasingLargeArray(); 1619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mSpanEndCache.clearWithReleasingLargeArray(); 1629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 1659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Resets the internal state for starting new text. 1669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 1679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void reset() { 1689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mSpanned = null; 1699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer = null; 1709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth = 0; 1719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.clear(); 1729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.clear(); 1739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.clear(); 1749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mSpanEndCache.clear(); 1759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka unbindNativeObject(); 1769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 1799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the characters to be measured. 1809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 1819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is always available. 1829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 1839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull char[] getChars() { 1849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mCopiedBuffer; 1859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 1889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the paragraph direction. 1899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 1909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is always available. 1919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 1929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @Layout.Direction int getParagraphDir() { 1939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mParaDir; 1949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 1979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the directions. 1989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 1999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is always available. 2009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public Directions getDirections(@IntRange(from = 0) int start, // inclusive 2029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end) { // exclusive 2039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mLtrWithoutBidi) { 2049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return Layout.DIRS_ALL_LEFT_TO_RIGHT; 2059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int length = end - start; 2089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return AndroidBidi.directions(mParaDir, mLevels.getRawArray(), start, mCopiedBuffer, start, 2099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka length); 2109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the whole text width. 2149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is available only if the MeasureText is computed with computeForMeasurement. 2169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns 0 in other cases. 2179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @FloatRange(from = 0.0f) float getWholeWidth() { 2199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mWholeWidth; 2209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the individual character's width. 2249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is available only if the MeasureText is computed with computeForMeasurement. 2269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns empty array in other cases. 2279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull FloatArray getWidths() { 2299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mWidths; 2309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the MetricsAffectingSpan end indices. 2349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If the input text is not a spanned string, this has one value that is the length of the text. 2369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is available only if the MeasureText is computed with computeForStaticLayout. 2389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns empty array in other cases. 2399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull IntArray getSpanEndCache() { 2419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mSpanEndCache; 2429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the int array which holds FontMetrics. 2469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This array holds the repeat of top, bottom, ascent, descent of font metrics value. 2489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is available only if the MeasureText is computed with computeForStaticLayout. 2509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns empty array in other cases. 2519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull IntArray getFontMetrics() { 2539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mFontMetrics; 2549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the native ptr of the MeasuredParagraph. 2589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is available only if the MeasureText is computed with computeForStaticLayout. 2609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns 0 in other cases. 2619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public /* Maybe Zero */ long getNativePtr() { 2639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mNativePtr; 2649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Generates new MeasuredParagraph for Bidi computation. 2689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If recycle is null, this returns new instance. If recycle is not null, this fills computed 2709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * result to recycle and returns recycle. 2719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 2739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 2749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 2759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 2769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param recycle pass existing MeasuredParagraph if you want to recycle it. 2779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @return measured text 2799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public static @NonNull MeasuredParagraph buildForBidi(@NonNull CharSequence text, 2819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 2829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 2839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir, 2849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MeasuredParagraph recycle) { 2859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = recycle == null ? obtain() : recycle; 2869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.resetAndAnalyzeBidi(text, start, end, textDir); 2879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 2889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Generates new MeasuredParagraph for measuring texts. 2929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If recycle is null, this returns new instance. If recycle is not null, this fills computed 2949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * result to recycle and returns recycle. 2959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paint the paint to be used for rendering the text. 2979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 2989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 2999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 3009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 3019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param recycle pass existing MeasuredParagraph if you want to recycle it. 3029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @return measured text 3049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 3059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public static @NonNull MeasuredParagraph buildForMeasurement(@NonNull TextPaint paint, 3069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull CharSequence text, 3079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 3089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 3099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir, 3109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MeasuredParagraph recycle) { 3119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = recycle == null ? obtain() : recycle; 3129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.resetAndAnalyzeBidi(text, start, end, textDir); 3139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.mWidths.resize(mt.mTextLength); 3159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mTextLength == 0) { 3169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 3179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mSpanned == null) { 3209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // No style change by MetricsAffectingSpan. Just measure all text. 3219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan( 3229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka paint, null /* spans */, start, end, 0 /* native static layout ptr */); 3239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 3249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // There may be a MetricsAffectingSpan. Split into span transitions and apply styles. 3259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int spanEnd; 3269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int spanStart = start; spanStart < end; spanStart = spanEnd) { 3279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, MetricAffectingSpan.class); 3289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd, 3299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 3309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class); 3319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan( 3329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka paint, spans, spanStart, spanEnd, 0 /* native static layout ptr */); 3339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 3369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 3399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Generates new MeasuredParagraph for StaticLayout. 3409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If recycle is null, this returns new instance. If recycle is not null, this fills computed 3429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * result to recycle and returns recycle. 3439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paint the paint to be used for rendering the text. 3459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 3469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 3479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 3489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 3499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param recycle pass existing MeasuredParagraph if you want to recycle it. 3509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @return measured text 3529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 3539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public static @NonNull MeasuredParagraph buildForStaticLayout( 3549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextPaint paint, 3559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull CharSequence text, 3569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 3579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 3589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir, 3599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MeasuredParagraph recycle) { 3609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = recycle == null ? obtain() : recycle; 3619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.resetAndAnalyzeBidi(text, start, end, textDir); 3629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mTextLength == 0) { 3639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Need to build empty native measured text for StaticLayout. 3649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // TODO: Stop creating empty measured text for empty lines. 3659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka long nativeBuilderPtr = nInitBuilder(); 3669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka try { 3679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.bindNativeObject( 3689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer)); 3699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } finally { 3709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nFreeBuilder(nativeBuilderPtr); 3719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 3739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka long nativeBuilderPtr = nInitBuilder(); 3769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka try { 3779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mSpanned == null) { 3789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // No style change by MetricsAffectingSpan. Just measure all text. 3799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, nativeBuilderPtr); 3809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.mSpanEndCache.append(end); 3819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 3829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // There may be a MetricsAffectingSpan. Split into span transitions and apply 3839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // styles. 3849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int spanEnd; 3859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int spanStart = start; spanStart < end; spanStart = spanEnd) { 3869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, 3879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 3889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd, 3899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 3909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, 3919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 3929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd, 3939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nativeBuilderPtr); 3949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.mSpanEndCache.append(spanEnd); 3959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.bindNativeObject(nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer)); 3989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } finally { 3999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nFreeBuilder(nativeBuilderPtr); 4009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 4039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 4069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Reset internal state and analyzes text for bidirectional runs. 4079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 4089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 4099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 4109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 4119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 4129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 4139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void resetAndAnalyzeBidi(@NonNull CharSequence text, 4149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, // inclusive 4159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive 4169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir) { 4179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka reset(); 4189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mSpanned = text instanceof Spanned ? (Spanned) text : null; 4199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mTextStart = start; 4209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mTextLength = end - start; 4219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mCopiedBuffer == null || mCopiedBuffer.length != mTextLength) { 4239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer = new char[mTextLength]; 4249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka TextUtils.getChars(text, start, end, mCopiedBuffer, 0); 4269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Replace characters associated with ReplacementSpan to U+FFFC. 4289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mSpanned != null) { 4299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka ReplacementSpan[] spans = mSpanned.getSpans(start, end, ReplacementSpan.class); 4309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int i = 0; i < spans.length; i++) { 4329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int startInPara = mSpanned.getSpanStart(spans[i]) - start; 4339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int endInPara = mSpanned.getSpanEnd(spans[i]) - start; 4349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The span interval may be larger and must be restricted to [start, end) 4359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (startInPara < 0) startInPara = 0; 4369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (endInPara > mTextLength) endInPara = mTextLength; 4379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka Arrays.fill(mCopiedBuffer, startInPara, endInPara, OBJECT_REPLACEMENT_CHARACTER); 4389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if ((textDir == TextDirectionHeuristics.LTR 4429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka || textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR 4439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka || textDir == TextDirectionHeuristics.ANYRTL_LTR) 4449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka && TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) { 4459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.clear(); 4469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mParaDir = Layout.DIR_LEFT_TO_RIGHT; 4479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLtrWithoutBidi = true; 4489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 4499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int bidiRequest; 4509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (textDir == TextDirectionHeuristics.LTR) { 4519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_LTR; 4529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else if (textDir == TextDirectionHeuristics.RTL) { 4539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_RTL; 4549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) { 4559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR; 4569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) { 4579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL; 4589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 4599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength); 4609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR; 4619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.resize(mTextLength); 4639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mParaDir = AndroidBidi.bidi(bidiRequest, mCopiedBuffer, mLevels.getRawArray()); 4649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLtrWithoutBidi = false; 4659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void applyReplacementRun(@NonNull ReplacementSpan replacement, 4699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, // inclusive, in copied buffer 4709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive, in copied buffer 4719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Maybe Zero */ long nativeBuilderPtr) { 4729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Use original text. Shouldn't matter. 4739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for 4749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // backward compatibility? or Should we initialize them for getFontMetricsInt? 4759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final float width = replacement.getSize( 4769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm); 4779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr == 0) { 4789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Assigns all width to the first character. This is the same behavior as minikin. 4799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.set(start, width); 4809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (end > start + 1) { 4819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka Arrays.fill(mWidths.getRawArray(), start + 1, end, 0.0f); 4829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth += width; 4849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 4859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nAddReplacementRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end, 4869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width); 4879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void applyStyleRun(@IntRange(from = 0) int start, // inclusive, in copied buffer 4919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive, in copied buffer 4929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Maybe Zero */ long nativeBuilderPtr) { 4939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr != 0) { 4949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint.getFontMetricsInt(mCachedFm); 4959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mLtrWithoutBidi) { 4989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // If the whole text is LTR direction, just apply whole region. 4999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr == 0) { 5009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth += mCachedPaint.getTextRunAdvances( 5019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */, 5029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.getRawArray(), start); 5039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end, 5059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka false /* isRtl */); 5069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // If there is multiple bidi levels, split into individual bidi level and apply style. 5099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka byte level = mLevels.get(start); 5109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Note that the empty text or empty range won't reach this method. 5119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Safe to search from start + 1. 5129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int levelStart = start, levelEnd = start + 1;; ++levelEnd) { 5139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (levelEnd == end || mLevels.get(levelEnd) != level) { // transition point 5149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final boolean isRtl = (level & 0x1) != 0; 5159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr == 0) { 5169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int levelLength = levelEnd - levelStart; 5179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth += mCachedPaint.getTextRunAdvances( 5189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer, levelStart, levelLength, levelStart, levelLength, 5199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka isRtl, mWidths.getRawArray(), levelStart); 5209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), levelStart, 5229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka levelEnd, isRtl); 5239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (levelEnd == end) { 5259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka break; 5269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka levelStart = levelEnd; 5289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka level = mLevels.get(levelEnd); 5299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void applyMetricsAffectingSpan( 5359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextPaint paint, 5369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MetricAffectingSpan[] spans, 5379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, // inclusive, in original text buffer 5389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive, in original text buffer 5399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Maybe Zero */ long nativeBuilderPtr) { 5409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint.set(paint); 5419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // XXX paint should not have a baseline shift, but... 5429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint.baselineShift = 0; 5439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final boolean needFontMetrics = nativeBuilderPtr != 0; 5459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (needFontMetrics && mCachedFm == null) { 5479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm = new Paint.FontMetricsInt(); 5489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka ReplacementSpan replacement = null; 5519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (spans != null) { 5529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int i = 0; i < spans.length; i++) { 5539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan span = spans[i]; 5549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (span instanceof ReplacementSpan) { 5559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The last ReplacementSpan is effective for backward compatibility reasons. 5569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka replacement = (ReplacementSpan) span; 5579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // TODO: No need to call updateMeasureState for ReplacementSpan as well? 5599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka span.updateMeasureState(mCachedPaint); 5609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int startInCopiedBuffer = start - mTextStart; 5659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int endInCopiedBuffer = end - mTextStart; 5669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (replacement != null) { 5689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, 5699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nativeBuilderPtr); 5709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, nativeBuilderPtr); 5729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (needFontMetrics) { 5759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mCachedPaint.baselineShift < 0) { 5769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.ascent += mCachedPaint.baselineShift; 5779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.top += mCachedPaint.baselineShift; 5789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.descent += mCachedPaint.baselineShift; 5809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.bottom += mCachedPaint.baselineShift; 5819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.top); 5849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.bottom); 5859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.ascent); 5869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.descent); 5879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 5919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the maximum index that the accumulated width not exceeds the width. 5929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 5939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If forward=false is passed, returns the minimum index from the end instead. 5949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 5959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This only works if the MeasuredParagraph is computed with computeForMeasurement. 5969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Undefined behavior in other case. 5979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 5989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int breakText(int limit, boolean forwards, float width) { 5999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka float[] w = mWidths.getRawArray(); 6009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (forwards) { 6019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int i = 0; 6029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i < limit) { 6039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width -= w[i]; 6049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (width < 0.0f) break; 6059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka i++; 6069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i > 0 && mCopiedBuffer[i - 1] == ' ') i--; 6089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return i; 6099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 6109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int i = limit - 1; 6119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i >= 0) { 6129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width -= w[i]; 6139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (width < 0.0f) break; 6149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka i--; 6159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i < limit - 1 && (mCopiedBuffer[i + 1] == ' ' || w[i + 1] == 0.0f)) { 6179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka i++; 6189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return limit - i - 1; 6209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 6249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the length of the substring. 6259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 6269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This only works if the MeasuredParagraph is computed with computeForMeasurement. 6279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Undefined behavior in other case. 6289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 6299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @FloatRange(from = 0.0f) float measure(int start, int limit) { 6309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka float width = 0; 6319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka float[] w = mWidths.getRawArray(); 6329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int i = start; i < limit; ++i) { 6339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width += w[i]; 6349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return width; 6369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native /* Non Zero */ long nInitBuilder(); 6399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 6419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Apply style to make native measured text. 6429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 6439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param nativeBuilderPtr The native MeasuredParagraph builder pointer. 6449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paintPtr The native paint pointer to be applied. 6459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start The start offset in the copied buffer. 6469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end The end offset in the copied buffer. 6479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param isRtl True if the text is RTL. 6489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 6499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr, 6509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Non Zero */ long paintPtr, 6519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 6529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 6539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka boolean isRtl); 6549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 6569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Apply ReplacementRun to make native measured text. 6579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 6589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param nativeBuilderPtr The native MeasuredParagraph builder pointer. 6599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paintPtr The native paint pointer to be applied. 6609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start The start offset in the copied buffer. 6619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end The end offset in the copied buffer. 6629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param width The width of the replacement. 6639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 6649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native void nAddReplacementRun(/* Non Zero */ long nativeBuilderPtr, 6659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Non Zero */ long paintPtr, 6669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 6679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 6689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @FloatRange(from = 0) float width); 6699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native long nBuildNativeMeasuredParagraph(/* Non Zero */ long nativeBuilderPtr, 6719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull char[] text); 6729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr); 6749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @CriticalNative 6769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native /* Non Zero */ long nGetReleaseFunc(); 6779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka} 678