Merge "Use fallback-based line spacing in TextView etc"
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 7fa8066..f9bdb0fe 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -755,14 +755,18 @@
}
}
- private void chooseSize(PopupWindow pop, CharSequence text, TextView tv) {
- int wid = tv.getPaddingLeft() + tv.getPaddingRight();
- int ht = tv.getPaddingTop() + tv.getPaddingBottom();
+ private void chooseSize(@NonNull PopupWindow pop, @NonNull CharSequence text,
+ @NonNull TextView tv) {
+ final int wid = tv.getPaddingLeft() + tv.getPaddingRight();
+ final int ht = tv.getPaddingTop() + tv.getPaddingBottom();
- int defaultWidthInPixels = mTextView.getResources().getDimensionPixelSize(
+ final int defaultWidthInPixels = mTextView.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.textview_error_popup_default_width);
- Layout l = new StaticLayout(text, tv.getPaint(), defaultWidthInPixels,
- Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
+ final StaticLayout l = StaticLayout.Builder.obtain(text, 0, text.length(), tv.getPaint(),
+ defaultWidthInPixels)
+ .setUseLineSpacingFromFallbacks(tv.mUseFallbackLineSpacing)
+ .build();
+
float max = 0;
for (int i = 0; i < l.getLineCount(); i++) {
max = Math.max(max, l.getLineWidth(i));
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 40253a1..2e1e963 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -33,6 +33,7 @@
import android.graphics.Region.Op;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.os.Build.VERSION_CODES;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
@@ -111,6 +112,7 @@
private CharSequence mTextOn;
private CharSequence mTextOff;
private boolean mShowText;
+ private boolean mUseFallbackLineSpacing;
private int mTouchMode;
private int mTouchSlop;
@@ -246,6 +248,11 @@
com.android.internal.R.styleable.Switch_switchPadding, 0);
mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false);
+ // TODO: replace CUR_DEVELOPMENT with P once P is added to android.os.Build.VERSION_CODES.
+ // STOPSHIP if the above TODO is not done.
+ mUseFallbackLineSpacing =
+ context.getApplicationInfo().targetSdkVersion >= VERSION_CODES.CUR_DEVELOPMENT;
+
ColorStateList thumbTintList = a.getColorStateList(
com.android.internal.R.styleable.Switch_thumbTint);
if (thumbTintList != null) {
@@ -894,8 +901,9 @@
int width = (int) Math.ceil(Layout.getDesiredWidth(transformed, 0,
transformed.length(), mTextPaint, getTextDirectionHeuristic()));
- return new StaticLayout(transformed, mTextPaint, width,
- Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
+ return StaticLayout.Builder.obtain(transformed, 0, transformed.length(), mTextPaint, width)
+ .setUseLineSpacingFromFallbacks(mUseFallbackLineSpacing)
+ .build();
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2417b0f..140ecc1 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -650,6 +650,8 @@
private boolean mListenerChanged = false;
// 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;
@ViewDebug.ExportedProperty(category = "text")
private int mGravity = Gravity.TOP | Gravity.START;
@@ -1252,8 +1254,11 @@
final boolean numberPasswordInputType = variation
== (EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD);
- mUseInternationalizedInput =
- context.getApplicationInfo().targetSdkVersion >= VERSION_CODES.O;
+ final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
+ mUseInternationalizedInput = targetSdkVersion >= VERSION_CODES.O;
+ // TODO: replace CUR_DEVELOPMENT with P once P is added to android.os.Build.VERSION_CODES.
+ // STOPSHIP if the above TODO is not done.
+ mUseFallbackLineSpacing = targetSdkVersion >= VERSION_CODES.CUR_DEVELOPMENT;
if (inputMethod != null) {
Class<?> c;
@@ -7914,6 +7919,7 @@
.setTextDirection(mTextDir)
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
+ .setUseLineSpacingFromFallbacks(mUseFallbackLineSpacing)
.setBreakStrategy(mBreakStrategy)
.setHyphenationFrequency(mHyphenationFrequency)
.setJustificationMode(mJustificationMode)
@@ -7963,6 +7969,7 @@
.setTextDirection(mTextDir)
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
+ .setUseLineSpacingFromFallbacks(mUseFallbackLineSpacing)
.setBreakStrategy(mBreakStrategy)
.setHyphenationFrequency(mHyphenationFrequency)
.setJustificationMode(mJustificationMode)
@@ -8015,6 +8022,7 @@
.setTextDirection(mTextDir)
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
+ .setUseLineSpacingFromFallbacks(mUseFallbackLineSpacing)
.setBreakStrategy(mBreakStrategy)
.setHyphenationFrequency(mHyphenationFrequency)
.setJustificationMode(mJustificationMode)
@@ -8374,6 +8382,7 @@
layoutBuilder.setAlignment(getLayoutAlignment())
.setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
.setIncludePad(getIncludeFontPadding())
+ .setUseLineSpacingFromFallbacks(mUseFallbackLineSpacing)
.setBreakStrategy(getBreakStrategy())
.setHyphenationFrequency(getHyphenationFrequency())
.setJustificationMode(getJustificationMode())
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index 31b167d..7870333 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -81,6 +81,7 @@
.setTextDirection(getTextDirectionHeuristic())
.setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
.setIncludePad(getIncludeFontPadding())
+ .setUseLineSpacingFromFallbacks(true)
.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
int maxLines;
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index 3230185..1107828 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -256,8 +256,11 @@
// StaticLayout.getWidth(), so this is non-trivial.
mHasMeasurements = true;
mLastMeasuredWidth = maxWidth;
- mLayout = new StaticLayout(
- mText, mTextPaint, maxWidth, mAlignment, mSpacingMult, mSpacingAdd, true);
+ mLayout = StaticLayout.Builder.obtain(mText, 0, mText.length(), mTextPaint, maxWidth)
+ .setAlignment(mAlignment)
+ .setLineSpacing(mSpacingAdd, mSpacingMult)
+ .setUseLineSpacingFromFallbacks(true)
+ .build();
return true;
}
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index bcf2514..ced74ee 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -77,10 +77,14 @@
}
@NonNull
+ public Typeface getTypefaceFor(@NonNull String fontName) {
+ return mFontMap.get(fontName);
+ }
+
+ @NonNull
public TextPaint getPaintFor(@NonNull String fontName) {
- final Typeface testTypeface = mFontMap.get(fontName);
final TextPaint paint = new TextPaint();
- paint.setTypeface(testTypeface);
+ paint.setTypeface(getTypefaceFor(fontName));
return paint;
}
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 5806bf1..d31da71 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -30,6 +30,7 @@
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import android.text.FontFallbackSetup;
import android.text.GetChars;
import android.text.Layout;
import android.text.Selection;
@@ -249,4 +250,56 @@
}
return builder.toString();
}
+
+ @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)) {
+ mTextView = new TextView(mActivity);
+ mTextView.setTypeface(setup.getTypefaceFor("sans-serif"));
+ mTextView.setTextSize(100);
+ mTextView.setText("aaaaa aabaa aaaaa"); // This should result in three lines.
+ mTextView.setPadding(0, 0, 0, 0);
+ mTextView.setIncludeFontPadding(false);
+
+ final int em = (int) Math.ceil(mTextView.getPaint().measureText("a"));
+ final int width = 5 * em;
+ final int height = 30 * em; // tall enough to not affect our other measurements
+ mTextView.measure(
+ View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+ mTextView.layout(0, 0, width, height);
+
+ final Layout layout = mTextView.getLayout();
+ assertNotNull(layout);
+ assertEquals(3, layout.getLineCount());
+
+ assertEquals(-em, layout.getLineAscent(0));
+ assertEquals(2 * em, layout.getLineDescent(0));
+
+ // 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));
+
+ assertEquals(-em, layout.getLineAscent(2));
+ assertEquals(2 * em, layout.getLineDescent(2));
+ }
+ }
}