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

Commit eb749119 authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Unhide Paint.getTextRunAdvances

This is necessary for getting individual character advances.

The only char[] version of getTextRunAdvances is used, so removing
String/CharSequence versions.

Bug: 112327179
Test: atest android.graphics.cts.PaintTest#testGetTextRunAdvances
Change-Id: Ic49a4742cccb2a5155f6afacef3555e29c7a061c
parent d75020c6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -14014,6 +14014,7 @@ package android.graphics {
    method public android.os.LocaleList getTextLocales();
    method public void getTextPath(char[], int, int, float, float, android.graphics.Path);
    method public void getTextPath(java.lang.String, int, int, float, float, android.graphics.Path);
    method public float getTextRunAdvances(char[], int, int, int, int, boolean, float[], int);
    method public float getTextScaleX();
    method public float getTextSize();
    method public float getTextSkewX();
+21 −56
Original line number Diff line number Diff line
@@ -186,44 +186,28 @@ public class PaintTest extends InstrumentationTestCase {
        Paint p = new Paint();

        final int count = end - start;
        final float[][] advanceArrays = new float[4][count];

        final float advance = p.getTextRunAdvances(str, start, end, contextStart, contextEnd,
                isRtl, advanceArrays[0], 0);

        final int contextCount = contextEnd - contextStart;
        final float[][] advanceArrays = new float[2][count];
        char chars[] = str.toCharArray();
        final float advance_c = p.getTextRunAdvances(chars, start, count, contextStart,
                contextEnd - contextStart, isRtl, advanceArrays[1], 0);
        assertEquals(advance, advance_c, 1.0f);

        final float advance = p.getTextRunAdvances(chars, start, count,
                contextStart, contextCount, isRtl, advanceArrays[0], 0);
        for (int c = 1; c < count; ++c) {
            final float firstPartAdvance = p.getTextRunAdvances(str, start, start + c,
                    contextStart, contextEnd, isRtl, advanceArrays[2], 0);
            final float secondPartAdvance = p.getTextRunAdvances(str, start + c, end,
                    contextStart, contextEnd, isRtl, advanceArrays[2], c);
            final float firstPartAdvance = p.getTextRunAdvances(chars, start, c,
                    contextStart, contextCount, isRtl, advanceArrays[1], 0);
            final float secondPartAdvance = p.getTextRunAdvances(chars, start + c, count - c,
                    contextStart, contextCount, isRtl, advanceArrays[1], c);
            assertEquals(advance, firstPartAdvance + secondPartAdvance, 1.0f);


            final float firstPartAdvance_c = p.getTextRunAdvances(chars, start, c,
                    contextStart, contextEnd - contextStart, isRtl, advanceArrays[3], 0);
            final float secondPartAdvance_c = p.getTextRunAdvances(chars, start + c,
                    count - c, contextStart, contextEnd - contextStart, isRtl,
                    advanceArrays[3], c);
            assertEquals(advance, firstPartAdvance_c + secondPartAdvance_c, 1.0f);
            assertEquals(firstPartAdvance, firstPartAdvance_c, 1.0f);
            assertEquals(secondPartAdvance, secondPartAdvance_c, 1.0f);

            for (int i = 1; i < advanceArrays.length; i++) {
            for (int j = 0; j < count; j++) {
                    assertEquals(advanceArrays[0][j], advanceArrays[i][j], 1.0f);
                }
                assertEquals(advanceArrays[0][j], advanceArrays[1][j], 1.0f);
            }


            // Compare results with measureText, getRunAdvance, and getTextWidths.
            if (compareWithOtherMethods && start == contextStart && end == contextEnd) {
                assertEquals(advance, p.measureText(str, start, end), 1.0f);
                assertEquals(advance, p.getRunAdvance(
                        str, start, end, contextStart, contextEnd, isRtl, end), 1.0f);
                        chars, start, count, contextStart, contextCount, isRtl, end), 1.0f);

                final float[] widths = new float[count];
                p.getTextWidths(str, start, end, widths);
@@ -236,19 +220,7 @@ public class PaintTest extends InstrumentationTestCase {

    public void testGetTextRunAdvances_invalid() {
        Paint p = new Paint();
        String text = "test";

        try {
            p.getTextRunAdvances((String)null, 0, 0, 0, 0, false, null, 0);
            fail("Should throw an IllegalArgumentException.");
        } catch (IllegalArgumentException e) {
        }

        try {
            p.getTextRunAdvances((CharSequence)null, 0, 0, 0, 0, false, null, 0);
            fail("Should throw an IllegalArgumentException.");
        } catch (IllegalArgumentException e) {
        }
        char[] text = "test".toCharArray();

        try {
            p.getTextRunAdvances((char[])null, 0, 0, 0, 0, false, null, 0);
@@ -257,50 +229,43 @@ public class PaintTest extends InstrumentationTestCase {
        }

        try {
            p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
                    new float[text.length() - 1], 0);
            p.getTextRunAdvances(text, 0, text.length, 0, text.length, false,
                    new float[text.length - 1], 0);
            fail("Should throw an IndexOutOfBoundsException.");
        } catch (IndexOutOfBoundsException e) {
        }

        try {
            p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
                    new float[text.length()], 1);
            p.getTextRunAdvances(text, 0, text.length, 0, text.length, false,
                    new float[text.length], 1);
            fail("Should throw an IndexOutOfBoundsException.");
        } catch (IndexOutOfBoundsException e) {
        }

        // 0 > contextStart
        try {
            p.getTextRunAdvances(text, 0, text.length(), -1, text.length(), false, null, 0);
            p.getTextRunAdvances(text, 0, text.length, -1, text.length, false, null, 0);
            fail("Should throw an IndexOutOfBoundsException.");
        } catch (IndexOutOfBoundsException e) {
        }

        // contextStart > start
        try {
            p.getTextRunAdvances(text, 0, text.length(), 1, text.length(), false, null, 0);
            fail("Should throw an IndexOutOfBoundsException.");
        } catch (IndexOutOfBoundsException e) {
        }

        // start > end
        try {
            p.getTextRunAdvances(text, 1, 0, 0, text.length(), false, null, 0);
            p.getTextRunAdvances(text, 0, text.length, 1, text.length, false, null, 0);
            fail("Should throw an IndexOutOfBoundsException.");
        } catch (IndexOutOfBoundsException e) {
        }

        // end > contextEnd
        try {
            p.getTextRunAdvances(text, 0, text.length(), 0, text.length() - 1, false, null, 0);
            p.getTextRunAdvances(text, 0, text.length, 0, text.length - 1, false, null, 0);
            fail("Should throw an IndexOutOfBoundsException.");
        } catch (IndexOutOfBoundsException e) {
        }

        // contextEnd > text.length
        try {
            p.getTextRunAdvances(text, 0, text.length(), 0, text.length() + 1, false, null, 0);
            p.getTextRunAdvances(text, 0, text.length, 0, text.length + 1, false, null, 0);
            fail("Should throw an IndexOutOfBoundsException.");
        } catch (IndexOutOfBoundsException e) {
        }
+48 −135
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@
package android.graphics;

import android.annotation.ColorInt;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Px;
import android.annotation.Size;
import android.annotation.UnsupportedAppUsage;
@@ -2325,17 +2327,53 @@ public class Paint {
    }

    /**
     * Convenience overload that takes a char array instead of a
     * String.
     * Retrieve the character advances of the text.
     *
     * @see #getTextRunAdvances(String, int, int, int, int, boolean, float[], int)
     * @hide
     */
    @UnsupportedAppUsage
    public float getTextRunAdvances(char[] chars, int index, int count,
            int contextIndex, int contextCount, boolean isRtl, float[] advances,
            int advancesIndex) {

     * Returns the total advance width for the characters in the run from {@code index} for
     * {@code count} of chars, and if {@code advances} is not null, the advance assigned to each of
     * these characters (java chars).
     *
     * <p>
     * The trailing surrogate in a valid surrogate pair is assigned an advance of 0.  Thus the
     * number of returned advances is always equal to count, not to the number of unicode codepoints
     * represented by the run.
     * </p>
     *
     * <p>
     * In the case of conjuncts or combining marks, the total advance is assigned to the first
     * logical character, and the following characters are assigned an advance of 0.
     * </p>
     *
     * <p>
     * This generates the sum of the advances of glyphs for characters in a reordered cluster as the
     * width of the first logical character in the cluster, and 0 for the widths of all other
     * characters in the cluster.  In effect, such clusters are treated like conjuncts.
     * </p>
     *
     * <p>
     * The shaping bounds limit the amount of context available outside start and end that can be
     * used for shaping analysis.  These bounds typically reflect changes in bidi level or font
     * metrics across which shaping does not occur.
     * </p>
     *
     * @param chars the text to measure.
     * @param index the index of the first character to measure
     * @param count the number of characters to measure
     * @param contextIndex the index of the first character to use for shaping context.
     *                     Context must cover the measureing target.
     * @param contextCount the number of character to use for shaping context.
     *                     Context must cover the measureing target.
     * @param isRtl whether the run is in RTL direction
     * @param advances array to receive the advances, must have room for all advances.
     *                 This can be null if only total advance is needed
     * @param advancesIndex the position in advances at which to put the advance corresponding to
     *                      the character at start
     * @return the total advance in pixels
     */
    public float getTextRunAdvances(@NonNull char[] chars, @IntRange(from = 0) int index,
            @IntRange(from = 0) int count, @IntRange(from = 0) int contextIndex,
            @IntRange(from = 0) int contextCount, boolean isRtl, @Nullable float[] advances,
            @IntRange(from = 0) int advancesIndex) {
        if (chars == null) {
            throw new IllegalArgumentException("text cannot be null");
        }
@@ -2371,131 +2409,6 @@ public class Paint {
        return res * mInvCompatScaling; // assume errors are not significant
    }

    /**
     * Convenience overload that takes a CharSequence instead of a
     * String.
     *
     * @see #getTextRunAdvances(String, int, int, int, int, boolean, float[], int)
     * @hide
     */
    public float getTextRunAdvances(CharSequence text, int start, int end,
            int contextStart, int contextEnd, boolean isRtl, float[] advances,
            int advancesIndex) {
        if (text == null) {
            throw new IllegalArgumentException("text cannot be null");
        }
        if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
                | (start - contextStart) | (contextEnd - end)
                | (text.length() - contextEnd)
                | (advances == null ? 0 :
                    (advances.length - advancesIndex - (end - start)))) < 0) {
            throw new IndexOutOfBoundsException();
        }

        if (text instanceof String) {
            return getTextRunAdvances((String) text, start, end,
                    contextStart, contextEnd, isRtl, advances, advancesIndex);
        }
        if (text instanceof SpannedString ||
            text instanceof SpannableString) {
            return getTextRunAdvances(text.toString(), start, end,
                    contextStart, contextEnd, isRtl, advances, advancesIndex);
        }
        if (text instanceof GraphicsOperations) {
            return ((GraphicsOperations) text).getTextRunAdvances(start, end,
                    contextStart, contextEnd, isRtl, advances, advancesIndex, this);
        }
        if (text.length() == 0 || end == start) {
            return 0f;
        }

        int contextLen = contextEnd - contextStart;
        int len = end - start;
        char[] buf = TemporaryBuffer.obtain(contextLen);
        TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
        float result = getTextRunAdvances(buf, start - contextStart, len,
                0, contextLen, isRtl, advances, advancesIndex);
        TemporaryBuffer.recycle(buf);
        return result;
    }

    /**
     * Returns the total advance width for the characters in the run
     * between start and end, and if advances is not null, the advance
     * assigned to each of these characters (java chars).
     *
     * <p>The trailing surrogate in a valid surrogate pair is assigned
     * an advance of 0.  Thus the number of returned advances is
     * always equal to count, not to the number of unicode codepoints
     * represented by the run.
     *
     * <p>In the case of conjuncts or combining marks, the total
     * advance is assigned to the first logical character, and the
     * following characters are assigned an advance of 0.
     *
     * <p>This generates the sum of the advances of glyphs for
     * characters in a reordered cluster as the width of the first
     * logical character in the cluster, and 0 for the widths of all
     * other characters in the cluster.  In effect, such clusters are
     * treated like conjuncts.
     *
     * <p>The shaping bounds limit the amount of context available
     * outside start and end that can be used for shaping analysis.
     * These bounds typically reflect changes in bidi level or font
     * metrics across which shaping does not occur.
     *
     * @param text the text to measure. Cannot be null.
     * @param start the index of the first character to measure
     * @param end the index past the last character to measure
     * @param contextStart the index of the first character to use for shaping context,
     * must be <= start
     * @param contextEnd the index past the last character to use for shaping context,
     * must be >= end
     * @param isRtl whether the run is in RTL direction
     * @param advances array to receive the advances, must have room for all advances,
     * can be null if only total advance is needed
     * @param advancesIndex the position in advances at which to put the
     * advance corresponding to the character at start
     * @return the total advance
     *
     * @hide
     */
    public float getTextRunAdvances(String text, int start, int end, int contextStart,
            int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
        if (text == null) {
            throw new IllegalArgumentException("text cannot be null");
        }
        if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
                | (start - contextStart) | (contextEnd - end)
                | (text.length() - contextEnd)
                | (advances == null ? 0 :
                    (advances.length - advancesIndex - (end - start)))) < 0) {
            throw new IndexOutOfBoundsException();
        }

        if (text.length() == 0 || start == end) {
            return 0f;
        }

        if (!mHasCompatScaling) {
            return nGetTextAdvances(mNativePaint, text, start, end, contextStart, contextEnd,
                    isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex);
        }

        final float oldSize = getTextSize();
        setTextSize(oldSize * mCompatScaling);
        final float totalAdvance = nGetTextAdvances(mNativePaint, text, start, end, contextStart,
                contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, advancesIndex);
        setTextSize(oldSize);

        if (advances != null) {
            for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
                advances[i] *= mInvCompatScaling;
            }
        }
        return totalAdvance * mInvCompatScaling; // assume errors are insignificant
    }

    /**
     * Returns the next cursor position in the run.  This avoids placing the
     * cursor between surrogates, between characters that form conjuncts,