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; 24a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonakaimport android.graphics.Rect; 259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.AutoGrowArray.ByteArray; 269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.AutoGrowArray.FloatArray; 279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.AutoGrowArray.IntArray; 289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.Layout.Directions; 299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.style.MetricAffectingSpan; 309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.text.style.ReplacementSpan; 319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport android.util.Pools.SynchronizedPool; 329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport dalvik.annotation.optimization.CriticalNative; 349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport libcore.util.NativeAllocationRegistry; 369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakaimport java.util.Arrays; 389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka/** 409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * MeasuredParagraph provides text information for rendering purpose. 419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * The first motivation of this class is identify the text directions and retrieving individual 439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * character widths. However retrieving character widths is slower than identifying text directions. 449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Thus, this class provides several builder methods for specific purposes. 459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * - buildForBidi: 479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Compute only text directions. 489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * - buildForMeasurement: 499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Compute text direction and all character widths. 509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * - buildForStaticLayout: 519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is bit special. StaticLayout also needs to know text direction and character widths for 529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * line breaking, but all things are done in native code. Similarly, text measurement is done 539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * in native code. So instead of storing result to Java array, this keeps the result in native 549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * code since there is no good reason to move the results to Java layer. 559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * In addition to the character widths, some additional information is computed for each purposes, 579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * e.g. whole text length for measurement or font metrics for static layout. 589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * MeasuredParagraph is NOT a thread safe object. 609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @hide 619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonakapublic class MeasuredParagraph { 639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static final char OBJECT_REPLACEMENT_CHARACTER = '\uFFFC'; 649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( 669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MeasuredParagraph.class.getClassLoader(), nGetReleaseFunc(), 1024); 679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private MeasuredParagraph() {} // Use build static functions instead. 699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static final SynchronizedPool<MeasuredParagraph> sPool = new SynchronizedPool<>(1); 719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static @NonNull MeasuredParagraph obtain() { // Use build static functions instead. 739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = sPool.acquire(); 749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt != null ? mt : new MeasuredParagraph(); 759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Recycle the MeasuredParagraph. 799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Do not call any methods after you call this method. 819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public void recycle() { 839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka release(); 849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka sPool.release(this); 859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The casted original text. 889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // 899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // This may be null if the passed text is not a Spanned. 909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable Spanned mSpanned; 919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The start offset of the target range in the original text (mSpanned); 939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @IntRange(from = 0) int mTextStart; 949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The length of the target range in the original text. 969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @IntRange(from = 0) int mTextLength; 979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The copied character buffer for measuring text. 999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // 1009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The length of this array is mTextLength. 1019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable char[] mCopiedBuffer; 1029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The whole paragraph direction. 1049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Layout.Direction int mParaDir; 1059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // True if the text is LTR direction and doesn't contain any bidi characters. 1079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private boolean mLtrWithoutBidi; 1089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The bidi level for individual characters. 1109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // 1119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // This is empty if mLtrWithoutBidi is true. 1129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @NonNull ByteArray mLevels = new ByteArray(); 1139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The whole width of the text. 1159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getWholeWidth comments. 1169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @FloatRange(from = 0.0f) float mWholeWidth; 1179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Individual characters' widths. 1199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getWidths comments. 1209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable FloatArray mWidths = new FloatArray(); 1219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The span end positions. 1239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getSpanEndCache comments. 1249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable IntArray mSpanEndCache = new IntArray(4); 1259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The font metrics. 1279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getFontMetrics comments. 1289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable IntArray mFontMetrics = new IntArray(4 * 4); 1299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The native MeasuredParagraph. 1319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // See getNativePtr comments. 1329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Do not modify these members directly. Use bindNativeObject/unbindNativeObject instead. 1339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private /* Maybe Zero */ long mNativePtr = 0; 1349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable Runnable mNativeObjectCleaner; 1359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Associate the native object to this Java object. 1379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void bindNativeObject(/* Non Zero*/ long nativePtr) { 1389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mNativePtr = nativePtr; 1399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mNativeObjectCleaner = sRegistry.registerNativeAllocation(this, nativePtr); 1409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Decouple the native object from this Java object and release the native object. 1439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void unbindNativeObject() { 1449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mNativePtr != 0) { 1459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mNativeObjectCleaner.run(); 1469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mNativePtr = 0; 1479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Following two objects are for avoiding object allocation. 1519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @NonNull TextPaint mCachedPaint = new TextPaint(); 1529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private @Nullable Paint.FontMetricsInt mCachedFm; 1539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 1559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Releases internal buffers. 1569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 1579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public void release() { 1589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka reset(); 1599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.clearWithReleasingLargeArray(); 1609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.clearWithReleasingLargeArray(); 1619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.clearWithReleasingLargeArray(); 1629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mSpanEndCache.clearWithReleasingLargeArray(); 1639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 1669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Resets the internal state for starting new text. 1679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 1689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void reset() { 1699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mSpanned = null; 1709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer = null; 1719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth = 0; 1729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.clear(); 1739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.clear(); 1749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.clear(); 1759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mSpanEndCache.clear(); 1769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka unbindNativeObject(); 1779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 180783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * Returns the length of the paragraph. 181783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * 182783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is always available. 183783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka */ 184783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka public int getTextLength() { 185783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka return mTextLength; 186783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } 187783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka 188783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka /** 1899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the characters to be measured. 1909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 1919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is always available. 1929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 1939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull char[] getChars() { 1949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mCopiedBuffer; 1959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 1989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the paragraph direction. 1999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is always available. 2019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @Layout.Direction int getParagraphDir() { 2039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mParaDir; 2049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the directions. 2089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is always available. 2109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public Directions getDirections(@IntRange(from = 0) int start, // inclusive 2129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end) { // exclusive 2139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mLtrWithoutBidi) { 2149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return Layout.DIRS_ALL_LEFT_TO_RIGHT; 2159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int length = end - start; 2189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return AndroidBidi.directions(mParaDir, mLevels.getRawArray(), start, mCopiedBuffer, start, 2199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka length); 2209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the whole text width. 2249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 225783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForMeasurement. 2269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns 0 in other cases. 2279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @FloatRange(from = 0.0f) float getWholeWidth() { 2299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mWholeWidth; 2309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the individual character's width. 2349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 235783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForMeasurement. 2369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns empty array in other cases. 2379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull FloatArray getWidths() { 2399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mWidths; 2409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the MetricsAffectingSpan end indices. 2449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If the input text is not a spanned string, this has one value that is the length of the text. 2469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 247783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForStaticLayout. 2489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns empty array in other cases. 2499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull IntArray getSpanEndCache() { 2519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mSpanEndCache; 2529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the int array which holds FontMetrics. 2569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This array holds the repeat of top, bottom, ascent, descent of font metrics value. 2589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 259783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForStaticLayout. 2609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns empty array in other cases. 2619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull IntArray getFontMetrics() { 2639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mFontMetrics; 2649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the native ptr of the MeasuredParagraph. 2689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 269783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForStaticLayout. 2709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns 0 in other cases. 2719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public /* Maybe Zero */ long getNativePtr() { 2739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mNativePtr; 2749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 277783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * Returns the width of the given range. 278783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * 279783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is not available if the MeasuredParagraph is computed with buildForBidi. 280783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * Returns 0 if the MeasuredParagraph is computed with buildForBidi. 281783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * 282783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * @param start the inclusive start offset of the target region in the text 283783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * @param end the exclusive end offset of the target region in the text 284783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka */ 285783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka public float getWidth(int start, int end) { 286783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka if (mNativePtr == 0) { 287783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka // We have result in Java. 288783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka final float[] widths = mWidths.getRawArray(); 289783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka float r = 0.0f; 290783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka for (int i = start; i < end; ++i) { 291783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka r += widths[i]; 292783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } 293783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka return r; 294783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } else { 295783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka // We have result in native. 296783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka return nGetWidth(mNativePtr, start, end); 297783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } 298783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } 299783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka 300783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka /** 301a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonaka * Retrieves the bounding rectangle that encloses all of the characters, with an implied origin 302a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonaka * at (0, 0). 303a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonaka * 304a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForStaticLayout. 305a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonaka */ 306fb0abe1feb2cadcee2a3edb2028e1da04bb8a8d5Seigo Nonaka public void getBounds(@IntRange(from = 0) int start, @IntRange(from = 0) int end, 307fb0abe1feb2cadcee2a3edb2028e1da04bb8a8d5Seigo Nonaka @NonNull Rect bounds) { 308fb0abe1feb2cadcee2a3edb2028e1da04bb8a8d5Seigo Nonaka nGetBounds(mNativePtr, mCopiedBuffer, start, end, bounds); 309a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonaka } 310a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonaka 311a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonaka /** 3129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Generates new MeasuredParagraph for Bidi computation. 3139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If recycle is null, this returns new instance. If recycle is not null, this fills computed 3159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * result to recycle and returns recycle. 3169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 3189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 3199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 3209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 3219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param recycle pass existing MeasuredParagraph if you want to recycle it. 3229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @return measured text 3249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 3259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public static @NonNull MeasuredParagraph buildForBidi(@NonNull CharSequence text, 3269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 3279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 3289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir, 3299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MeasuredParagraph recycle) { 3309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = recycle == null ? obtain() : recycle; 3319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.resetAndAnalyzeBidi(text, start, end, textDir); 3329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 3339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 3369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Generates new MeasuredParagraph for measuring texts. 3379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If recycle is null, this returns new instance. If recycle is not null, this fills computed 3399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * result to recycle and returns recycle. 3409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paint the paint to be used for rendering the text. 3429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 3439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 3449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 3459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 3469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param recycle pass existing MeasuredParagraph if you want to recycle it. 3479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @return measured text 3499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 3509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public static @NonNull MeasuredParagraph buildForMeasurement(@NonNull TextPaint paint, 3519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull CharSequence text, 3529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 3539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 3549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir, 3559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MeasuredParagraph recycle) { 3569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = recycle == null ? obtain() : recycle; 3579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.resetAndAnalyzeBidi(text, start, end, textDir); 3589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.mWidths.resize(mt.mTextLength); 3609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mTextLength == 0) { 3619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 3629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mSpanned == null) { 3659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // No style change by MetricsAffectingSpan. Just measure all text. 3669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan( 3679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka paint, null /* spans */, start, end, 0 /* native static layout ptr */); 3689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 3699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // There may be a MetricsAffectingSpan. Split into span transitions and apply styles. 3709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int spanEnd; 3719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int spanStart = start; spanStart < end; spanStart = spanEnd) { 3729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, MetricAffectingSpan.class); 3739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd, 3749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 3759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class); 3769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan( 3779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka paint, spans, spanStart, spanEnd, 0 /* native static layout ptr */); 3789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 3819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 3849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Generates new MeasuredParagraph for StaticLayout. 3859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If recycle is null, this returns new instance. If recycle is not null, this fills computed 3879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * result to recycle and returns recycle. 3889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paint the paint to be used for rendering the text. 3909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 3919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 3929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 3939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 3949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param recycle pass existing MeasuredParagraph if you want to recycle it. 3959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @return measured text 3979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 3989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public static @NonNull MeasuredParagraph buildForStaticLayout( 3999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextPaint paint, 4009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull CharSequence text, 4019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 4029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 4039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir, 40487b1547c929190c77b6b2d779f1d992691f04d17Seigo Nonaka boolean computeHyphenation, 405783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka boolean computeLayout, 4069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MeasuredParagraph recycle) { 4079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = recycle == null ? obtain() : recycle; 4089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.resetAndAnalyzeBidi(text, start, end, textDir); 4099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mTextLength == 0) { 4109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Need to build empty native measured text for StaticLayout. 4119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // TODO: Stop creating empty measured text for empty lines. 4129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka long nativeBuilderPtr = nInitBuilder(); 4139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka try { 4149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.bindNativeObject( 41587b1547c929190c77b6b2d779f1d992691f04d17Seigo Nonaka nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer, 416783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka computeHyphenation, computeLayout)); 4179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } finally { 4189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nFreeBuilder(nativeBuilderPtr); 4199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 4219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka long nativeBuilderPtr = nInitBuilder(); 4249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka try { 4259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mSpanned == null) { 4269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // No style change by MetricsAffectingSpan. Just measure all text. 4279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, nativeBuilderPtr); 4289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.mSpanEndCache.append(end); 4299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 4309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // There may be a MetricsAffectingSpan. Split into span transitions and apply 4319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // styles. 4329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int spanEnd; 4339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int spanStart = start; spanStart < end; spanStart = spanEnd) { 4349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, 4359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 4369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd, 4379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 4389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, 4399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 4409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd, 4419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nativeBuilderPtr); 4429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.mSpanEndCache.append(spanEnd); 4439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 44587b1547c929190c77b6b2d779f1d992691f04d17Seigo Nonaka mt.bindNativeObject(nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer, 446783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka computeHyphenation, computeLayout)); 4479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } finally { 4489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nFreeBuilder(nativeBuilderPtr); 4499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 4529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 4559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Reset internal state and analyzes text for bidirectional runs. 4569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 4579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 4589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 4599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 4609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 4619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 4629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void resetAndAnalyzeBidi(@NonNull CharSequence text, 4639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, // inclusive 4649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive 4659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir) { 4669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka reset(); 4679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mSpanned = text instanceof Spanned ? (Spanned) text : null; 4689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mTextStart = start; 4699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mTextLength = end - start; 4709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mCopiedBuffer == null || mCopiedBuffer.length != mTextLength) { 4729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer = new char[mTextLength]; 4739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka TextUtils.getChars(text, start, end, mCopiedBuffer, 0); 4759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Replace characters associated with ReplacementSpan to U+FFFC. 4779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mSpanned != null) { 4789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka ReplacementSpan[] spans = mSpanned.getSpans(start, end, ReplacementSpan.class); 4799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int i = 0; i < spans.length; i++) { 4819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int startInPara = mSpanned.getSpanStart(spans[i]) - start; 4829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int endInPara = mSpanned.getSpanEnd(spans[i]) - start; 4839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The span interval may be larger and must be restricted to [start, end) 4849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (startInPara < 0) startInPara = 0; 4859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (endInPara > mTextLength) endInPara = mTextLength; 4869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka Arrays.fill(mCopiedBuffer, startInPara, endInPara, OBJECT_REPLACEMENT_CHARACTER); 4879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if ((textDir == TextDirectionHeuristics.LTR 4919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka || textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR 4929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka || textDir == TextDirectionHeuristics.ANYRTL_LTR) 4939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka && TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) { 4949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.clear(); 4959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mParaDir = Layout.DIR_LEFT_TO_RIGHT; 4969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLtrWithoutBidi = true; 4979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 4989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int bidiRequest; 4999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (textDir == TextDirectionHeuristics.LTR) { 5009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_LTR; 5019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else if (textDir == TextDirectionHeuristics.RTL) { 5029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_RTL; 5039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) { 5049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR; 5059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) { 5069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL; 5079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength); 5099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR; 5109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.resize(mTextLength); 5129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mParaDir = AndroidBidi.bidi(bidiRequest, mCopiedBuffer, mLevels.getRawArray()); 5139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLtrWithoutBidi = false; 5149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void applyReplacementRun(@NonNull ReplacementSpan replacement, 5189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, // inclusive, in copied buffer 5199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive, in copied buffer 5209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Maybe Zero */ long nativeBuilderPtr) { 5219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Use original text. Shouldn't matter. 5229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for 5239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // backward compatibility? or Should we initialize them for getFontMetricsInt? 5249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final float width = replacement.getSize( 5259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm); 5269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr == 0) { 5279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Assigns all width to the first character. This is the same behavior as minikin. 5289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.set(start, width); 5299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (end > start + 1) { 5309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka Arrays.fill(mWidths.getRawArray(), start + 1, end, 0.0f); 5319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth += width; 5339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nAddReplacementRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end, 5359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width); 5369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void applyStyleRun(@IntRange(from = 0) int start, // inclusive, in copied buffer 5409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive, in copied buffer 5419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Maybe Zero */ long nativeBuilderPtr) { 5429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mLtrWithoutBidi) { 5449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // If the whole text is LTR direction, just apply whole region. 5459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr == 0) { 5469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth += mCachedPaint.getTextRunAdvances( 5479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */, 5489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.getRawArray(), start); 5499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end, 5519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka false /* isRtl */); 5529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // If there is multiple bidi levels, split into individual bidi level and apply style. 5559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka byte level = mLevels.get(start); 5569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Note that the empty text or empty range won't reach this method. 5579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Safe to search from start + 1. 5589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int levelStart = start, levelEnd = start + 1;; ++levelEnd) { 5599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (levelEnd == end || mLevels.get(levelEnd) != level) { // transition point 5609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final boolean isRtl = (level & 0x1) != 0; 5619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr == 0) { 5629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int levelLength = levelEnd - levelStart; 5639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth += mCachedPaint.getTextRunAdvances( 5649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer, levelStart, levelLength, levelStart, levelLength, 5659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka isRtl, mWidths.getRawArray(), levelStart); 5669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), levelStart, 5689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka levelEnd, isRtl); 5699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (levelEnd == end) { 5719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka break; 5729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka levelStart = levelEnd; 5749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka level = mLevels.get(levelEnd); 5759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void applyMetricsAffectingSpan( 5819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextPaint paint, 5829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MetricAffectingSpan[] spans, 5839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, // inclusive, in original text buffer 5849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive, in original text buffer 5859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Maybe Zero */ long nativeBuilderPtr) { 5869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint.set(paint); 5879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // XXX paint should not have a baseline shift, but... 5889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint.baselineShift = 0; 5899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final boolean needFontMetrics = nativeBuilderPtr != 0; 5919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (needFontMetrics && mCachedFm == null) { 5939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm = new Paint.FontMetricsInt(); 5949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka ReplacementSpan replacement = null; 5979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (spans != null) { 5989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int i = 0; i < spans.length; i++) { 5999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan span = spans[i]; 6009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (span instanceof ReplacementSpan) { 6019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The last ReplacementSpan is effective for backward compatibility reasons. 6029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka replacement = (ReplacementSpan) span; 6039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 6049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // TODO: No need to call updateMeasureState for ReplacementSpan as well? 6059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka span.updateMeasureState(mCachedPaint); 6069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int startInCopiedBuffer = start - mTextStart; 6119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int endInCopiedBuffer = end - mTextStart; 6129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6130903665f97435d27a893d45927e4a019008cadd6Seigo Nonaka if (nativeBuilderPtr != 0) { 6140903665f97435d27a893d45927e4a019008cadd6Seigo Nonaka mCachedPaint.getFontMetricsInt(mCachedFm); 6150903665f97435d27a893d45927e4a019008cadd6Seigo Nonaka } 6160903665f97435d27a893d45927e4a019008cadd6Seigo Nonaka 6179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (replacement != null) { 6189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, 6199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nativeBuilderPtr); 6209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 6219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, nativeBuilderPtr); 6229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (needFontMetrics) { 6259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mCachedPaint.baselineShift < 0) { 6269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.ascent += mCachedPaint.baselineShift; 6279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.top += mCachedPaint.baselineShift; 6289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 6299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.descent += mCachedPaint.baselineShift; 6309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.bottom += mCachedPaint.baselineShift; 6319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.top); 6349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.bottom); 6359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.ascent); 6369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.descent); 6379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 6419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the maximum index that the accumulated width not exceeds the width. 6429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 6439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If forward=false is passed, returns the minimum index from the end instead. 6449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 645783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This only works if the MeasuredParagraph is computed with buildForMeasurement. 6469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Undefined behavior in other case. 6479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 6489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int breakText(int limit, boolean forwards, float width) { 6499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka float[] w = mWidths.getRawArray(); 6509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (forwards) { 6519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int i = 0; 6529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i < limit) { 6539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width -= w[i]; 6549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (width < 0.0f) break; 6559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka i++; 6569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i > 0 && mCopiedBuffer[i - 1] == ' ') i--; 6589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return i; 6599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 6609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int i = limit - 1; 6619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i >= 0) { 6629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width -= w[i]; 6639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (width < 0.0f) break; 6649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka i--; 6659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i < limit - 1 && (mCopiedBuffer[i + 1] == ' ' || w[i + 1] == 0.0f)) { 6679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka i++; 6689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return limit - i - 1; 6709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 6749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the length of the substring. 6759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 676783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This only works if the MeasuredParagraph is computed with buildForMeasurement. 6779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Undefined behavior in other case. 6789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 6799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @FloatRange(from = 0.0f) float measure(int start, int limit) { 6809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka float width = 0; 6819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka float[] w = mWidths.getRawArray(); 6829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int i = start; i < limit; ++i) { 6839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width += w[i]; 6849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return width; 6869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 68849ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka /** 68949ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka * This only works if the MeasuredParagraph is computed with buildForStaticLayout. 69049ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka */ 691c3328d648e827c8a65f46ed3a8b0ec96076b5ebeSeigo Nonaka public @IntRange(from = 0) int getMemoryUsage() { 69249ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka return nGetMemoryUsage(mNativePtr); 69349ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka } 69449ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka 6959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native /* Non Zero */ long nInitBuilder(); 6969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 6989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Apply style to make native measured text. 6999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 7009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param nativeBuilderPtr The native MeasuredParagraph builder pointer. 7019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paintPtr The native paint pointer to be applied. 7029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start The start offset in the copied buffer. 7039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end The end offset in the copied buffer. 7049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param isRtl True if the text is RTL. 7059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 7069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr, 7079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Non Zero */ long paintPtr, 7089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 7099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 7109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka boolean isRtl); 7119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 7129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 7139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Apply ReplacementRun to make native measured text. 7149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 7159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param nativeBuilderPtr The native MeasuredParagraph builder pointer. 7169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paintPtr The native paint pointer to be applied. 7179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start The start offset in the copied buffer. 7189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end The end offset in the copied buffer. 7199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param width The width of the replacement. 7209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 7219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native void nAddReplacementRun(/* Non Zero */ long nativeBuilderPtr, 7229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Non Zero */ long paintPtr, 7239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 7249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 7259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @FloatRange(from = 0) float width); 7269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 7279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native long nBuildNativeMeasuredParagraph(/* Non Zero */ long nativeBuilderPtr, 72887b1547c929190c77b6b2d779f1d992691f04d17Seigo Nonaka @NonNull char[] text, 729783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka boolean computeHyphenation, 730783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka boolean computeLayout); 7319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 7329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr); 7339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 7349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @CriticalNative 735783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka private static native float nGetWidth(/* Non Zero */ long nativePtr, 736783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka @IntRange(from = 0) int start, 737783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka @IntRange(from = 0) int end); 738783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka 739783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka @CriticalNative 7409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native /* Non Zero */ long nGetReleaseFunc(); 74149ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka 74249ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka @CriticalNative 74349ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka private static native int nGetMemoryUsage(/* Non Zero */ long nativePtr); 744a553477ddf55d170a66410ed325ae5e5d3005965Seigo Nonaka 745fb0abe1feb2cadcee2a3edb2028e1da04bb8a8d5Seigo Nonaka private static native void nGetBounds(long nativePtr, char[] buf, int start, int end, 746fb0abe1feb2cadcee2a3edb2028e1da04bb8a8d5Seigo Nonaka Rect rect); 7479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka} 748