@@ -24,20 +24,27 @@ import androidx.compose.ui.semantics.SemanticsNode
24
24
import androidx.compose.ui.semantics.SemanticsOwner
25
25
import androidx.compose.ui.text.MultiParagraph
26
26
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection
27
+ import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.AsyncImagePainterClass
27
28
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.BitmapField
29
+ import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.ChildFieldOfModifierNode
28
30
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.CompositionField
29
31
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.ContentPainterElementClass
30
32
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.ContentPainterModifierClass
31
33
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.GetInnerLayerCoordinatorMethod
32
34
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.GetInteropViewMethod
35
+ import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.HeadFieldOfNodeChain
33
36
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.ImageField
34
37
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.LayoutField
35
38
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.LayoutNodeField
39
+ import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.NodesFieldOfLayoutNode
36
40
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterElementClass
37
41
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterField
38
42
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterFieldOfAsyncImagePainter
39
43
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterFieldOfContentPainterElement
40
44
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterFieldOfContentPainterModifier
45
+ import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterFieldOfPainterNode
46
+ import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterMethodOfAsync3ImagePainter
47
+ import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.PainterNodeClass
41
48
import com.datadog.android.sessionreplay.compose.internal.reflection.ComposeReflection.StaticLayoutField
42
49
import com.datadog.android.sessionreplay.compose.internal.reflection.getSafe
43
50
@@ -141,6 +148,31 @@ internal class ReflectionUtils {
141
148
}
142
149
}
143
150
151
+ fun getCoil3AsyncImagePainter (semanticsNode : SemanticsNode ): Painter ? {
152
+ // Check if Coil3 ContentPainterNode is present first to optimize the performance
153
+ // by skipping the node chain iteration
154
+ if (PainterNodeClass == null ) {
155
+ return null
156
+ }
157
+ val layoutNode = LayoutNodeField ?.getSafe(semanticsNode)
158
+ val nodeChain = NodesFieldOfLayoutNode ?.getSafe(layoutNode)
159
+ val headNode = HeadFieldOfNodeChain ?.getSafe(nodeChain) as ? Modifier .Node
160
+ var currentNode = headNode
161
+ var painterNode: Modifier .Node ? = null
162
+ // Iterate NodeChain to find Coil3 `ContentPainterNode`
163
+ while (currentNode != null ) {
164
+ if (currentNode::class .java == PainterNodeClass ) {
165
+ painterNode = currentNode
166
+ break
167
+ }
168
+ currentNode = ChildFieldOfModifierNode ?.getSafe(currentNode) as ? Modifier .Node
169
+ }
170
+ val asyncImagePainter = PainterFieldOfPainterNode ?.getSafe(painterNode)
171
+ val painter =
172
+ asyncImagePainter?.let { PainterMethodOfAsync3ImagePainter ?.invoke(it) }
173
+ return painter as ? Painter
174
+ }
175
+
144
176
fun getLocalImagePainter (semanticsNode : SemanticsNode ): Painter ? {
145
177
val modifier = semanticsNode.layoutInfo.getModifierInfo().firstOrNull {
146
178
PainterElementClass ?.isInstance(it.modifier) == true
@@ -149,6 +181,11 @@ internal class ReflectionUtils {
149
181
}
150
182
151
183
fun getAsyncImagePainter (semanticsNode : SemanticsNode ): Painter ? {
184
+ // Check if Coil AsyncImagePainter is present first to optimize the performance
185
+ // by skipping the modifier iteration
186
+ if (AsyncImagePainterClass == null ) {
187
+ return null
188
+ }
152
189
val asyncPainter = semanticsNode.layoutInfo.getModifierInfo().firstNotNullOfOrNull {
153
190
if (ContentPainterModifierClass ?.isInstance(it.modifier) == true ) {
154
191
PainterFieldOfContentPainterModifier ?.getSafe(it.modifier)
0 commit comments