Merge "Modify textAnimator to support strokeWidth Change fontInterpolator to use adaptive step when change and cache typeface for different weights" into tm-qpr-dev

This commit is contained in:
Sherry Zhou
2023-03-08 16:52:28 +00:00
committed by Android (Google) Code Review
5 changed files with 61 additions and 14 deletions

View File

@@ -19,14 +19,15 @@ package com.android.systemui.animation
import android.graphics.fonts.Font
import android.graphics.fonts.FontVariationAxis
import android.util.MathUtils
import android.util.MathUtils.abs
import java.lang.Float.max
import java.lang.Float.min
private const val TAG_WGHT = "wght"
private const val TAG_ITAL = "ital"
private const val FONT_WEIGHT_MAX = 1000f
private const val FONT_WEIGHT_MIN = 0f
private const val FONT_WEIGHT_ANIMATION_STEP = 10f
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
@@ -118,14 +119,17 @@ class FontInterpolator {
lerp(startAxes, endAxes) { tag, startValue, endValue ->
when (tag) {
// TODO: Good to parse 'fvar' table for retrieving default value.
TAG_WGHT ->
adjustWeight(
TAG_WGHT -> {
adaptiveAdjustWeight(
MathUtils.lerp(
startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
progress
)
),
startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
)
}
TAG_ITAL ->
adjustItalic(
MathUtils.lerp(
@@ -205,10 +209,14 @@ class FontInterpolator {
return result
}
// For the performance reasons, we animate weight with FONT_WEIGHT_ANIMATION_STEP. This helps
// For the performance reasons, we animate weight with adaptive step. This helps
// Cache hit ratio in the Skia glyph cache.
private fun adjustWeight(value: Float) =
coerceInWithStep(value, FONT_WEIGHT_MIN, FONT_WEIGHT_MAX, FONT_WEIGHT_ANIMATION_STEP)
// 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.

View File

@@ -190,6 +190,7 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
* @param textSize an optional font size.
* @param colors an optional colors array that must be the same size as numLines passed to
* the TextInterpolator
* @param strokeWidth an optional paint stroke width
* @param animate an optional boolean indicating true for showing style transition as animation,
* false for immediate style transition. True by default.
* @param duration an optional animation duration in milliseconds. This is ignored if animate is
@@ -201,6 +202,7 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
weight: Int = -1,
textSize: Float = -1f,
color: Int? = null,
strokeWidth: Float = -1f,
animate: Boolean = true,
duration: Long = -1L,
interpolator: TimeInterpolator? = null,
@@ -254,6 +256,9 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
if (color != null) {
textInterpolator.targetPaint.color = color
}
if (strokeWidth >= 0F) {
textInterpolator.targetPaint.strokeWidth = strokeWidth
}
textInterpolator.onTargetPaintModified()
if (animate) {

View File

@@ -473,6 +473,7 @@ class TextInterpolator(layout: Layout) {
// TODO(172943390): Add other interpolation or support custom interpolator.
out.textSize = MathUtils.lerp(from.textSize, to.textSize, progress)
out.color = ColorUtils.blendARGB(from.color, to.color, progress)
out.strokeWidth = MathUtils.lerp(from.strokeWidth, to.strokeWidth, progress)
}
// Shape the text and stores the result to out argument.

View File

@@ -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' 500, 'ital' 0.5, 'GRAD' 450", interp.lerp(startFont, endFont, 0.5f))
assertSameAxes("'wght' 496, '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' 250, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f))
assertSameAxes("'wght' 249, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f))
}
@Test

View File

@@ -57,7 +57,18 @@ class AnimatableClockViewTest : SysuiTestCase() {
clockView.measure(50, 50)
verify(mockTextAnimator).glyphFilter = any()
verify(mockTextAnimator).setTextStyle(300, -1.0f, 200, false, 350L, null, 0L, null)
verify(mockTextAnimator)
.setTextStyle(
weight = 300,
textSize = -1.0f,
color = 200,
strokeWidth = -1F,
animate = false,
duration = 350L,
interpolator = null,
delay = 0L,
onAnimationEnd = null
)
verifyNoMoreInteractions(mockTextAnimator)
}
@@ -68,8 +79,30 @@ class AnimatableClockViewTest : SysuiTestCase() {
clockView.animateAppearOnLockscreen()
verify(mockTextAnimator, times(2)).glyphFilter = any()
verify(mockTextAnimator).setTextStyle(100, -1.0f, 200, false, 0L, null, 0L, null)
verify(mockTextAnimator).setTextStyle(300, -1.0f, 200, true, 350L, null, 0L, null)
verify(mockTextAnimator)
.setTextStyle(
weight = 100,
textSize = -1.0f,
color = 200,
strokeWidth = -1F,
animate = false,
duration = 0L,
interpolator = null,
delay = 0L,
onAnimationEnd = null
)
verify(mockTextAnimator)
.setTextStyle(
weight = 300,
textSize = -1.0f,
color = 200,
strokeWidth = -1F,
animate = true,
duration = 350L,
interpolator = null,
delay = 0L,
onAnimationEnd = null
)
verifyNoMoreInteractions(mockTextAnimator)
}
}