MeasuredParagraph.java revision c3328d648e827c8a65f46ed3a8b0ec96076b5ebe
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 /** 179783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * Returns the length of the paragraph. 180783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * 181783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is always available. 182783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka */ 183783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka public int getTextLength() { 184783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka return mTextLength; 185783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } 186783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka 187783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka /** 1889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the characters to be measured. 1899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 1909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is always available. 1919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 1929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull char[] getChars() { 1939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mCopiedBuffer; 1949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 1959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 1969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 1979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the paragraph direction. 1989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 1999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is always available. 2009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @Layout.Direction int getParagraphDir() { 2029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mParaDir; 2039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the directions. 2079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This is always available. 2099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public Directions getDirections(@IntRange(from = 0) int start, // inclusive 2119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end) { // exclusive 2129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mLtrWithoutBidi) { 2139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return Layout.DIRS_ALL_LEFT_TO_RIGHT; 2149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int length = end - start; 2179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return AndroidBidi.directions(mParaDir, mLevels.getRawArray(), start, mCopiedBuffer, start, 2189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka length); 2199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the whole text width. 2239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 224783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForMeasurement. 2259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns 0 in other cases. 2269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @FloatRange(from = 0.0f) float getWholeWidth() { 2289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mWholeWidth; 2299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the individual character's width. 2339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 234783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForMeasurement. 2359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns empty array in other cases. 2369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull FloatArray getWidths() { 2389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mWidths; 2399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the MetricsAffectingSpan end indices. 2439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If the input text is not a spanned string, this has one value that is the length of the text. 2459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 246783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForStaticLayout. 2479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns empty array in other cases. 2489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull IntArray getSpanEndCache() { 2509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mSpanEndCache; 2519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the int array which holds FontMetrics. 2559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 2569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * This array holds the repeat of top, bottom, ascent, descent of font metrics value. 2579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 258783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForStaticLayout. 2599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns empty array in other cases. 2609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public @NonNull IntArray getFontMetrics() { 2629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mFontMetrics; 2639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 2669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the native ptr of the MeasuredParagraph. 2679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 268783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is available only if the MeasuredParagraph is computed with buildForStaticLayout. 2699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns 0 in other cases. 2709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 2719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public /* Maybe Zero */ long getNativePtr() { 2729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mNativePtr; 2739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 2749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 2759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 276783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * Returns the width of the given range. 277783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * 278783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This is not available if the MeasuredParagraph is computed with buildForBidi. 279783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * Returns 0 if the MeasuredParagraph is computed with buildForBidi. 280783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * 281783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * @param start the inclusive start offset of the target region in the text 282783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * @param end the exclusive end offset of the target region in the text 283783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka */ 284783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka public float getWidth(int start, int end) { 285783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka if (mNativePtr == 0) { 286783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka // We have result in Java. 287783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka final float[] widths = mWidths.getRawArray(); 288783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka float r = 0.0f; 289783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka for (int i = start; i < end; ++i) { 290783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka r += widths[i]; 291783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } 292783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka return r; 293783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } else { 294783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka // We have result in native. 295783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka return nGetWidth(mNativePtr, start, end); 296783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } 297783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka } 298783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka 299783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka /** 3009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Generates new MeasuredParagraph for Bidi computation. 3019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If recycle is null, this returns new instance. If recycle is not null, this fills computed 3039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * result to recycle and returns recycle. 3049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 3069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 3079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 3089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 3099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param recycle pass existing MeasuredParagraph if you want to recycle it. 3109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @return measured text 3129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 3139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public static @NonNull MeasuredParagraph buildForBidi(@NonNull CharSequence text, 3149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 3159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 3169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir, 3179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MeasuredParagraph recycle) { 3189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = recycle == null ? obtain() : recycle; 3199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.resetAndAnalyzeBidi(text, start, end, textDir); 3209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 3219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 3249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Generates new MeasuredParagraph for measuring texts. 3259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If recycle is null, this returns new instance. If recycle is not null, this fills computed 3279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * result to recycle and returns recycle. 3289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paint the paint to be used for rendering the text. 3309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 3319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 3329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 3339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 3349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param recycle pass existing MeasuredParagraph if you want to recycle it. 3359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @return measured text 3379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 3389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public static @NonNull MeasuredParagraph buildForMeasurement(@NonNull TextPaint paint, 3399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull CharSequence text, 3409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 3419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 3429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir, 3439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MeasuredParagraph recycle) { 3449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = recycle == null ? obtain() : recycle; 3459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.resetAndAnalyzeBidi(text, start, end, textDir); 3469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.mWidths.resize(mt.mTextLength); 3489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mTextLength == 0) { 3499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 3509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mSpanned == null) { 3539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // No style change by MetricsAffectingSpan. Just measure all text. 3549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan( 3559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka paint, null /* spans */, start, end, 0 /* native static layout ptr */); 3569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 3579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // There may be a MetricsAffectingSpan. Split into span transitions and apply styles. 3589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int spanEnd; 3599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int spanStart = start; spanStart < end; spanStart = spanEnd) { 3609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, MetricAffectingSpan.class); 3619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd, 3629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 3639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class); 3649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan( 3659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka paint, spans, spanStart, spanEnd, 0 /* native static layout ptr */); 3669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 3699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 3709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 3719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 3729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Generates new MeasuredParagraph for StaticLayout. 3739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If recycle is null, this returns new instance. If recycle is not null, this fills computed 3759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * result to recycle and returns recycle. 3769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paint the paint to be used for rendering the text. 3789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 3799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 3809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 3819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 3829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param recycle pass existing MeasuredParagraph if you want to recycle it. 3839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 3849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @return measured text 3859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 3869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka public static @NonNull MeasuredParagraph buildForStaticLayout( 3879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextPaint paint, 3889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull CharSequence text, 3899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 3909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 3919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir, 39287b1547c929190c77b6b2d779f1d992691f04d17Seigo Nonaka boolean computeHyphenation, 393783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka boolean computeLayout, 3949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MeasuredParagraph recycle) { 3959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final MeasuredParagraph mt = recycle == null ? obtain() : recycle; 3969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.resetAndAnalyzeBidi(text, start, end, textDir); 3979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mTextLength == 0) { 3989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Need to build empty native measured text for StaticLayout. 3999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // TODO: Stop creating empty measured text for empty lines. 4009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka long nativeBuilderPtr = nInitBuilder(); 4019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka try { 4029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.bindNativeObject( 40387b1547c929190c77b6b2d779f1d992691f04d17Seigo Nonaka nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer, 404783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka computeHyphenation, computeLayout)); 4059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } finally { 4069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nFreeBuilder(nativeBuilderPtr); 4079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 4099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka long nativeBuilderPtr = nInitBuilder(); 4129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka try { 4139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mt.mSpanned == null) { 4149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // No style change by MetricsAffectingSpan. Just measure all text. 4159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, nativeBuilderPtr); 4169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.mSpanEndCache.append(end); 4179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 4189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // There may be a MetricsAffectingSpan. Split into span transitions and apply 4199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // styles. 4209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int spanEnd; 4219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int spanStart = start; spanStart < end; spanStart = spanEnd) { 4229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, 4239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 4249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd, 4259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 4269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, 4279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan.class); 4289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd, 4299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nativeBuilderPtr); 4309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mt.mSpanEndCache.append(spanEnd); 4319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 43387b1547c929190c77b6b2d779f1d992691f04d17Seigo Nonaka mt.bindNativeObject(nBuildNativeMeasuredParagraph(nativeBuilderPtr, mt.mCopiedBuffer, 434783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka computeHyphenation, computeLayout)); 4359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } finally { 4369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nFreeBuilder(nativeBuilderPtr); 4379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return mt; 4409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 4439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Reset internal state and analyzes text for bidirectional runs. 4449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 4459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param text the character sequence to be measured 4469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start the inclusive start offset of the target region in the text 4479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end the exclusive end offset of the target region in the text 4489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param textDir the text direction 4499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 4509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void resetAndAnalyzeBidi(@NonNull CharSequence text, 4519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, // inclusive 4529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive 4539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextDirectionHeuristic textDir) { 4549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka reset(); 4559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mSpanned = text instanceof Spanned ? (Spanned) text : null; 4569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mTextStart = start; 4579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mTextLength = end - start; 4589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mCopiedBuffer == null || mCopiedBuffer.length != mTextLength) { 4609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer = new char[mTextLength]; 4619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka TextUtils.getChars(text, start, end, mCopiedBuffer, 0); 4639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Replace characters associated with ReplacementSpan to U+FFFC. 4659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mSpanned != null) { 4669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka ReplacementSpan[] spans = mSpanned.getSpans(start, end, ReplacementSpan.class); 4679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int i = 0; i < spans.length; i++) { 4699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int startInPara = mSpanned.getSpanStart(spans[i]) - start; 4709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int endInPara = mSpanned.getSpanEnd(spans[i]) - start; 4719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The span interval may be larger and must be restricted to [start, end) 4729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (startInPara < 0) startInPara = 0; 4739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (endInPara > mTextLength) endInPara = mTextLength; 4749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka Arrays.fill(mCopiedBuffer, startInPara, endInPara, OBJECT_REPLACEMENT_CHARACTER); 4759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 4789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if ((textDir == TextDirectionHeuristics.LTR 4799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka || textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR 4809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka || textDir == TextDirectionHeuristics.ANYRTL_LTR) 4819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka && TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) { 4829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.clear(); 4839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mParaDir = Layout.DIR_LEFT_TO_RIGHT; 4849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLtrWithoutBidi = true; 4859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 4869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int bidiRequest; 4879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (textDir == TextDirectionHeuristics.LTR) { 4889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_LTR; 4899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else if (textDir == TextDirectionHeuristics.RTL) { 4909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_RTL; 4919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) { 4929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR; 4939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) { 4949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL; 4959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 4969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength); 4979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR; 4989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 4999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLevels.resize(mTextLength); 5009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mParaDir = AndroidBidi.bidi(bidiRequest, mCopiedBuffer, mLevels.getRawArray()); 5019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mLtrWithoutBidi = false; 5029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void applyReplacementRun(@NonNull ReplacementSpan replacement, 5069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, // inclusive, in copied buffer 5079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive, in copied buffer 5089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Maybe Zero */ long nativeBuilderPtr) { 5099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Use original text. Shouldn't matter. 5109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for 5119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // backward compatibility? or Should we initialize them for getFontMetricsInt? 5129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final float width = replacement.getSize( 5139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm); 5149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr == 0) { 5159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Assigns all width to the first character. This is the same behavior as minikin. 5169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.set(start, width); 5179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (end > start + 1) { 5189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka Arrays.fill(mWidths.getRawArray(), start + 1, end, 0.0f); 5199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth += width; 5219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nAddReplacementRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end, 5239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width); 5249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void applyStyleRun(@IntRange(from = 0) int start, // inclusive, in copied buffer 5289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive, in copied buffer 5299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Maybe Zero */ long nativeBuilderPtr) { 5309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr != 0) { 5319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint.getFontMetricsInt(mCachedFm); 5329d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mLtrWithoutBidi) { 5359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // If the whole text is LTR direction, just apply whole region. 5369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr == 0) { 5379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth += mCachedPaint.getTextRunAdvances( 5389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */, 5399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWidths.getRawArray(), start); 5409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end, 5429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka false /* isRtl */); 5439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // If there is multiple bidi levels, split into individual bidi level and apply style. 5469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka byte level = mLevels.get(start); 5479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Note that the empty text or empty range won't reach this method. 5489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // Safe to search from start + 1. 5499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int levelStart = start, levelEnd = start + 1;; ++levelEnd) { 5509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (levelEnd == end || mLevels.get(levelEnd) != level) { // transition point 5519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final boolean isRtl = (level & 0x1) != 0; 5529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (nativeBuilderPtr == 0) { 5539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int levelLength = levelEnd - levelStart; 5549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mWholeWidth += mCachedPaint.getTextRunAdvances( 5559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCopiedBuffer, levelStart, levelLength, levelStart, levelLength, 5569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka isRtl, mWidths.getRawArray(), levelStart); 5579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), levelStart, 5599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka levelEnd, isRtl); 5609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (levelEnd == end) { 5629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka break; 5639d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka levelStart = levelEnd; 5659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka level = mLevels.get(levelEnd); 5669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private void applyMetricsAffectingSpan( 5729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @NonNull TextPaint paint, 5739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @Nullable MetricAffectingSpan[] spans, 5749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, // inclusive, in original text buffer 5759d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, // exclusive, in original text buffer 5769d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Maybe Zero */ long nativeBuilderPtr) { 5779d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint.set(paint); 5789d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // XXX paint should not have a baseline shift, but... 5799d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedPaint.baselineShift = 0; 5809d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5819d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final boolean needFontMetrics = nativeBuilderPtr != 0; 5829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (needFontMetrics && mCachedFm == null) { 5849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm = new Paint.FontMetricsInt(); 5859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 5879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka ReplacementSpan replacement = null; 5889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (spans != null) { 5899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int i = 0; i < spans.length; i++) { 5909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka MetricAffectingSpan span = spans[i]; 5919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (span instanceof ReplacementSpan) { 5929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // The last ReplacementSpan is effective for backward compatibility reasons. 5939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka replacement = (ReplacementSpan) span; 5949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 5959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka // TODO: No need to call updateMeasureState for ReplacementSpan as well? 5969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka span.updateMeasureState(mCachedPaint); 5979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 5999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int startInCopiedBuffer = start - mTextStart; 6029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka final int endInCopiedBuffer = end - mTextStart; 6039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (replacement != null) { 6059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, 6069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka nativeBuilderPtr); 6079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 6089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, nativeBuilderPtr); 6099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (needFontMetrics) { 6129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (mCachedPaint.baselineShift < 0) { 6139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.ascent += mCachedPaint.baselineShift; 6149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.top += mCachedPaint.baselineShift; 6159d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 6169d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.descent += mCachedPaint.baselineShift; 6179d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mCachedFm.bottom += mCachedPaint.baselineShift; 6189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.top); 6219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.bottom); 6229d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.ascent); 6239d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka mFontMetrics.append(mCachedFm.descent); 6249d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6259d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6269d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 6289d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the maximum index that the accumulated width not exceeds the width. 6299d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 6309d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * If forward=false is passed, returns the minimum index from the end instead. 6319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 632783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This only works if the MeasuredParagraph is computed with buildForMeasurement. 6339d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Undefined behavior in other case. 6349d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 6359d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int breakText(int limit, boolean forwards, float width) { 6369d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka float[] w = mWidths.getRawArray(); 6379d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (forwards) { 6389d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int i = 0; 6399d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i < limit) { 6409d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width -= w[i]; 6419d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (width < 0.0f) break; 6429d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka i++; 6439d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6449d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i > 0 && mCopiedBuffer[i - 1] == ' ') i--; 6459d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return i; 6469d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } else { 6479d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka int i = limit - 1; 6489d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i >= 0) { 6499d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width -= w[i]; 6509d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka if (width < 0.0f) break; 6519d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka i--; 6529d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6539d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka while (i < limit - 1 && (mCopiedBuffer[i + 1] == ' ' || w[i + 1] == 0.0f)) { 6549d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka i++; 6559d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6569d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return limit - i - 1; 6579d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6589d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6599d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6609d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 6619d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Returns the length of the substring. 6629d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 663783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka * This only works if the MeasuredParagraph is computed with buildForMeasurement. 6649d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Undefined behavior in other case. 6659d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 6669d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @FloatRange(from = 0.0f) float measure(int start, int limit) { 6679d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka float width = 0; 6689d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka float[] w = mWidths.getRawArray(); 6699d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka for (int i = start; i < limit; ++i) { 6709d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka width += w[i]; 6719d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6729d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka return width; 6739d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka } 6749d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 67549ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka /** 67649ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka * This only works if the MeasuredParagraph is computed with buildForStaticLayout. 67749ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka */ 678c3328d648e827c8a65f46ed3a8b0ec96076b5ebeSeigo Nonaka public @IntRange(from = 0) int getMemoryUsage() { 67949ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka return nGetMemoryUsage(mNativePtr); 68049ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka } 68149ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka 6829d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native /* Non Zero */ long nInitBuilder(); 6839d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6849d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 6859d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Apply style to make native measured text. 6869d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 6879d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param nativeBuilderPtr The native MeasuredParagraph builder pointer. 6889d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paintPtr The native paint pointer to be applied. 6899d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start The start offset in the copied buffer. 6909d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end The end offset in the copied buffer. 6919d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param isRtl True if the text is RTL. 6929d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 6939d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr, 6949d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Non Zero */ long paintPtr, 6959d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 6969d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 6979d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka boolean isRtl); 6989d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 6999d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /** 7009d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * Apply ReplacementRun to make native measured text. 7019d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * 7029d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param nativeBuilderPtr The native MeasuredParagraph builder pointer. 7039d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param paintPtr The native paint pointer to be applied. 7049d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param start The start offset in the copied buffer. 7059d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param end The end offset in the copied buffer. 7069d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka * @param width The width of the replacement. 7079d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka */ 7089d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native void nAddReplacementRun(/* Non Zero */ long nativeBuilderPtr, 7099d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka /* Non Zero */ long paintPtr, 7109d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int start, 7119d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @IntRange(from = 0) int end, 7129d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @FloatRange(from = 0) float width); 7139d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 7149d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native long nBuildNativeMeasuredParagraph(/* Non Zero */ long nativeBuilderPtr, 71587b1547c929190c77b6b2d779f1d992691f04d17Seigo Nonaka @NonNull char[] text, 716783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka boolean computeHyphenation, 717783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka boolean computeLayout); 7189d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 7199d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr); 7209d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka 7219d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka @CriticalNative 722783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka private static native float nGetWidth(/* Non Zero */ long nativePtr, 723783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka @IntRange(from = 0) int start, 724783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka @IntRange(from = 0) int end); 725783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka 726783f961d2fa6f916009844dafeaa08ffaf96a4d3Seigo Nonaka @CriticalNative 7279d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka private static native /* Non Zero */ long nGetReleaseFunc(); 72849ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka 72949ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka @CriticalNative 73049ca0244c9fa01dd667755cde6eb2342b8e2e05dSeigo Nonaka private static native int nGetMemoryUsage(/* Non Zero */ long nativePtr); 7319d3bd08ebab564ed9231c8ee112e8085cda74ce8Seigo Nonaka} 732