diff options
4 files changed, 22 insertions, 36 deletions
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt index 7e1bfb921ca9..addabcc0282a 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt @@ -21,7 +21,6 @@ import android.graphics.fonts.FontVariationAxis import android.util.Log import android.util.LruCache import android.util.MathUtils -import android.util.MathUtils.abs import androidx.annotation.VisibleForTesting import java.lang.Float.max import java.lang.Float.min @@ -30,8 +29,6 @@ private const val TAG_WGHT = "wght" private const val TAG_ITAL = "ital" private const val FONT_WEIGHT_DEFAULT_VALUE = 400f -private const val FONT_WEIGHT_ANIMATION_FRAME_COUNT = 100 - private const val FONT_ITALIC_MAX = 1f private const val FONT_ITALIC_MIN = 0f private const val FONT_ITALIC_ANIMATION_STEP = 0.1f @@ -39,11 +36,12 @@ private const val FONT_ITALIC_DEFAULT_VALUE = 0f // Benchmarked via Perfetto, difference between 10 and 50 entries is about 0.3ms in // frame draw time on a Pixel 6. -@VisibleForTesting const val FONT_CACHE_MAX_ENTRIES = 10 +@VisibleForTesting const val DEFAULT_FONT_CACHE_MAX_ENTRIES = 10 /** Provide interpolation of two fonts by adjusting font variation settings. */ -class FontInterpolator { - +class FontInterpolator( + numberOfAnimationSteps: Int? = null, +) { /** * Cache key for the interpolated font. * @@ -88,8 +86,9 @@ class FontInterpolator { // Font interpolator has two level caches: one for input and one for font with different // variation settings. No synchronization is needed since FontInterpolator is not designed to be // thread-safe and can be used only on UI thread. - private val interpCache = LruCache<InterpKey, Font>(FONT_CACHE_MAX_ENTRIES) - private val verFontCache = LruCache<VarFontKey, Font>(FONT_CACHE_MAX_ENTRIES) + val cacheMaxEntries = numberOfAnimationSteps?.let { it * 2 } ?: DEFAULT_FONT_CACHE_MAX_ENTRIES + private val interpCache = LruCache<InterpKey, Font>(cacheMaxEntries) + private val verFontCache = LruCache<VarFontKey, Font>(cacheMaxEntries) // Mutable keys for recycling. private val tmpInterpKey = InterpKey(null, null, 0f) @@ -128,18 +127,12 @@ class FontInterpolator { val newAxes = lerp(startAxes, endAxes) { tag, startValue, endValue -> when (tag) { - // TODO: Good to parse 'fvar' table for retrieving default value. - TAG_WGHT -> { - adaptiveAdjustWeight( - MathUtils.lerp( - startValue ?: FONT_WEIGHT_DEFAULT_VALUE, - endValue ?: FONT_WEIGHT_DEFAULT_VALUE, - progress - ), + TAG_WGHT -> + MathUtils.lerp( startValue ?: FONT_WEIGHT_DEFAULT_VALUE, endValue ?: FONT_WEIGHT_DEFAULT_VALUE, + progress ) - } TAG_ITAL -> adjustItalic( MathUtils.lerp( @@ -175,9 +168,9 @@ class FontInterpolator { val newFont = Font.Builder(start).setFontVariationSettings(newAxes.toTypedArray()).build() interpCache.put(InterpKey(start, end, progress), newFont) verFontCache.put(VarFontKey(start, newAxes), newFont) - if (DEBUG) { - Log.d(LOG_TAG, "[$progress] Cache MISS for $tmpInterpKey / $tmpVarFontKey") - } + + // Cache misses are likely to create memory leaks, so this is logged at error level. + Log.e(LOG_TAG, "[$progress] Cache MISS for $tmpInterpKey / $tmpVarFontKey") return newFont } @@ -225,15 +218,6 @@ class FontInterpolator { return result } - // For the performance reasons, we animate weight with adaptive step. This helps - // Cache hit ratio in the Skia glyph cache. - // The reason we don't use fix step is because the range of weight axis is not normalized, - // some are from 50 to 100, others are from 0 to 1000, so we cannot give a constant proper step - private fun adaptiveAdjustWeight(value: Float, start: Float, end: Float): Float { - val step = max(abs(end - start) / FONT_WEIGHT_ANIMATION_FRAME_COUNT, 1F) - return coerceInWithStep(value, min(start, end), max(start, end), step) - } - // For the performance reasons, we animate italic with FONT_ITALIC_ANIMATION_STEP. This helps // Cache hit ratio in the Skia glyph cache. private fun adjustItalic(value: Float) = diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt index 16ddf0c36d9d..b555fa583588 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt @@ -108,7 +108,8 @@ class TextAnimator( } // Following two members are for mutable for testing purposes. - public var textInterpolator: TextInterpolator = TextInterpolator(layout, typefaceCache) + public var textInterpolator: TextInterpolator = + TextInterpolator(layout, typefaceCache, numberOfAnimationSteps) public var animator: ValueAnimator = ValueAnimator.ofFloat(1f).apply { duration = DEFAULT_ANIMATION_DURATION diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt index 8ed8d8fb61fd..02caeeddd774 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt @@ -31,6 +31,7 @@ import java.lang.Math.max class TextInterpolator( layout: Layout, var typefaceCache: TypefaceVariantCache, + numberOfAnimationSteps: Int? = null, ) { /** * Returns base paint used for interpolation. @@ -85,7 +86,7 @@ class TextInterpolator( private class Line(val runs: List<Run>) private var lines = listOf<Line>() - private val fontInterpolator = FontInterpolator() + private val fontInterpolator = FontInterpolator(numberOfAnimationSteps) // Recycling object for glyph drawing and tweaking. private val tmpPaint = TextPaint() diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt index 57a355f4e127..5e1a8e1432dd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt @@ -37,7 +37,7 @@ class FontInterpolatorTest : SysuiTestCase() { private fun assertSameAxes(expect: Font, actual: Font) { val expectAxes = expect.axes?.also { it.sortBy { axis -> axis.tag } } val actualAxes = actual.axes?.also { it.sortBy { axis -> axis.tag } } - assertThat(expectAxes).isEqualTo(actualAxes) + assertThat(actualAxes).isEqualTo(expectAxes) } private fun assertSameAxes(expectVarSettings: String, actual: Font) { @@ -46,7 +46,7 @@ class FontInterpolatorTest : SysuiTestCase() { it.sortBy { axis -> axis.tag } } val actualAxes = actual.axes?.also { it.sortBy { axis -> axis.tag } } - assertThat(expectAxes).isEqualTo(actualAxes) + assertThat(actualAxes).isEqualTo(expectAxes) } @Test @@ -61,7 +61,7 @@ class FontInterpolatorTest : SysuiTestCase() { val interp = FontInterpolator() assertSameAxes(startFont, interp.lerp(startFont, endFont, 0f)) assertSameAxes(endFont, interp.lerp(startFont, endFont, 1f)) - assertSameAxes("'wght' 496, 'ital' 0.5, 'GRAD' 450", interp.lerp(startFont, endFont, 0.5f)) + assertSameAxes("'wght' 500, 'ital' 0.5, 'GRAD' 450", interp.lerp(startFont, endFont, 0.5f)) } @Test @@ -74,7 +74,7 @@ class FontInterpolatorTest : SysuiTestCase() { .build() val interp = FontInterpolator() - assertSameAxes("'wght' 249, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f)) + assertSameAxes("'wght' 250, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f)) } @Test @@ -118,7 +118,7 @@ class FontInterpolatorTest : SysuiTestCase() { .setFontVariationSettings("'wght' 1") .build() val resultFont = interp.lerp(startFont, endFont, 0.5f) - for (i in 0..FONT_CACHE_MAX_ENTRIES + 1) { + for (i in 0..interp.cacheMaxEntries + 1) { val f1 = Font.Builder(sFont) .setFontVariationSettings("'wght' ${i * 100}") .build() |