diff options
| -rw-r--r-- | core/java/android/text/ClientFlags.java | 7 | ||||
| -rw-r--r-- | core/java/android/text/MeasuredParagraph.java | 103 | ||||
| -rw-r--r-- | core/java/android/text/TextFlags.java | 2 | ||||
| -rw-r--r-- | core/java/android/text/flags/flags.aconfig | 7 |
4 files changed, 119 insertions, 0 deletions
diff --git a/core/java/android/text/ClientFlags.java b/core/java/android/text/ClientFlags.java index 0421d5aaa69b..32f05be5a83a 100644 --- a/core/java/android/text/ClientFlags.java +++ b/core/java/android/text/ClientFlags.java @@ -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); + } } diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java index b268c2edd9a7..09f15c3aca3e 100644 --- a/core/java/android/text/MeasuredParagraph.java +++ b/core/java/android/text/MeasuredParagraph.java @@ -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; @@ -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; @@ -148,6 +154,7 @@ public class MeasuredParagraph { reset(); mLevels.clearWithReleasingLargeArray(); mWidths.clearWithReleasingLargeArray(); + mRunLevels.clearWithReleasingLargeArray(); mFontMetrics.clearWithReleasingLargeArray(); mSpanEndCache.clearWithReleasingLargeArray(); } @@ -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; } /** @@ -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; } @@ -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; } @@ -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) diff --git a/core/java/android/text/TextFlags.java b/core/java/android/text/TextFlags.java index 24663862400d..770e5c97f50a 100644 --- a/core/java/android/text/TextFlags.java +++ b/core/java/android/text/TextFlags.java @@ -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, }; /** @@ -71,6 +72,7 @@ public final class TextFlags { Flags.phraseStrictFallback(), Flags.useBoundsForWidth(), Flags.fixLineHeightForLocale(), + Flags.icuBidiMigration(), }; /** diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig index f3e0ea780182..a49aee1d023d 100644 --- a/core/java/android/text/flags/flags.aconfig +++ b/core/java/android/text/flags/flags.aconfig @@ -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" +} |