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

Commit bd3eda61 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refactor TextLine class"

parents c1d607e9 888dbca2
Loading
Loading
Loading
Loading
+46 −0
Original line number Original line Diff line number Diff line
@@ -2360,6 +2360,52 @@ public abstract class Layout {
        public Directions(int[] dirs) {
        public Directions(int[] dirs) {
            mDirections = dirs;
            mDirections = dirs;
        }
        }

        /**
         * Returns number of BiDi runs.
         *
         * @hide
         */
        public @IntRange(from = 0) int getRunCount() {
            return mDirections.length / 2;
        }

        /**
         * Returns the start offset of the BiDi run.
         *
         * @param runIndex the index of the BiDi run
         * @return the start offset of the BiDi run.
         * @hide
         */
        public @IntRange(from = 0) int getRunStart(@IntRange(from = 0) int runIndex) {
            return mDirections[runIndex * 2];
        }

        /**
         * Returns the length of the BiDi run.
         *
         * Note that this method may return too large number due to reducing the number of object
         * allocations. The too large number means the remaining part is assigned to this run. The
         * caller must clamp the returned value.
         *
         * @param runIndex the index of the BiDi run
         * @return the length of the BiDi run.
         * @hide
         */
        public @IntRange(from = 0) int getRunLength(@IntRange(from = 0) int runIndex) {
            return mDirections[runIndex * 2 + 1] & RUN_LENGTH_MASK;
        }

        /**
         * Returns true if the BiDi run is RTL.
         *
         * @param runIndex the index of the BiDi run
         * @return true if the BiDi run is RTL.
         * @hide
         */
        public boolean isRunRtl(int runIndex) {
            return (mDirections[runIndex * 2 + 1] & RUN_RTL_FLAG) != 0;
        }
    }
    }


    /**
    /**
+94 −142
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package android.text;
package android.text;


import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.annotation.UnsupportedAppUsage;
@@ -51,6 +52,8 @@ import java.util.ArrayList;
public class TextLine {
public class TextLine {
    private static final boolean DEBUG = false;
    private static final boolean DEBUG = false;


    private static final char TAB_CHAR = '\t';

    private TextPaint mPaint;
    private TextPaint mPaint;
    @UnsupportedAppUsage
    @UnsupportedAppUsage
    private CharSequence mText;
    private CharSequence mText;
@@ -232,6 +235,10 @@ public class TextLine {
        mEllipsisEnd = ellipsisStart != ellipsisEnd ? ellipsisEnd : 0;
        mEllipsisEnd = ellipsisStart != ellipsisEnd ? ellipsisEnd : 0;
    }
    }


    private char charAt(int i) {
        return mCharsValid ? mChars[i] : mText.charAt(i + mStart);
    }

    /**
    /**
     * Justify the line to the given width.
     * Justify the line to the given width.
     */
     */
@@ -261,51 +268,23 @@ public class TextLine {
     * @param bottom the bottom of the line
     * @param bottom the bottom of the line
     */
     */
    void draw(Canvas c, float x, int top, int y, int bottom) {
    void draw(Canvas c, float x, int top, int y, int bottom) {
        if (!mHasTabs) {
            if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
                drawRun(c, 0, mLen, false, x, top, y, bottom, false);
                return;
            }
            if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
                drawRun(c, 0, mLen, true, x, top, y, bottom, false);
                return;
            }
        }

        float h = 0;
        float h = 0;
        int[] runs = mDirections.mDirections;
        final int runCount = mDirections.getRunCount();
        for (int runIndex = 0; runIndex < runCount; runIndex++) {
            final int runStart = mDirections.getRunStart(runIndex);
            final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
            final boolean runIsRtl = mDirections.isRunRtl(runIndex);


        int lastRunIndex = runs.length - 2;
            int segStart = runStart;
        for (int i = 0; i < runs.length; i += 2) {
            int runStart = runs[i];
            int runLimit = runStart + (runs[i+1] & Layout.RUN_LENGTH_MASK);
            if (runLimit > mLen) {
                runLimit = mLen;
            }
            boolean runIsRtl = (runs[i+1] & Layout.RUN_RTL_FLAG) != 0;

            int segstart = runStart;
            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
                int codept = 0;
                if (j == runLimit || charAt(j) == TAB_CHAR) {
                if (mHasTabs && j < runLimit) {
                    h += drawRun(c, segStart, j, runIsRtl, x + h, top, y, bottom,
                    codept = mChars[j];
                            runIndex != (runCount - 1) || j != mLen);
                    if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) {
                        codept = Character.codePointAt(mChars, j);
                        if (codept > 0xFFFF) {
                            ++j;
                            continue;
                        }
                    }
                }


                if (j == runLimit || codept == '\t') {
                    if (j != runLimit) {  // charAt(j) == TAB_CHAR
                    h += drawRun(c, segstart, j, runIsRtl, x+h, top, y, bottom,
                            i != lastRunIndex || j != mLen);

                    if (codept == '\t') {
                        h = mDir * nextTab(h * mDir);
                        h = mDir * nextTab(h * mDir);
                    }
                    }
                    segstart = j + 1;
                    segStart = j + 1;
                }
                }
            }
            }
        }
        }
