Merge "Allow TextAnimator TypefaceCaches to be shared" into udc-dev

This commit is contained in:
Hawkwood Glazier
2023-04-21 14:27:36 +00:00
committed by Android (Google) Code Review
3 changed files with 57 additions and 27 deletions

View File

@@ -24,12 +24,30 @@ import android.graphics.Canvas
import android.graphics.Typeface
import android.graphics.fonts.Font
import android.text.Layout
import android.text.TextPaint
import android.util.LruCache
private const val DEFAULT_ANIMATION_DURATION: Long = 300
private const val TYPEFACE_CACHE_MAX_ENTRIES = 5
typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
interface TypefaceVariantCache {
fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface?
}
class TypefaceVariantCacheImpl() : TypefaceVariantCache {
private val cache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES)
override fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface? {
cache.get(fvar)?.let {
return it
}
targetPaint.fontVariationSettings = fvar
return targetPaint.typeface?.also { cache.put(fvar, it) }
}
}
/**
* This class provides text animation between two styles.
*
@@ -56,9 +74,19 @@ typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
* ```
* </code> </pre>
*/
class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
class TextAnimator(
layout: Layout,
private val invalidateCallback: () -> Unit,
) {
var typefaceCache: TypefaceVariantCache = TypefaceVariantCacheImpl()
get() = field
set(value) {
field = value
textInterpolator.typefaceCache = value
}
// Following two members are for mutable for testing purposes.
public var textInterpolator: TextInterpolator = TextInterpolator(layout)
public var textInterpolator: TextInterpolator = TextInterpolator(layout, typefaceCache)
public var animator: ValueAnimator =
ValueAnimator.ofFloat(1f).apply {
duration = DEFAULT_ANIMATION_DURATION
@@ -68,9 +96,7 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
}
addListener(
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
textInterpolator.rebase()
}
override fun onAnimationEnd(animation: Animator?) = textInterpolator.rebase()
override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
}
)
@@ -116,8 +142,6 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
private val fontVariationUtils = FontVariationUtils()
private val typefaceCache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES)
fun updateLayout(layout: Layout) {
textInterpolator.layout = layout
}
@@ -220,12 +244,8 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
}
if (!fvar.isNullOrBlank()) {
textInterpolator.targetPaint.typeface = typefaceCache.get(fvar) ?: run {
textInterpolator.targetPaint.fontVariationSettings = fvar
textInterpolator.targetPaint.typeface?.also {
typefaceCache.put(fvar, textInterpolator.targetPaint.typeface)
}
}
textInterpolator.targetPaint.typeface =
typefaceCache.getTypefaceForVariant(fvar, textInterpolator.targetPaint)
}
if (color != null) {
@@ -304,7 +324,8 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
weight = weight,
width = width,
opticalSize = opticalSize,
roundness = roundness,)
roundness = roundness,
)
setTextStyle(
fvar = fvar,
textSize = textSize,

View File

@@ -28,8 +28,10 @@ import com.android.internal.graphics.ColorUtils
import java.lang.Math.max
/** Provide text style linear interpolation for plain text. */
class TextInterpolator(layout: Layout) {
class TextInterpolator(
layout: Layout,
var typefaceCache: TypefaceVariantCache,
) {
/**
* Returns base paint used for interpolation.
*

View File

@@ -31,6 +31,7 @@ import android.text.TextPaint
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.io.File
@@ -64,6 +65,7 @@ private val END_PAINT = TextPaint(PAINT).apply {
@RunWith(AndroidTestingRunner::class)
@SmallTest
class TextInterpolatorTest : SysuiTestCase() {
lateinit var typefaceCache: TypefaceVariantCache
private fun makeLayout(
text: String,
@@ -75,11 +77,16 @@ class TextInterpolatorTest : SysuiTestCase() {
.setTextDirection(dir).build()
}
@Before
fun setup() {
typefaceCache = TypefaceVariantCacheImpl()
}
@Test
fun testStartState() {
val layout = makeLayout(TEXT, PAINT)
val interp = TextInterpolator(layout)
val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -98,7 +105,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testEndState() {
val layout = makeLayout(TEXT, PAINT)
val interp = TextInterpolator(layout)
val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -116,7 +123,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testMiddleState() {
val layout = makeLayout(TEXT, PAINT)
val interp = TextInterpolator(layout)
val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -138,7 +145,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testRebase() {
val layout = makeLayout(TEXT, PAINT)
val interp = TextInterpolator(layout)
val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -160,7 +167,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testBidi_LTR() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.LTR)
val interp = TextInterpolator(layout)
val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -180,7 +187,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testBidi_RTL() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
val interp = TextInterpolator(layout)
val interp = TextInterpolator(layout, typefaceCache)
interp.basePaint.set(START_PAINT)
interp.onBasePaintModified()
@@ -200,7 +207,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_Empty() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
val interp = TextInterpolator(layout).apply {
val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
}
}
@@ -222,7 +229,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_Xcoordinate() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
val interp = TextInterpolator(layout).apply {
val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
glyph.x += 30f
}
@@ -247,7 +254,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_Ycoordinate() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
val interp = TextInterpolator(layout).apply {
val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
glyph.y += 30f
}
@@ -272,7 +279,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_TextSize() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
val interp = TextInterpolator(layout).apply {
val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
glyph.textSize += 10f
}
@@ -297,7 +304,7 @@ class TextInterpolatorTest : SysuiTestCase() {
fun testGlyphCallback_Color() {
val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
val interp = TextInterpolator(layout).apply {
val interp = TextInterpolator(layout, typefaceCache).apply {
glyphFilter = { glyph, progress ->
glyph.color = Color.RED
}