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

Commit fac7e459 authored by Siyamed Sinir's avatar Siyamed Sinir Committed by Android (Google) Code Review
Browse files

Merge "Enable/disable fallback line spacing in TextView"

parents 1cd19bdc 8038267b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -579,6 +579,7 @@ package android {
    field public static final int fadingEdge = 16842975; // 0x10100df
    field public static final int fadingEdgeLength = 16842976; // 0x10100e0
    field public static final int fadingMode = 16843745; // 0x10103e1
    field public static final int fallbackLineSpacing = 16844155; // 0x101057b
    field public static final int fastScrollAlwaysVisible = 16843573; // 0x1010335
    field public static final int fastScrollEnabled = 16843302; // 0x1010226
    field public static final int fastScrollOverlayPosition = 16843578; // 0x101033a
@@ -52310,6 +52311,7 @@ package android.widget {
    method public boolean isAllCaps();
    method public boolean isCursorVisible();
    method public boolean isElegantTextHeight();
    method public boolean isFallbackLineSpacing();
    method public boolean isInputMethodTarget();
    method public boolean isSuggestionsEnabled();
    method public boolean isTextSelectable();
@@ -52353,6 +52355,7 @@ package android.widget {
    method public void setError(java.lang.CharSequence);
    method public void setError(java.lang.CharSequence, android.graphics.drawable.Drawable);
    method public void setExtractedText(android.view.inputmethod.ExtractedText);
    method public void setFallbackLineSpacing(boolean);
    method public void setFilters(android.text.InputFilter[]);
    method public void setFontFeatureSettings(java.lang.String);
    method public boolean setFontVariationSettings(java.lang.String);
+55 −2
Original line number Diff line number Diff line
@@ -296,6 +296,7 @@ import java.util.Locale;
 * @attr ref android.R.styleable#TextView_imeActionId
 * @attr ref android.R.styleable#TextView_editorExtras
 * @attr ref android.R.styleable#TextView_elegantTextHeight
 * @attr ref android.R.styleable#TextView_fallbackLineSpacing
 * @attr ref android.R.styleable#TextView_letterSpacing
 * @attr ref android.R.styleable#TextView_fontFeatureSettings
 * @attr ref android.R.styleable#TextView_breakStrategy
@@ -655,7 +656,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    // True if internationalized input should be used for numbers and date and time.
    private final boolean mUseInternationalizedInput;
    // True if fallback fonts that end up getting used should be allowed to affect line spacing.
    /* package */ final boolean mUseFallbackLineSpacing;
    /* package */ boolean mUseFallbackLineSpacing;

    @ViewDebug.ExportedProperty(category = "text")
    private int mGravity = Gravity.TOP | Gravity.START;
@@ -3255,6 +3256,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        float mShadowDx = 0, mShadowDy = 0, mShadowRadius = 0;
        boolean mHasElegant = false;
        boolean mElegant = false;
        boolean mHasFallbackLineSpacing = false;
        boolean mFallbackLineSpacing = false;
        boolean mHasLetterSpacing = false;
        float mLetterSpacing = 0;
        String mFontFeatureSettings = null;
@@ -3279,6 +3282,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    + "    mShadowRadius:" + mShadowRadius + "\n"
                    + "    mHasElegant:" + mHasElegant + "\n"
                    + "    mElegant:" + mElegant + "\n"
                    + "    mHasFallbackLineSpacing:" + mHasFallbackLineSpacing + "\n"
                    + "    mFallbackLineSpacing:" + mFallbackLineSpacing + "\n"
                    + "    mHasLetterSpacing:" + mHasLetterSpacing + "\n"
                    + "    mLetterSpacing:" + mLetterSpacing + "\n"
                    + "    mFontFeatureSettings:" + mFontFeatureSettings + "\n"
@@ -3317,6 +3322,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                com.android.internal.R.styleable.TextAppearance_shadowRadius);
        sAppearanceValues.put(com.android.internal.R.styleable.TextView_elegantTextHeight,
                com.android.internal.R.styleable.TextAppearance_elegantTextHeight);
        sAppearanceValues.put(com.android.internal.R.styleable.TextView_fallbackLineSpacing,
                com.android.internal.R.styleable.TextAppearance_fallbackLineSpacing);
        sAppearanceValues.put(com.android.internal.R.styleable.TextView_letterSpacing,
                com.android.internal.R.styleable.TextAppearance_letterSpacing);
        sAppearanceValues.put(com.android.internal.R.styleable.TextView_fontFeatureSettings,
@@ -3407,6 +3414,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    attributes.mHasElegant = true;
                    attributes.mElegant = appearance.getBoolean(attr, attributes.mElegant);
                    break;
                case com.android.internal.R.styleable.TextAppearance_fallbackLineSpacing:
                    attributes.mHasFallbackLineSpacing = true;
                    attributes.mFallbackLineSpacing = appearance.getBoolean(attr,
                            attributes.mFallbackLineSpacing);
                    break;
                case com.android.internal.R.styleable.TextAppearance_letterSpacing:
                    attributes.mHasLetterSpacing = true;
                    attributes.mLetterSpacing =
@@ -3460,6 +3472,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            setElegantTextHeight(attributes.mElegant);
        }

        if (attributes.mHasFallbackLineSpacing) {
            setFallbackLineSpacing(attributes.mFallbackLineSpacing);
        }

        if (attributes.mHasLetterSpacing) {
            setLetterSpacing(attributes.mLetterSpacing);
        }
@@ -3741,7 +3757,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     *
     * @param elegant set the paint's elegant metrics flag.
     *
     * @see Paint#isElegantTextHeight(boolean)
     * @see Paint#isElegantTextHeight()
     *
     * @attr ref android.R.styleable#TextView_elegantTextHeight
     */
@@ -3756,6 +3772,43 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        }
    }

    /**
     * Set whether to respect the ascent and descent of the fallback fonts that are used in
     * displaying the text (which is needed to avoid text from consecutive lines running into
     * each other). If set, fallback fonts that end up getting used can increase the ascent
     * and descent of the lines that they are used on.
     * <p/>
     * It is required to be true if text could be in languages like Burmese or Tibetan where text
     * is typically much taller or deeper than Latin text.
     *
     * @param enabled whether to expand linespacing based on fallback fonts, {@code true} by default
     *
     * @see StaticLayout.Builder#setUseLineSpacingFromFallbacks(boolean)
     *
     * @attr ref android.R.styleable#TextView_fallbackLineSpacing
     */
    public void setFallbackLineSpacing(boolean enabled) {
        if (mUseFallbackLineSpacing != enabled) {
            mUseFallbackLineSpacing = enabled;
            if (mLayout != null) {
                nullLayouts();
                requestLayout();
                invalidate();
            }
        }
    }

    /**
     * @return whether fallback line spacing is enabled, {@code true} by default
     *
     * @see #setFallbackLineSpacing(boolean)
     *
     * @attr ref android.R.styleable#TextView_fallbackLineSpacing
     */
    public boolean isFallbackLineSpacing() {
        return mUseFallbackLineSpacing;
    }

    /**
     * Get the value of the TextView's elegant height metrics flag. This setting selects font
     * variants that have not been compacted to fit Latin-based vertical
+8 −0
Original line number Diff line number Diff line
@@ -4470,6 +4470,10 @@
        <attr name="shadowRadius" format="float" />
        <!-- Elegant text height, especially for less compacted complex script text. -->
        <attr name="elegantTextHeight" format="boolean" />
        <!-- Whether to respect the ascent and descent of the fallback fonts that are used in
        displaying the text. When true, fallback fonts that end up getting used can increase
        the ascent and descent of the lines that they are used on. -->
        <attr name="fallbackLineSpacing" format="boolean"/>
        <!-- Text letter-spacing. -->
        <attr name="letterSpacing" format="float" />
        <!-- Font feature settings. -->
@@ -4803,6 +4807,10 @@
        <attr name="textAllCaps" />
        <!-- Elegant text height, especially for less compacted complex script text. -->
        <attr name="elegantTextHeight" />
        <!-- Whether to respect the ascent and descent of the fallback fonts that are used in
        displaying the text. When true, fallback fonts that end up getting used can increase
        the ascent and descent of the lines that they are used on. -->
        <attr name="fallbackLineSpacing" format="boolean"/>
        <!-- Text letter-spacing. -->
        <attr name="letterSpacing" />
        <!-- Font feature settings. -->
+1 −0
Original line number Diff line number Diff line
@@ -2860,6 +2860,7 @@
      <public name="isVrOnly"/>
      <public name="widgetFeatures" />
      <public name="appComponentFactory" />
      <public name="fallbackLineSpacing" />
    </public-group>

    <public-group type="style" first-id="0x010302e0">
+138 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.widget;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import android.app.Activity;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.text.DynamicLayout;
import android.text.FontFallbackSetup;
import android.text.Layout;
import android.text.StaticLayout;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView.BufferType;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.Arrays;
import java.util.Collection;

/**
 * Parametrized test for TextView#setFallbackLineSpacing.
 */
