From fa043bb5d9673bfa0f66fd9dfd680918b11e8456 Mon Sep 17 00:00:00 2001 From: Tyler Freeman Date: Thu, 13 Apr 2023 19:27:34 +0000 Subject: [PATCH] fix(non linear font scaling): recalculate proportional line height if they setTextSize() after setting line height This will only recalculate if both were set in SP, since that's the only time the proportion calculation happens anyway. Bug: 273326061 Test: atest cts/tests/tests/widget/src/android/widget/cts/TextViewFontScalingTest.kt Change-Id: I41ad12cdef6f1b93b60deca039c9ab72bb59e39f --- core/java/android/util/TypedValue.java | 20 ++++++++++++---- core/java/android/widget/TextView.java | 32 ++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java index b93e3386b7cca..330a9fce1b83b 100644 --- a/core/java/android/util/TypedValue.java +++ b/core/java/android/util/TypedValue.java @@ -385,10 +385,22 @@ public class TypedValue { * * @return The complex unit type. */ - public int getComplexUnit() - { - return COMPLEX_UNIT_MASK & (data>>TypedValue.COMPLEX_UNIT_SHIFT); - } + public int getComplexUnit() { + return getUnitFromComplexDimension(data); + } + + /** + * Return the complex unit type for the given complex dimension. For example, a dimen type + * with value 12sp will return {@link #COMPLEX_UNIT_SP}. Use with values created with {@link + * #createComplexDimension(int, int)} etc. + * + * @return The complex unit type. + * + * @hide + */ + public static int getUnitFromComplexDimension(int complexDimension) { + return COMPLEX_UNIT_MASK & (complexDimension >> TypedValue.COMPLEX_UNIT_SHIFT); + } /** * Converts an unpacked complex data value holding a dimension to its final floating point pixel diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 65a937bdc4bc7..3fbb50581b25e 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -868,6 +868,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @UnsupportedAppUsage private float mSpacingAdd = 0.0f; + /** + * Remembers what line height was set to originally, before we broke it down into raw pixels. + * + *

This is stored as a complex dimension with both value and unit packed into one field! + * {@see TypedValue} + */ + private int mLineHeightComplexDimen; + private int mBreakStrategy; private int mHyphenationFrequency; private int mJustificationMode; @@ -4641,6 +4649,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (size != mTextPaint.getTextSize()) { mTextPaint.setTextSize(size); + maybeRecalculateLineHeight(); if (shouldRequestLayout && mLayout != null) { // Do not auto-size right after setting the text size. mNeedsAutoSizeText = false; @@ -6226,6 +6235,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (lineHeight != fontHeight) { // Set lineSpacingExtra by the difference of lineSpacing with lineHeight setLineSpacing(lineHeight - fontHeight, 1f); + + mLineHeightComplexDimen = + TypedValue.createComplexDimension(lineHeight, TypedValue.COMPLEX_UNIT_PX); } } @@ -6258,6 +6270,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener || mTextSizeUnit != TypedValue.COMPLEX_UNIT_SP ) { setLineHeightPx(TypedValue.applyDimension(unit, lineHeight, metrics)); + + // Do this last so it overwrites what setLineHeightPx() sets it to. + mLineHeightComplexDimen = TypedValue.createComplexDimension(lineHeight, unit); return; } @@ -6276,6 +6291,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener ); var ratio = lineHeight / textSizeSp; setLineHeightPx(textSizePx * ratio); + + // Do this last so it overwrites what setLineHeightPx() sets it to. + mLineHeightComplexDimen = TypedValue.createComplexDimension(lineHeight, unit); + } + + private void maybeRecalculateLineHeight() { + if (mLineHeightComplexDimen == 0) { + return; + } + int unit = TypedValue.getUnitFromComplexDimension(mLineHeightComplexDimen); + if (unit != TypedValue.COMPLEX_UNIT_SP) { + // The lineHeight was never supplied in SP, so we didn't do any fancy recalculations + // in setLineHeight(). We don't need to recalculate. + return; + } + + setLineHeight(unit, TypedValue.complexToFloat(mLineHeightComplexDimen)); } /**