xref: /aosp_15_r20/external/lottie/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottiePainter.kt (revision bb5273fecd5c61b9ace70f9ff4fcd88f0e12e3f7)

<lambda>null1 package com.airbnb.lottie.compose
2 
3 import android.graphics.Matrix
4 import android.graphics.Typeface
5 import androidx.compose.runtime.Composable
6 import androidx.compose.runtime.getValue
7 import androidx.compose.runtime.mutableFloatStateOf
8 import androidx.compose.runtime.mutableStateOf
9 import androidx.compose.runtime.remember
10 import androidx.compose.runtime.setValue
11 import androidx.compose.ui.geometry.Size
12 import androidx.compose.ui.graphics.drawscope.DrawScope
13 import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
14 import androidx.compose.ui.graphics.nativeCanvas
15 import androidx.compose.ui.graphics.painter.Painter
16 import androidx.compose.ui.layout.ScaleFactor
17 import androidx.compose.ui.unit.IntSize
18 import com.airbnb.lottie.AsyncUpdates
19 import com.airbnb.lottie.LottieComposition
20 import com.airbnb.lottie.LottieDrawable
21 import com.airbnb.lottie.RenderMode
22 import kotlin.math.roundToInt
23 
24 /**
25  * A composable that makes it easy to create a [LottiePainter] and update its properties.
26  */
27 @Composable
28 fun rememberLottiePainter(
29     composition: LottieComposition? = null,
30     progress: Float = 0f,
31     outlineMasksAndMattes: Boolean = false,
32     applyOpacityToLayers: Boolean = false,
33     enableMergePaths: Boolean = false,
34     renderMode: RenderMode = RenderMode.AUTOMATIC,
35     maintainOriginalImageBounds: Boolean = false,
36     dynamicProperties: LottieDynamicProperties? = null,
37     clipToCompositionBounds: Boolean = true,
38     clipTextToBoundingBox: Boolean = false,
39     fontMap: Map<String, Typeface>? = null,
40     asyncUpdates: AsyncUpdates = AsyncUpdates.AUTOMATIC,
41 ): LottiePainter {
42     val painter = remember { LottiePainter() }
43     painter.composition = composition
44     painter.progress = progress
45     painter.outlineMasksAndMattes = outlineMasksAndMattes
46     painter.applyOpacityToLayers = applyOpacityToLayers
47     painter.enableMergePaths = enableMergePaths
48     painter.renderMode = renderMode
49     painter.maintainOriginalImageBounds = maintainOriginalImageBounds
50     painter.dynamicProperties = dynamicProperties
51     painter.clipToCompositionBounds = clipToCompositionBounds
52     painter.clipTextToBoundingBox = clipTextToBoundingBox
53     painter.fontMap = fontMap
54     painter.asyncUpdates = asyncUpdates
55     return painter
56 }
57 
58 /**
59  * A [Painter] that renders a [LottieComposition].
60  */
61 class LottiePainter internal constructor(
62     composition: LottieComposition? = null,
63     progress: Float = 0f,
64     outlineMasksAndMattes: Boolean = false,
65     applyOpacityToLayers: Boolean = false,
66     enableMergePaths: Boolean = false,
67     renderMode: RenderMode = RenderMode.AUTOMATIC,
68     maintainOriginalImageBounds: Boolean = false,
69     dynamicProperties: LottieDynamicProperties? = null,
70     clipToCompositionBounds: Boolean = true,
71     clipTextToBoundingBox: Boolean = false,
72     fontMap: Map<String, Typeface>? = null,
73     asyncUpdates: AsyncUpdates = AsyncUpdates.AUTOMATIC,
74 ) : Painter() {
75     internal var composition by mutableStateOf(composition)
76     internal var progress by mutableFloatStateOf(progress)
77     internal var outlineMasksAndMattes by mutableStateOf(outlineMasksAndMattes)
78     internal var applyOpacityToLayers by mutableStateOf(applyOpacityToLayers)
79     internal var enableMergePaths by mutableStateOf(enableMergePaths)
80     internal var renderMode by mutableStateOf(renderMode)
81     internal var maintainOriginalImageBounds by mutableStateOf(maintainOriginalImageBounds)
82     internal var dynamicProperties by mutableStateOf(dynamicProperties)
83     internal var clipToCompositionBounds by mutableStateOf(clipToCompositionBounds)
84     internal var fontMap by mutableStateOf(fontMap)
85     internal var asyncUpdates by mutableStateOf(asyncUpdates)
86     internal var clipTextToBoundingBox by mutableStateOf(clipTextToBoundingBox)
87 
88     private var setDynamicProperties: LottieDynamicProperties? = null
89 
90     private val drawable = LottieDrawable()
91     private val matrix = Matrix()
92     override val intrinsicSize: Size
93         get() {
94             val composition = composition ?: return Size.Unspecified
95             return Size(composition.bounds.width().toFloat(), composition.bounds.height().toFloat())
96         }
97 
onDrawnull98     override fun DrawScope.onDraw() {
99         val composition = composition ?: return
100         drawIntoCanvas { canvas ->
101             val compositionSize = Size(composition.bounds.width().toFloat(), composition.bounds.height().toFloat())
102             val intSize = IntSize(size.width.roundToInt(), size.height.roundToInt())
103 
104             matrix.reset()
105             matrix.preScale(intSize.width / compositionSize.width, intSize.height / compositionSize.height)
106 
107             drawable.enableMergePathsForKitKatAndAbove(enableMergePaths)
108             drawable.renderMode = renderMode
109             drawable.asyncUpdates = asyncUpdates
110             drawable.composition = composition
111             drawable.setFontMap(fontMap)
112             if (dynamicProperties !== setDynamicProperties) {
113                 setDynamicProperties?.removeFrom(drawable)
114                 dynamicProperties?.addTo(drawable)
115                 setDynamicProperties = dynamicProperties
116             }
117             drawable.setOutlineMasksAndMattes(outlineMasksAndMattes)
118             drawable.isApplyingOpacityToLayersEnabled = applyOpacityToLayers
119             drawable.maintainOriginalImageBounds = maintainOriginalImageBounds
120             drawable.clipToCompositionBounds = clipToCompositionBounds
121             drawable.clipTextToBoundingBox = clipTextToBoundingBox
122             drawable.progress = progress
123             drawable.setBounds(0, 0, composition.bounds.width(), composition.bounds.height())
124             drawable.draw(canvas.nativeCanvas, matrix)
125         }
126 
127     }
128 }
129 
timesnull130 private operator fun Size.times(scale: ScaleFactor): IntSize {
131     return IntSize((width * scale.scaleX).toInt(), (height * scale.scaleY).toInt())
132 }
133