@@ -323,75 +302,81 @@ public class TextLine {
    }
    }


    /**
    /**
     * Returns information about a position on the line.
     * Returns the signed graphical offset from the leading margin.
     *
     *
     * @param offset the line-relative character offset, between 0 and the
     * Following examples are all for measuring offset=3. LX(e.g. L0, L1, ...) denotes a
     * line length, inclusive
     * character which has LTR BiDi property. On the other hand, RX(e.g. R0, R1, ...) denotes a
     * @param trailing true to measure the trailing edge of the character
     * character which has RTL BiDi property. Assuming all character has 1em width.
     * before offset, false to measure the leading edge of the character
     *
     * at offset.
     * Example 1: All LTR chars within LTR context
     * @param fmi receives metrics information about the requested
     *   Input Text (logical)  :   L0 L1 L2 L3 L4 L5 L6 L7 L8
     * character, can be null.
     *   Input Text (visual)   :   L0 L1 L2 L3 L4 L5 L6 L7 L8
     * @return the signed offset from the leading margin to the requested
     *   Output(trailing=true) :  |--------| (Returns 3em)
     * character edge.
     *   Output(trailing=false):  |--------| (Returns 3em)
     *
     * Example 2: All RTL chars within RTL context.
     *   Input Text (logical)  :   R0 R1 R2 R3 R4 R5 R6 R7 R8
     *   Input Text (visual)   :   R8 R7 R6 R5 R4 R3 R2 R1 R0
     *   Output(trailing=true) :                    |--------| (Returns -3em)
     *   Output(trailing=false):                    |--------| (Returns -3em)
     *
     * Example 3: BiDi chars within LTR context.
     *   Input Text (logical)  :   L0 L1 L2 R3 R4 R5 L6 L7 L8
     *   Input Text (visual)   :   L0 L1 L2 R5 R4 R3 L6 L7 L8
     *   Output(trailing=true) :  |-----------------| (Returns 6em)
     *   Output(trailing=false):  |--------| (Returns 3em)
     *
     * Example 4: BiDi chars within RTL context.
     *   Input Text (logical)  :   L0 L1 L2 R3 R4 R5 L6 L7 L8
     *   Input Text (visual)   :   L6 L7 L8 R5 R4 R3 L0 L1 L2
     *   Output(trailing=true) :           |-----------------| (Returns -6em)
     *   Output(trailing=false):                    |--------| (Returns -3em)
     *
     * @param offset the line-relative character offset, between 0 and the line length, inclusive
     * @param trailing no effect if the offset is not on the BiDi transition offset. If the offset
     *                 is on the BiDi transition offset and true is passed, the offset is regarded
     *                 as the edge of the trailing run's edge. If false, the offset is regarded as
     *                 the edge of the preceding run's edge. See example above.
     * @param fmi receives metrics information about the requested character, can be null
     * @return the signed graphical offset from the leading margin to the requested character edge.
     *         The positive value means the offset is right from the leading edge. The negative
     *         value means the offset is left from the leading edge.
     */
     */
    public float measure(int offset, boolean trailing, FontMetricsInt fmi) {
    public float measure(@IntRange(from = 0) int offset, boolean trailing,
        int target = trailing ? offset - 1 : offset;
            @NonNull FontMetricsInt fmi) {
        if (offset > mLen) {
            throw new IndexOutOfBoundsException(
                    "offset(" + offset + ") should be less than line limit(" + mLen + ")");
        }
        final int target = trailing ? offset - 1 : offset;
        if (target < 0) {
        if (target < 0) {
            return 0;
            return 0;
        }
        }


        float h = 0;
        float h = 0;
        for (int runIndex = 0; runIndex < mDirections.getRunCount(); runIndex++) {
            final int runStart = mDirections.getRunStart(runIndex);
            final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
            final boolean runIsRtl = mDirections.isRunRtl(runIndex);


        if (!mHasTabs) {
            int segStart = runStart;
            if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
                return measureRun(0, offset, mLen, false, fmi);
            }
            if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
                return measureRun(0, offset, mLen, true, fmi);
            }
        }

        char[] chars = mChars;
        int[] runs = mDirections.mDirections;
        for (int i = 0; i < runs.length; i += 2) {
            int runStart = runs[i];
            int runLimit = runStart + (runs[i+1] & Layout.RUN_LENGTH_MASK);
            if (runLimit > mLen) {
                runLimit = mLen;
            }
            boolean runIsRtl = (runs[i+1] & Layout.RUN_RTL_FLAG) != 0;

            int segstart = runStart;
            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
                int codept = 0;
                if (j == runLimit || charAt(j) == TAB_CHAR) {
                if (mHasTabs && j < runLimit) {
                    final boolean targetIsInThisSegment = target >= segStart && target < j;
                    codept = chars[j];
                    final boolean sameDirection = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
                    if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) {
                        codept = Character.codePointAt(chars, j);
                        if (codept > 0xFFFF) {
                            ++j;
                            continue;
                        }
                    }
                }

                if (j == runLimit || codept == '\t') {
                    boolean inSegment = target >= segstart && target < j;


                    boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
                    if (targetIsInThisSegment && sameDirection) {
                    if (inSegment && advance) {
                        return h + measureRun(segStart, offset, j, runIsRtl, fmi);
                        return h + measureRun(segstart, offset, j, runIsRtl, fmi);
                    }
                    }


                    float w = measureRun(segstart, j, j, runIsRtl, fmi);
                    final float segmentWidth = measureRun(segStart, j, j, runIsRtl, fmi);
                    h += advance ? w : -w;
                    h += sameDirection ? segmentWidth : -segmentWidth;


                    if (inSegment) {
                    if (targetIsInThisSegment) {
                        return h + measureRun(segstart, offset, j, runIsRtl, null);
                        return h + measureRun(segStart, offset, j, runIsRtl, null);
                    }
                    }


                    if (codept == '\t') {
                    if (j != runLimit) {  // charAt(j) == TAB_CHAR
                        if (offset == j) {
                        if (offset == j) {
                            return h;
                            return h;
                        }
                        }
@@ -401,7 +386,7 @@ public class TextLine {
                        }
                        }
                    }
                    }


                    segstart = j + 1;
                    segStart = j + 1;
                }
                }
            }
            }
        }
        }
