Skip to content

Commit

Permalink
fix animation junk after the first loop
Browse files Browse the repository at this point in the history
  • Loading branch information
alexzhirkevich committed Oct 15, 2024
1 parent 054cece commit 3f13866
Show file tree
Hide file tree
Showing 24 changed files with 57 additions and 117 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.github.alexzhirkevich.compottie

import android.app.Activity
import android.app.Application
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.createFontFamilyResolver
Expand All @@ -9,7 +8,7 @@ import androidx.compose.ui.text.font.createFontFamilyResolver
@OptIn(InternalCompottieApi::class)
internal actual fun makeFontFamilyResolver() : FontFamily.Resolver {
return createFontFamilyResolver(
requireNotNull(Compottie.context){
checkNotNull(Compottie.context){
"Compottie failed to initialize"
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ internal actual fun ExtendedPathMeasure() : ExtendedPathMeasure = AndroidExtende
private val tempAndroidMatrix = android.graphics.Matrix()
internal actual fun Path.addPath(path: Path, matrix: Matrix) : Path {
return asAndroidPath().apply {
addPath(path.asAndroidPath(), tempAndroidMatrix.apply {
reset()
setFromInternal(matrix)
})
addPath(
path.asAndroidPath(),
tempAndroidMatrix.apply {
reset()
setFromInternal(matrix)
}
)
}.asComposePath()
}

//
//internal actual fun Path.set(other : Path) {
// asAndroidPath().set(other.asAndroidPath())
//}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package io.github.alexzhirkevich.compottie

import io.github.alexzhirkevich.compottie.internal.Animation
import io.github.alexzhirkevich.compottie.internal.LottieJson

public object Compottie {

public const val IterateForever : Int = Int.MAX_VALUE
Expand All @@ -25,30 +22,15 @@ public object Compottie {
* All running animations will shrink their shader cache size.
* */
@ExperimentalCompottieApi
public var shaderCacheLimit : Int = 15
public var shaderCacheLimit : Int = 10

/**
* Limit the number of in-memory cached lottie compositions.
* */
@ExperimentalCompottieApi
public var compositionCacheLimit : Int = 15

/**
* Warmup JSON parser. The first animation parsing will be much faster
* */
@ExperimentalCompottieApi
public fun warmup() {
LottieJson.decodeFromString<Animation>(warmupAnim)
}
public var compositionCacheLimit : Int = 10

@InternalCompottieApi
public var context : LottieContext? = null
internal set
}


private val warmupAnim by lazy {
"""
{"v":"5.7.1","fr":60,"ip":0,"op":181,"w":500,"h":500,"nm":"Comp 1","ddd":0,"fonts":{"list":[{"fPath":"","fFamily":"","fStyle":"","fName":"","origin":3}]},"assets":[{"id":"comp_0","layers":[]},{"id":"blep","h":512,"w":512,"u":"/images/","p":"blep.png","e":1}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,268,0],"ix":2},"a":{"a":0,"k":[1000,1000,0],"ix":1},"s":{"a":0,"k":[27,27,100],"ix":6}},"ao":0,"w":2000,"h":2000,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":1,"ty":4,"nm":"рука 1.1 Outlines 2","cl":"1","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[195.262,126.787,0],"ix":2},"a":{"a":0,"k":[195.262,126.787,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"mode":"a","o":{"a":0,"k":100},"inv":false,"x":{"a":0,"k":0},"pt":{"a":0,"k":{"c":true,"v":[[247.109,125.719],[66.109,306.719],[424.109,389.719]],"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]]}}}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.885,0.104],[-0.781,0.233]],"o":[[-0.629,-0.074],[0.782,-0.232]],"v":[[-0.258,-2.695],[0.105,2.535]],"c":true},"ix":2},"nm":"Path 1","hd":false},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0,"y":1},"s":[0],"t":5},{"s":[100],"t":22}],"ix":2},"o":{"a":0,"k":0,"ix":3},"s":{"a":1,"k":[{"o":{"x":0.463,"y":0},"i":{"x":0.853,"y":1},"s":[0],"t":22},{"s":[100],"t":36}],"ix":1},"m":1},{"ty":"mm","mm":4,"nm":"Merge Paths 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[192.227,107.118],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"hd":false}],"ip":0,"op":600,"st":0,"bm":0},{"nm":"Text Layer","ty":5,"sr":1,"ks":{"p":{"k":[5,80],"a":0}},"ip":0,"op":120,"st":0,"t":{"a":[],"d":{"k":[{"s":{"f":"Ubuntu Light Italic","fc":[0,0,0],"s":100,"t":"Hello","j":0,"sc":[0,0,0],"sw":0},"t":0}]},"m":{"a":{"k":[0,0],"a":0}},"p":{}}},{"ddd":0,"ty":2,"sr":1,"ks":{"a":{"k":[0,0],"a":0},"p":{"k":[0,0],"a":0},"s":{"k":[100,100],"a":0},"r":{"k":0,"a":0},"o":{"k":100,"a":0},"sk":{"k":0,"a":0},"sa":{"k":0,"a":0}},"ao":0,"ip":0,"op":60,"st":0,"bm":0,"ind":0,"refId":"blep"}],"markers":[]}
""".trimIndent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import kotlin.time.Duration
import kotlin.time.Duration.Companion.microseconds
import kotlin.time.measureTime

internal object UnspecifiedCompositionKey

/**
* Load and prepare [LottieComposition] for displaying.
Expand All @@ -64,7 +64,7 @@ public fun rememberLottieComposition(
LaunchedEffect(result) {
try {
val composition = withContext(Compottie.ioDispatcher()) {
val specInstance = updatedSpec()
val specInstance = updatedSpec()
val k = when (key) {
UnspecifiedCompositionKey -> specInstance.key
null -> null
Expand Down Expand Up @@ -343,3 +343,4 @@ public class LottieComposition internal constructor(
}
}

private object UnspecifiedCompositionKey
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import kotlinx.serialization.json.jsonPrimitive
@Serializable(with = AnimatedShapeSerializer::class)
internal sealed interface AnimatedShape : AnimatedProperty<Path> {

fun interpolatedMutable(state: AnimationState): Path

fun rawBezier(state: AnimationState) : Bezier

fun copy(): AnimatedShape
Expand Down Expand Up @@ -55,10 +53,6 @@ internal sealed interface AnimatedShape : AnimatedProperty<Path> {
return tmpPath
}

override fun interpolatedMutable(state: AnimationState): Path {
return Path().apply { bezier.mapPath(this) }
}

override fun copy(): AnimatedShape {
return Default(
expression = expression,
Expand Down Expand Up @@ -90,11 +84,11 @@ internal sealed interface AnimatedShape : AnimatedProperty<Path> {
private var bezierDelegate = BaseKeyframeAnimation(
index = index,
keyframes = keyframes,
emptyValue = Bezier(),
emptyValue = tmpBezier,
map = { s, e, p ->
tmpBezier.interpolateBetween(s, e, easingX.transform(p))
tmpBezier
}
},
)

@Transient
Expand All @@ -109,31 +103,13 @@ internal sealed interface AnimatedShape : AnimatedProperty<Path> {
}
)

@Transient
private var mutableDelegate = BaseKeyframeAnimation(
index = index,
keyframes = keyframes,
emptyValue = tmpPath,
map = { s, e, p ->
tmpBezier.interpolateBetween(s, e, easingX.transform(p))

Path().apply {
tmpBezier.mapPath(this)
}
}
)

override fun setClosed(closed: Boolean) {
keyframes.fastForEach {
it.start?.setIsClosed(closed)
it.end?.setIsClosed(closed)
}
}

override fun interpolatedMutable(state: AnimationState): Path {
return mutableDelegate.raw(state)
}

override fun rawBezier(state: AnimationState): Bezier {
return bezierDelegate.raw(state)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ internal sealed class AnimatedVector2 : DynamicProperty<Vec2>() {
emptyValue = Offset.Zero,
map = { s, e, p ->
if (inTangent != null && outTangent != null && s != e) {
path.rewind()
path.reset()
path.createPath(s, e, outTangent, inTangent)
pathMeasure.setPath(path, false)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ internal class BaseKeyframeAnimation<T : Any, K, out KF : Keyframe<K>>(

private val lastFrame: Float by lazy { sortedKeyframes.last().time }

private val initialValue by lazy {
keyframes.first().run {
private val initialValue : T get() {
return sortedKeyframes.first().run {
map(
requireNotNull(
start,
Expand All @@ -43,11 +43,11 @@ internal class BaseKeyframeAnimation<T : Any, K, out KF : Keyframe<K>>(
}
}

private val targetValue by lazy {
private val targetValue : T get() {

val preLast = sortedKeyframes.getOrNull(sortedKeyframes.lastIndex - 1)

keyframes.last().run {
return sortedKeyframes.last().run {
map(
requireNotNull(
preLast?.start ?: start,
Expand All @@ -64,9 +64,6 @@ internal class BaseKeyframeAnimation<T : Any, K, out KF : Keyframe<K>>(

override fun raw(state: AnimationState): T {

if (sortedKeyframes.isEmpty())
return emptyValue

return when {
sortedKeyframes.isEmpty() -> emptyValue
state.frame >= lastFrame -> targetValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ internal class ContentGroupImpl(

private val rect = MutableRect(0f, 0f, 0f, 0f)
private val offscreenRect = MutableRect(0f, 0f, 0f, 0f)
private val offscreenPaint = Paint().apply {
}
private val offscreenPaint = Paint()
private val matrix = Matrix()
private val path = Path()

Expand Down Expand Up @@ -100,12 +99,10 @@ internal class ContentGroupImpl(

override fun getPath(state: AnimationState): Path {

path.rewind()
path.reset()
if (hidden(state)) {
return path
}
matrix.fastReset()

matrix.fastSetFrom(transform.matrix(state))
pathContents.fastForEachReversed {
path.addPath(it.getPath(state), matrix)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ internal class Bezier(
}

fun mapPath(outPath : Path) {
outPath.rewind()
outPath.reset()
outPath.moveTo(initialPoint.x, initialPoint.y)

var pathFromDataCurrentPoint = initialPoint
Expand All @@ -125,7 +125,7 @@ internal class Bezier(
//
// This does its best to add a tiny value to the vertex without affecting the final
// animation as much as possible.
// outPath.relativeMoveTo(0.01f, 0.01f);
// outPath.relativeMoveTo(0.01f, 0.01f);
outPath.lineTo(curve.vertex.x, curve.vertex.y)
} else {
outPath.cubicTo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ internal fun Path.applyTrimPath(
}


tempPath.rewind()
tempPath.reset()
pathMeasure.getSegment(
startDistance = newStart,
stopDistance = newEnd,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ internal abstract class BaseLayer : Layer {
}

masks?.fastForEach { mask ->
val maskPath = mask.shape?.interpolatedMutable(state) ?: return@fastForEach
val maskPath = mask.shape?.interpolated(state) ?: return@fastForEach
path.set(maskPath)
path.transform(matrix)

Expand Down Expand Up @@ -413,7 +413,7 @@ internal abstract class BaseLayer : Layer {
) {
canvas.saveLayer(rect, contentPaint)
canvas.drawRect(rect, contentPaint)
val maskPath = mask.shape?.interpolatedMutable(state) ?: return
val maskPath = mask.shape?.interpolated(state) ?: return
path.set(maskPath)
path.transform(matrix)
contentPaint.alpha = mask.opacity?.interpolatedNorm(state)?.coerceIn(0f, 1f) ?: 1f
Expand All @@ -427,7 +427,7 @@ internal abstract class BaseLayer : Layer {
mask: Mask,
state: AnimationState,
) {
val maskPath = mask.shape?.interpolatedMutable(state) ?: return
val maskPath = mask.shape?.interpolated(state) ?: return
path.set(maskPath)
path.transform(matrix)
contentPaint.alpha = mask.opacity?.interpolatedNorm(state)?.coerceIn(0f, 1f) ?: 1f
Expand All @@ -440,7 +440,7 @@ internal abstract class BaseLayer : Layer {
mask: Mask,
state: AnimationState,
) {
val maskPath = mask.shape?.interpolatedMutable(state) ?: return
val maskPath = mask.shape?.interpolated(state) ?: return
path.set(maskPath)
path.transform(matrix)
canvas.drawPath(path, dstOutPaint)
Expand All @@ -456,7 +456,7 @@ internal abstract class BaseLayer : Layer {
canvas.drawRect(rect, contentPaint)
dstOutPaint.alpha = mask.opacity?.interpolatedNorm(state)
?.coerceIn(0f, 1f) ?: 1f
val maskPath = mask.shape?.interpolatedMutable(state) ?: return
val maskPath = mask.shape?.interpolated(state) ?: return
path.set(maskPath)
path.transform(matrix)
canvas.drawPath(path, dstOutPaint)
Expand All @@ -470,7 +470,7 @@ internal abstract class BaseLayer : Layer {
state: AnimationState,
) {
canvas.saveLayer(rect, dstInPaint)
val maskPath = mask.shape?.interpolatedMutable(state) ?: return
val maskPath = mask.shape?.interpolated(state) ?: return
path.set(maskPath)
path.transform(matrix)
contentPaint.alpha = mask.opacity?.interpolatedNorm(state)?.coerceIn(0f, 1f) ?: 1f
Expand All @@ -487,7 +487,7 @@ internal abstract class BaseLayer : Layer {
canvas.saveLayer(rect, dstInPaint)
canvas.drawRect(rect, contentPaint)
dstOutPaint.alpha = mask.opacity?.interpolatedNorm(state)?.coerceIn(0f, 1f) ?: 1f
val maskPath = mask.shape?.interpolatedMutable(state) ?: return
val maskPath = mask.shape?.interpolated(state) ?: return
path.set(maskPath)
path.transform(matrix)
canvas.drawPath(path, dstOutPaint)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,8 @@ internal data class PrecompositionLayer(
}

override fun compose(state: AnimationState): List<Layer> {
return (state.assets[refId] as? PrecompositionAsset?)?.layers.orEmpty().fastMap {
it.deepCopy()
}
return (state.assets[refId] as? PrecompositionAsset?)?.layers
?.fastMap(Layer::deepCopy).orEmpty()
}

override fun drawLayer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ internal class SolidColorLayer(
return
}

path.rewind()
path.reset()

parentMatrix.map(Offset.Zero).let { path.moveTo(it.x, it.y) }
parentMatrix.map(Offset(width, 0f)).let { path.lineTo(it.x, it.y) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,7 @@ package io.github.alexzhirkevich.compottie.internal.platform

import androidx.compose.ui.graphics.Matrix
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PathFillType
import androidx.compose.ui.graphics.PathMeasure
import androidx.compose.ui.graphics.PathOperation
import io.github.alexzhirkevich.compottie.internal.AnimationState
import io.github.alexzhirkevich.compottie.internal.shapes.TrimPathShape
import io.github.alexzhirkevich.compottie.internal.utils.floorMod
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt

internal expect fun ExtendedPathMeasure() : ExtendedPathMeasure

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ internal abstract class BaseStrokeShape() : Shape, DrawingContent {
if (pathGroup.trimPath != null) {
applyTrimPath(canvas, state, pathGroup)
} else {
path.rewind()
path.reset()
pathGroup.paths.fastForEachReversed {
path.addPath(it.getPath(state))
}
Expand Down Expand Up @@ -243,7 +243,7 @@ internal abstract class BaseStrokeShape() : Shape, DrawingContent {
state: AnimationState,
outBounds: MutableRect,
) {
path.rewind()
path.reset()
pathGroups.fastForEach { pathGroup ->
pathGroup.paths.fastForEach {
path.addPath(it.getPath(state), parentMatrix)
Expand Down Expand Up @@ -279,7 +279,7 @@ internal abstract class BaseStrokeShape() : Shape, DrawingContent {
return
}

path.rewind()
path.reset()

pathGroup.paths.fastForEachReversed {
path.addPath(it.getPath(state))
Expand Down
Loading

0 comments on commit 3f13866

Please sign in to comment.