Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da183ef7 authored by Seigo Nonaka's avatar Seigo Nonaka Committed by Android (Google) Code Review
Browse files

Merge "Use ICU Bidi instead of own implementation" into main

parents d26b5778 a636a77a
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+103 −0
Original line number Diff line number Diff line
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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(),
    };

    /**
+7 −0
Original line number Diff line number Diff line
@@ -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"
}