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:
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user