Cache Outline for PunchHole Transformation

Test: added PunchHoleTest
Bug: b/290184746
Flag: NONE
Change-Id: I252c78cca408be30216fff892fc3705ddcba157c
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/PunchHole.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/PunchHole.kt
index 62d67f0..984086b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/PunchHole.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/PunchHole.kt
@@ -19,9 +19,11 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.geometry.toRect
 import androidx.compose.ui.graphics.BlendMode
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Outline
 import androidx.compose.ui.graphics.Paint
 import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.graphics.Shape
@@ -30,6 +32,7 @@
 import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
 import androidx.compose.ui.graphics.drawscope.translate
 import androidx.compose.ui.graphics.withSaveLayer
+import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.toSize
 import com.android.compose.animation.scene.Element
 import com.android.compose.animation.scene.ElementKey
@@ -43,6 +46,11 @@
     private val bounds: ElementKey,
     private val shape: Shape,
 ) : ModifierTransformation {
+
+    private var lastSize: Size = Size.Unspecified
+    private var lastLayoutDirection: LayoutDirection = LayoutDirection.Ltr
+    private var lastOutline: Outline? = null
+
     override fun Modifier.transform(
         layoutImpl: SceneTransitionLayoutImpl,
         scene: Scene,
@@ -59,7 +67,6 @@
                 drawContent()
                 return@drawWithContent
             }
-
             drawIntoCanvas { canvas ->
                 canvas.withSaveLayer(size.toRect(), Paint()) {
                     drawContent()
@@ -78,13 +85,19 @@
             return
         }
 
-        // TODO(b/290184746): Cache outline if the size of bounds does not change.
+        val outline =
+            if (boundsSize == lastSize && layoutDirection == lastLayoutDirection) {
+                lastOutline!!
+            } else {
+                val newOutline = shape.createOutline(boundsSize, layoutDirection, this)
+                lastSize = boundsSize
+                lastLayoutDirection = layoutDirection
+                lastOutline = newOutline
+                newOutline
+            }
+
         drawOutline(
-            shape.createOutline(
-                boundsSize,
-                layoutDirection,
-                this,
-            ),
+            outline,
             Color.Black,
             blendMode = BlendMode.DstOut,
         )