@MediumTest
@RunWith(Parameterized.class)
public class TextViewFallbackLineSpacingTest {

    @Parameterized.Parameters(name = "{0}")
    public static Collection layouts() {
        return Arrays.asList(new Object[][] {
                // name, enabled, BufferType
                { "Enabled - StaticLayout", true, BufferType.NORMAL},
                { "Disabled - StaticLayout", false, BufferType.NORMAL},
                { "Enabled - DynamicLayout", true, BufferType.EDITABLE},
                { "Disabled - DynamicLayout", false, BufferType.EDITABLE},
        });
    }

    @Rule
    public ActivityTestRule<TextViewActivity> mActivityRule = new ActivityTestRule<>(
            TextViewActivity.class);

    private final boolean mEnabled;
    private final BufferType mBufferType;

    public TextViewFallbackLineSpacingTest(String testName, boolean enabled,
            BufferType bufferType) {
        mEnabled = enabled;
        mBufferType = bufferType;
    }

    @Test
    public void testFallbackLineSpacing() {
        // All glyphs in the fonts are 1em wide.
        final String[] testFontFiles = {
                // ascent == 1em, descent == 2em, only supports 'a' and space
                "ascent1em-descent2em.ttf",
                // ascent == 3em, descent == 4em, only supports 'b'
                "ascent3em-descent4em.ttf"
        };
        final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
                + "<familyset>"
                + "  <family name='sans-serif'>"
                + "    <font weight='400' style='normal'>ascent1em-descent2em.ttf</font>"
                + "  </family>"
                + "  <family>"
                + "    <font weight='400' style='normal'>ascent3em-descent4em.ttf</font>"
                + "  </family>"
                + "</familyset>";

        try (FontFallbackSetup setup =
                     new FontFallbackSetup("DynamicLayout", testFontFiles, xml)) {
            final Activity activity = mActivityRule.getActivity();
            final TextView textView = new TextView(activity);
            textView.setTypeface(setup.getTypefaceFor("sans-serif"));
            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 100);
            // This should result in three lines.
            textView.setText("aaaaa aabaa aaaaa", mBufferType);
            textView.setPadding(0, 0, 0, 0);
            textView.setIncludeFontPadding(false);
            textView.setFallbackLineSpacing(mEnabled);

            final int em = (int) Math.ceil(textView.getPaint().measureText("a"));
            final int width = 5 * em;
            final int height = 30 * em; // tall enough to not affect our other measurements
            textView.measure(
                    View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
                    View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
            textView.layout(0, 0, width, height);

            final Layout layout = textView.getLayout();
            assertNotNull(layout);
            if (mBufferType == BufferType.NORMAL) {
                assertTrue(layout instanceof StaticLayout);
            } else {
                assertTrue(layout instanceof DynamicLayout);
            }
            assertEquals(3, layout.getLineCount());

            assertEquals(-em, layout.getLineAscent(0));
            assertEquals(2 * em, layout.getLineDescent(0));

            if (mEnabled) {
                // The second line has a 'b', so it needs more ascent and descent.
                assertEquals(-3 * em, layout.getLineAscent(1));
                assertEquals(4 * em, layout.getLineDescent(1));
            } else {
                // old behavior
                assertEquals(-em, layout.getLineAscent(1));
                assertEquals(2 * em, layout.getLineDescent(1));
            }

            assertEquals(-em, layout.getLineAscent(2));
            assertEquals(2 * em, layout.getLineDescent(2));
        }
    }
}
Loading