Loading core/java/android/text/ClientFlags.java +7 −0 Original line number Diff line number Diff line Loading @@ -54,4 +54,11 @@ public class ClientFlags { public static boolean fixLineHeightForLocale() { return TextFlags.isFeatureEnabled(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE); } /** * @see Flags#icuBidiMigration() */ public static boolean icuBidiMigration() { return TextFlags.isFeatureEnabled(Flags.FLAG_ICU_BIDI_MIGRATION); } } core/java/android/text/MeasuredParagraph.java +103 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.text.LineBreakConfig; import android.graphics.text.MeasuredText; import android.icu.text.Bidi; import android.text.AutoGrowArray.ByteArray; import android.text.AutoGrowArray.FloatArray; import android.text.AutoGrowArray.IntArray; Loading Loading @@ -115,6 +116,11 @@ public class MeasuredParagraph { // This is empty if mLtrWithoutBidi is true. private @NonNull ByteArray mLevels = new ByteArray(); // The bidi level for runs. private @NonNull ByteArray mRunLevels = new ByteArray(); private Bidi mBidi; // The whole width of the text. // See getWholeWidth comments. private @FloatRange(from = 0.0f) float mWholeWidth; Loading Loading @@ -148,6 +154,7 @@ public class MeasuredParagraph { reset(); mLevels.clearWithReleasingLargeArray(); mWidths.clearWithReleasingLargeArray(); mRunLevels.clearWithReleasingLargeArray(); mFontMetrics.clearWithReleasingLargeArray(); mSpanEndCache.clearWithReleasingLargeArray(); } Loading @@ -160,10 +167,12 @@ public class MeasuredParagraph { mCopiedBuffer = null; mWholeWidth = 0; mLevels.clear(); mRunLevels.clear(); mWidths.clear(); mFontMetrics.clear(); mSpanEndCache.clear(); mMeasuredText = null; mBidi = null; } /** Loading Loading @@ -193,6 +202,13 @@ public class MeasuredParagraph { * @hide */ public @Layout.Direction int getParagraphDir() { if (ClientFlags.icuBidiMigration()) { if (mBidi == null) { return Layout.DIR_LEFT_TO_RIGHT; } return (mBidi.getParaLevel() & 0x01) == 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT; } return mParaDir; } Loading @@ -204,6 +220,62 @@ public class MeasuredParagraph { */ public Directions getDirections(@IntRange(from = 0) int start, // inclusive @IntRange(from = 0) int end) { // exclusive if (ClientFlags.icuBidiMigration()) { // Easy case: mBidi == null means the text is all LTR and no bidi suppot is needed. if (mBidi == null) { return Layout.DIRS_ALL_LEFT_TO_RIGHT; } // Easy case: If the original text only contains single directionality run, the // substring is only single run. if (start == end) { if ((mBidi.getParaLevel() & 0x01) == 0) { return Layout.DIRS_ALL_LEFT_TO_RIGHT; } else { return Layout.DIRS_ALL_RIGHT_TO_LEFT; } } // Okay, now we need to generate the line instance. Bidi bidi = mBidi.createLineBidi(start, end); // Easy case: If the line instance only contains single directionality run, no need // to reorder visually. if (bidi.getRunCount() == 1) { if ((bidi.getParaLevel() & 0x01) == 1) { return Layout.DIRS_ALL_RIGHT_TO_LEFT; } else { return Layout.DIRS_ALL_LEFT_TO_RIGHT; } } // Reorder directionality run visually. mRunLevels.resize(bidi.getRunCount()); byte[] levels = mRunLevels.getRawArray(); for (int i = 0; i < bidi.getRunCount(); ++i) { levels[i] = (byte) bidi.getRunLevel(i); } int[] visualOrders = Bidi.reorderVisual(levels); int[] dirs = new int[bidi.getRunCount() * 2]; for (int i = 0; i < bidi.getRunCount(); ++i) { int vIndex; if ((mBidi.getBaseLevel() & 0x01) == 1) { // For the historical reasons, if the base directionality is RTL, the Android // draws from the right, i.e. the visually reordered run needs to be reversed. vIndex = visualOrders[bidi.getRunCount() - i - 1]; } else { vIndex = visualOrders[i]; } // Special packing of dire dirs[i * 2] = bidi.getRunStart(vIndex); dirs[i * 2 + 1] = bidi.getRunLevel(vIndex) << Layout.RUN_LEVEL_SHIFT | (bidi.getRunLimit(vIndex) - dirs[i * 2]); } return new Directions(dirs); } if (mLtrWithoutBidi) { return Layout.DIRS_ALL_LEFT_TO_RIGHT; } Loading Loading @@ -608,6 +680,37 @@ public class MeasuredParagraph { } } if (ClientFlags.icuBidiMigration()) { if ((textDir == TextDirectionHeuristics.LTR || textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR || textDir == TextDirectionHeuristics.ANYRTL_LTR) && TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) { mLevels.clear(); mLtrWithoutBidi = true; return; } final int bidiRequest; if (textDir == TextDirectionHeuristics.LTR) { bidiRequest = Bidi.LTR; } else if (textDir == TextDirectionHeuristics.RTL) { bidiRequest = Bidi.RTL; } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) { bidiRequest = Bidi.LEVEL_DEFAULT_LTR; } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) { bidiRequest = Bidi.LEVEL_DEFAULT_RTL; } else { final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength); bidiRequest = isRtl ? Bidi.RTL : Bidi.LTR; } mBidi = new Bidi(mCopiedBuffer, 0, null, 0, mCopiedBuffer.length, bidiRequest); mLevels.resize(mTextLength); byte[] rawArray = mLevels.getRawArray(); for (int i = 0; i < mTextLength; ++i) { rawArray[i] = mBidi.getLevelAt(i); } mLtrWithoutBidi = false; return; } if ((textDir == TextDirectionHeuristics.LTR || textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR || textDir == TextDirectionHeuristics.ANYRTL_LTR) Loading core/java/android/text/TextFlags.java +2 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ public final class TextFlags { Flags.FLAG_PHRASE_STRICT_FALLBACK, Flags.FLAG_USE_BOUNDS_FOR_WIDTH, Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE, Flags.FLAG_ICU_BIDI_MIGRATION, }; /** Loading @@ -71,6 +72,7 @@ public final class TextFlags { Flags.phraseStrictFallback(), Flags.useBoundsForWidth(), Flags.fixLineHeightForLocale(), Flags.icuBidiMigration(), }; /** Loading core/java/android/text/flags/flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -103,3 +103,10 @@ flag { description: "Fix that InputService#onUpdateSelection is not called when insert mode gesture is performed." bug: "300850862" } flag { name: "icu_bidi_migration" namespace: "text" description: "A flag for replacing AndroidBidi with android.icu.text.Bidi." bug: "317144801" } Loading
core/java/android/text/ClientFlags.java +7 −0 Original line number Diff line number Diff line Loading @@ -54,4 +54,11 @@ public class ClientFlags { public static boolean fixLineHeightForLocale() { return TextFlags.isFeatureEnabled(Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE); } /** * @see Flags#icuBidiMigration() */ public static boolean icuBidiMigration() { return TextFlags.isFeatureEnabled(Flags.FLAG_ICU_BIDI_MIGRATION); } }
core/java/android/text/MeasuredParagraph.java +103 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.text.LineBreakConfig; import android.graphics.text.MeasuredText; import android.icu.text.Bidi; import android.text.AutoGrowArray.ByteArray; import android.text.AutoGrowArray.FloatArray; import android.text.AutoGrowArray.IntArray; Loading Loading @@ -115,6 +116,11 @@ public class MeasuredParagraph { // This is empty if mLtrWithoutBidi is true. private @NonNull ByteArray mLevels = new ByteArray(); // The bidi level for runs. private @NonNull ByteArray mRunLevels = new ByteArray(); private Bidi mBidi; // The whole width of the text. // See getWholeWidth comments. private @FloatRange(from = 0.0f) float mWholeWidth; Loading Loading @@ -148,6 +154,7 @@ public class MeasuredParagraph { reset(); mLevels.clearWithReleasingLargeArray(); mWidths.clearWithReleasingLargeArray(); mRunLevels.clearWithReleasingLargeArray(); mFontMetrics.clearWithReleasingLargeArray(); mSpanEndCache.clearWithReleasingLargeArray(); } Loading @@ -160,10 +167,12 @@ public class MeasuredParagraph { mCopiedBuffer = null; mWholeWidth = 0; mLevels.clear(); mRunLevels.clear(); mWidths.clear(); mFontMetrics.clear(); mSpanEndCache.clear(); mMeasuredText = null; mBidi = null; } /** Loading Loading @@ -193,6 +202,13 @@ public class MeasuredParagraph { * @hide */ public @Layout.Direction int getParagraphDir() { if (ClientFlags.icuBidiMigration()) { if (mBidi == null) { return Layout.DIR_LEFT_TO_RIGHT; } return (mBidi.getParaLevel() & 0x01) == 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT; } return mParaDir; } Loading @@ -204,6 +220,62 @@ public class MeasuredParagraph { */ public Directions getDirections(@IntRange(from = 0) int start, // inclusive @IntRange(from = 0) int end) { // exclusive if (ClientFlags.icuBidiMigration()) { // Easy case: mBidi == null means the text is all LTR and no bidi suppot is needed. if (mBidi == null) { return Layout.DIRS_ALL_LEFT_TO_RIGHT; } // Easy case: If the original text only contains single directionality run, the // substring is only single run. if (start == end) { if ((mBidi.getParaLevel() & 0x01) == 0) { return Layout.DIRS_ALL_LEFT_TO_RIGHT; } else { return Layout.DIRS_ALL_RIGHT_TO_LEFT; } } // Okay, now we need to generate the line instance. Bidi bidi = mBidi.createLineBidi(start, end); // Easy case: If the line instance only contains single directionality run, no need // to reorder visually. if (bidi.getRunCount() == 1) { if ((bidi.getParaLevel() & 0x01) == 1) { return Layout.DIRS_ALL_RIGHT_TO_LEFT; } else { return Layout.DIRS_ALL_LEFT_TO_RIGHT; } } // Reorder directionality run visually. mRunLevels.resize(bidi.getRunCount()); byte[] levels = mRunLevels.getRawArray(); for (int i = 0; i < bidi.getRunCount(); ++i) { levels[i] = (byte) bidi.getRunLevel(i); } int[] visualOrders = Bidi.reorderVisual(levels); int[] dirs = new int[bidi.getRunCount() * 2]; for (int i = 0; i < bidi.getRunCount(); ++i) { int vIndex; if ((mBidi.getBaseLevel() & 0x01) == 1) { // For the historical reasons, if the base directionality is RTL, the Android // draws from the right, i.e. the visually reordered run needs to be reversed. vIndex = visualOrders[bidi.getRunCount() - i - 1]; } else { vIndex = visualOrders[i]; } // Special packing of dire dirs[i * 2] = bidi.getRunStart(vIndex); dirs[i * 2 + 1] = bidi.getRunLevel(vIndex) << Layout.RUN_LEVEL_SHIFT | (bidi.getRunLimit(vIndex) - dirs[i * 2]); } return new Directions(dirs); } if (mLtrWithoutBidi) { return Layout.DIRS_ALL_LEFT_TO_RIGHT; } Loading Loading @@ -608,6 +680,37 @@ public class MeasuredParagraph { } } if (ClientFlags.icuBidiMigration()) { if ((textDir == TextDirectionHeuristics.LTR || textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR || textDir == TextDirectionHeuristics.ANYRTL_LTR) && TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) { mLevels.clear(); mLtrWithoutBidi = true; return; } final int bidiRequest; if (textDir == TextDirectionHeuristics.LTR) { bidiRequest = Bidi.LTR; } else if (textDir == TextDirectionHeuristics.RTL) { bidiRequest = Bidi.RTL; } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) { bidiRequest = Bidi.LEVEL_DEFAULT_LTR; } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) { bidiRequest = Bidi.LEVEL_DEFAULT_RTL; } else { final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength); bidiRequest = isRtl ? Bidi.RTL : Bidi.LTR; } mBidi = new Bidi(mCopiedBuffer, 0, null, 0, mCopiedBuffer.length, bidiRequest); mLevels.resize(mTextLength); byte[] rawArray = mLevels.getRawArray(); for (int i = 0; i < mTextLength; ++i) { rawArray[i] = mBidi.getLevelAt(i); } mLtrWithoutBidi = false; return; } if ((textDir == TextDirectionHeuristics.LTR || textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR || textDir == TextDirectionHeuristics.ANYRTL_LTR) Loading
core/java/android/text/TextFlags.java +2 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ public final class TextFlags { Flags.FLAG_PHRASE_STRICT_FALLBACK, Flags.FLAG_USE_BOUNDS_FOR_WIDTH, Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE, Flags.FLAG_ICU_BIDI_MIGRATION, }; /** Loading @@ -71,6 +72,7 @@ public final class TextFlags { Flags.phraseStrictFallback(), Flags.useBoundsForWidth(), Flags.fixLineHeightForLocale(), Flags.icuBidiMigration(), }; /** Loading
core/java/android/text/flags/flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -103,3 +103,10 @@ flag { description: "Fix that InputService#onUpdateSelection is not called when insert mode gesture is performed." bug: "300850862" } flag { name: "icu_bidi_migration" namespace: "text" description: "A flag for replacing AndroidBidi with android.icu.text.Bidi." bug: "317144801" }