@@ -426,62 +411,29 @@ public class TextLine {
        }
        }


        float h = 0;
        float h = 0;
        for (int runIndex = 0; runIndex < mDirections.getRunCount(); runIndex++) {
            final int runStart = mDirections.getRunStart(runIndex);
            final int runLimit = Math.min(runStart + mDirections.getRunLength(runIndex), mLen);
            final boolean runIsRtl = mDirections.isRunRtl(runIndex);


        if (!mHasTabs) {
            int segStart = runStart;
            if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
                for (int offset = 0; offset <= mLen; ++offset) {
                    measurement[offset] = measureRun(0, offset, mLen, false, fmi);
                }
                return measurement;
            }
            if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
                for (int offset = 0; offset <= mLen; ++offset) {
                    measurement[offset] = measureRun(0, offset, mLen, true, fmi);
                }
                return measurement;
            }
        }

        char[] chars = mChars;
        int[] runs = mDirections.mDirections;
        for (int i = 0; i < runs.length; i += 2) {
            int runStart = runs[i];
            int runLimit = runStart + (runs[i + 1] & Layout.RUN_LENGTH_MASK);
            if (runLimit > mLen) {
                runLimit = mLen;
            }
            boolean runIsRtl = (runs[i + 1] & Layout.RUN_RTL_FLAG) != 0;

            int segstart = runStart;
            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; ++j) {
            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; ++j) {
                int codept = 0;
                if (j == runLimit || charAt(j) == TAB_CHAR) {
                if (mHasTabs && j < runLimit) {
                    final  float oldh = h;
                    codept = chars[j];
                    final boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
                    if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) {
                    final float w = measureRun(segStart, j, j, runIsRtl, fmi);
                        codept = Character.codePointAt(chars, j);
                        if (codept > 0xFFFF) {
                            ++j;
                            continue;
                        }
                    }
                }

                if (j == runLimit || codept == '\t') {
                    float oldh = h;
                    boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
                    float w = measureRun(segstart, j, j, runIsRtl, fmi);
                    h += advance ? w : -w;
                    h += advance ? w : -w;


                    float baseh = advance ? oldh : h;
                    final float baseh = advance ? oldh : h;
                    FontMetricsInt crtfmi = advance ? fmi : null;
                    FontMetricsInt crtfmi = advance ? fmi : null;
                    for (int offset = segstart; offset <= j && offset <= mLen; ++offset) {
                    for (int offset = segStart; offset <= j && offset <= mLen; ++offset) {
                        if (target[offset] >= segstart && target[offset] < j) {
                        if (target[offset] >= segStart && target[offset] < j) {
                            measurement[offset] =
                            measurement[offset] =
                                    baseh + measureRun(segstart, offset, j, runIsRtl, crtfmi);
                                    baseh + measureRun(segStart, offset, j, runIsRtl, crtfmi);
                        }
                        }
                    }
                    }


                    if (codept == '\t') {
                    if (j != runLimit) {  // charAt(j) == TAB_CHAR
                        if (target[j] == j) {
                        if (target[j] == j) {
                            measurement[j] = h;
                            measurement[j] = h;
                        }
                        }
@@ -491,7 +443,7 @@ public class TextLine {
                        }
                        }
                    }
                    }


                    segstart = j + 1;
                    segStart = j + 1;
                }
                }
            }
            }
        }
        }