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

Commit a4d59758 authored by Tyler Freeman's avatar Tyler Freeman
Browse files

fix(non linear font scaling): preserve proportionality of lineHeight when...

fix(non linear font scaling): preserve proportionality of lineHeight when non-linear font scaling is in effect

This ensures that the design intent is preserved when using large font
scales and non-linear font scaling: the line height proportions should
still match even when using SP units for both text size and line height.

If the dev does not define both textSize and lineHeight in SP units, we
don't do the corrective recalculation. Unfortunately, this could result
in cramped-looking text due to the lineHeight not scaling with text
size. There are linters to warn the developer of this though, so we hope
they do the right thing.

Bug: 273326061
Test: atest cts/tests/tests/widget/src/android/widget/cts/TextViewFontScalingTest.kt
Change-Id: I17f9b7c8d3e0e63deed4037ebf0e99b690bc694a
parent da945139
Loading
Loading
Loading
Loading
+43 −5
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.FontScaleConverterFactory;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -1233,7 +1234,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                defStyleAttr, defStyleRes);
        int firstBaselineToTopHeight = -1;
        int lastBaselineToBottomHeight = -1;
        int lineHeight = -1;
        float lineHeight = -1f;
        int lineHeightUnit = -1;
        readTextAppearance(context, a, attributes, true /* styleArray */);
@@ -1583,7 +1585,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    break;
                case com.android.internal.R.styleable.TextView_lineHeight:
                    TypedValue peekValue = a.peekValue(attr);
                    if (peekValue != null && peekValue.type == TypedValue.TYPE_DIMENSION) {
                        lineHeightUnit = peekValue.getComplexUnit();
                        lineHeight = TypedValue.complexToFloat(peekValue.data);
                    } else {
                        lineHeight = a.getDimensionPixelSize(attr, -1);
                    }
                    break;
            }
        }
@@ -1936,7 +1944,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            setLastBaselineToBottomHeight(lastBaselineToBottomHeight);
        }
        if (lineHeight >= 0) {
            setLineHeight(lineHeight);
            if (lineHeightUnit == -1) {
                setLineHeightPx(lineHeight);
            } else {
                setLineHeight(lineHeightUnit, lineHeight);
            }
        }
    }
@@ -6236,8 +6248,34 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            @TypedValue.ComplexDimensionUnit int unit,
            @FloatRange(from = 0) float lineHeight
    ) {
        setLineHeightPx(
                TypedValue.applyDimension(unit, lineHeight, getDisplayMetricsOrSystem()));
        var metrics = getDisplayMetricsOrSystem();
        // We can avoid the recalculation if we know non-linear font scaling isn't being used
        // (an optimization for the majority case).
        // We also don't try to do the recalculation unless both textSize and lineHeight are in SP.
        if (!FontScaleConverterFactory.isNonLinearFontScalingActive(
                    getResources().getConfiguration().fontScale)
                || unit != TypedValue.COMPLEX_UNIT_SP
                || mTextSizeUnit != TypedValue.COMPLEX_UNIT_SP
        ) {
            setLineHeightPx(TypedValue.applyDimension(unit, lineHeight, metrics));
            return;
        }
        // Recalculate a proportional line height when non-linear font scaling is in effect.
        // Otherwise, a desired 2x line height at font scale 1.0 will not be 2x at font scale 2.0,
        // due to non-linear font scaling compressing higher SP sizes. See b/273326061 for details.
        // We know they are using SP units for both the text size and the line height
        // at this point, so determine the ratio between them. This is the *intended* line spacing
        // multiplier if font scale == 1.0. We can then determine what the pixel value for the line
        // height would be if we preserved proportions.
        var textSizePx = getTextSize();
        var textSizeSp = TypedValue.convertPixelsToDimension(
                TypedValue.COMPLEX_UNIT_SP,
                textSizePx,
                metrics
        );
        var ratio = lineHeight / textSizeSp;
        setLineHeightPx(textSizePx * ratio);
    }
    /**