1 /*
<lambda>null2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 @file:Suppress("DEPRECATION")
18 
19 package androidx.compose.ui.layout
20 
21 import androidx.collection.IntObjectMap
22 import androidx.collection.intObjectMapOf
23 import androidx.compose.ui.ExperimentalComposeUiApi
24 import androidx.compose.ui.InternalComposeUiApi
25 import androidx.compose.ui.autofill.Autofill
26 import androidx.compose.ui.autofill.AutofillManager
27 import androidx.compose.ui.autofill.AutofillTree
28 import androidx.compose.ui.draganddrop.DragAndDropManager
29 import androidx.compose.ui.focus.FocusOwner
30 import androidx.compose.ui.geometry.MutableRect
31 import androidx.compose.ui.geometry.Offset
32 import androidx.compose.ui.graphics.Canvas
33 import androidx.compose.ui.graphics.GraphicsContext
34 import androidx.compose.ui.graphics.Matrix
35 import androidx.compose.ui.graphics.ReusableGraphicsLayerScope
36 import androidx.compose.ui.graphics.layer.GraphicsLayer
37 import androidx.compose.ui.hapticfeedback.HapticFeedback
38 import androidx.compose.ui.input.InputModeManager
39 import androidx.compose.ui.input.key.KeyEvent
40 import androidx.compose.ui.input.pointer.PointerIconService
41 import androidx.compose.ui.modifier.ModifierLocalManager
42 import androidx.compose.ui.node.InternalCoreApi
43 import androidx.compose.ui.node.LayoutNode
44 import androidx.compose.ui.node.LayoutNodeDrawScope
45 import androidx.compose.ui.node.MeasureAndLayoutDelegate
46 import androidx.compose.ui.node.OwnedLayer
47 import androidx.compose.ui.node.Owner
48 import androidx.compose.ui.node.OwnerSnapshotObserver
49 import androidx.compose.ui.node.RootForTest
50 import androidx.compose.ui.platform.AccessibilityManager
51 import androidx.compose.ui.platform.Clipboard
52 import androidx.compose.ui.platform.ClipboardManager
53 import androidx.compose.ui.platform.PlatformTextInputSessionScope
54 import androidx.compose.ui.platform.SoftwareKeyboardController
55 import androidx.compose.ui.platform.TextToolbar
56 import androidx.compose.ui.platform.ViewConfiguration
57 import androidx.compose.ui.platform.WindowInfo
58 import androidx.compose.ui.semantics.EmptySemanticsModifier
59 import androidx.compose.ui.semantics.SemanticsOwner
60 import androidx.compose.ui.spatial.RectManager
61 import androidx.compose.ui.text.font.Font
62 import androidx.compose.ui.text.font.FontFamily
63 import androidx.compose.ui.text.input.TextInputService
64 import androidx.compose.ui.unit.Constraints
65 import androidx.compose.ui.unit.Density
66 import androidx.compose.ui.unit.IntOffset
67 import androidx.compose.ui.unit.IntSize
68 import androidx.compose.ui.unit.LayoutDirection
69 import androidx.compose.ui.viewinterop.InteropView
70 import com.google.common.truth.Truth
71 import java.util.concurrent.Executors
72 import kotlin.coroutines.CoroutineContext
73 import kotlin.math.max
74 import kotlin.math.min
75 import kotlinx.coroutines.asCoroutineDispatcher
76 
77 internal fun createDelegate(
78     root: LayoutNode,
79     firstMeasureCompleted: Boolean = true,
80     createLayer: () -> OwnedLayer = { TODO() }
81 ): MeasureAndLayoutDelegate {
82     val delegate = MeasureAndLayoutDelegate(root)
83     root.attach(FakeOwner(delegate, createLayer))
84     if (firstMeasureCompleted) {
85         delegate.updateRootConstraints(defaultRootConstraints())
86         Truth.assertThat(delegate.measureAndLayout()).isTrue()
87     }
88     return delegate
89 }
90 
91 @OptIn(InternalComposeUiApi::class)
92 private class FakeOwner(
93     val delegate: MeasureAndLayoutDelegate,
94     val createLayer: () -> OwnedLayer,
95     override val coroutineContext: CoroutineContext =
96         Executors.newFixedThreadPool(3).asCoroutineDispatcher()
97 ) : Owner {
98     override val measureIteration: Long
99         get() = delegate.measureIteration
100 
onRequestMeasurenull101     override fun onRequestMeasure(
102         layoutNode: LayoutNode,
103         affectsLookahead: Boolean,
104         forceRequest: Boolean,
105         scheduleMeasureAndLayout: Boolean
106     ) {
107         if (affectsLookahead) {
108             delegate.requestLookaheadRemeasure(layoutNode)
109         } else {
110             delegate.requestRemeasure(layoutNode)
111         }
112     }
113 
onRequestRelayoutnull114     override fun onRequestRelayout(
115         layoutNode: LayoutNode,
116         affectsLookahead: Boolean,
117         forceRequest: Boolean
118     ) {
119         if (affectsLookahead) {
120             delegate.requestLookaheadRelayout(layoutNode, forceRequest)
121         } else {
122             delegate.requestRelayout(layoutNode, forceRequest)
123         }
124     }
125 
measureAndLayoutnull126     override fun measureAndLayout(sendPointerUpdate: Boolean) {
127         delegate.measureAndLayout()
128     }
129 
measureAndLayoutnull130     override fun measureAndLayout(layoutNode: LayoutNode, constraints: Constraints) {
131         delegate.measureAndLayout(layoutNode, constraints)
132     }
133 
forceMeasureTheSubtreenull134     override fun forceMeasureTheSubtree(layoutNode: LayoutNode, affectsLookahead: Boolean) {
135         delegate.forceMeasureTheSubtree(layoutNode, affectsLookahead)
136     }
137 
<lambda>null138     override val snapshotObserver: OwnerSnapshotObserver = OwnerSnapshotObserver { it.invoke() }
139 
140     override val modifierLocalManager: ModifierLocalManager = ModifierLocalManager(this)
141 
142     override val dragAndDropManager: DragAndDropManager
143         get() = TODO("Not yet implemented")
144 
registerOnEndApplyChangesListenernull145     override fun registerOnEndApplyChangesListener(listener: () -> Unit) {
146         TODO("Not yet implemented")
147     }
148 
onEndApplyChangesnull149     override fun onEndApplyChanges() {
150         TODO("Not yet implemented")
151     }
152 
registerOnLayoutCompletedListenernull153     override fun registerOnLayoutCompletedListener(listener: Owner.OnLayoutCompletedListener) {
154         TODO("Not yet implemented")
155     }
156 
onLayoutChangenull157     override fun onLayoutChange(layoutNode: LayoutNode) {}
158 
onLayoutNodeDeactivatednull159     override fun onLayoutNodeDeactivated(layoutNode: LayoutNode) {}
160 
onInteropViewLayoutChangenull161     override fun onInteropViewLayoutChange(view: InteropView) {}
162 
163     @OptIn(InternalCoreApi::class) override var showLayoutBounds: Boolean = false
164 
onPreAttachnull165     override fun onPreAttach(node: LayoutNode) {}
166 
onPostAttachnull167     override fun onPostAttach(node: LayoutNode) {}
168 
onDetachnull169     override fun onDetach(node: LayoutNode) {}
170 
171     override val root: LayoutNode = LayoutNode()
172 
173     override val semanticsOwner: SemanticsOwner
174         get() = SemanticsOwner(root, EmptySemanticsModifier(), intObjectMapOf())
175 
176     override val layoutNodes: IntObjectMap<LayoutNode>
177         get() = TODO("Not yet implemented")
178 
179     override val sharedDrawScope: LayoutNodeDrawScope
180         get() = TODO("Not yet implemented")
181 
182     override val rootForTest: RootForTest
183         get() = TODO("Not yet implemented")
184 
185     override val hapticFeedBack: HapticFeedback
186         get() = TODO("Not yet implemented")
187 
188     override val inputModeManager: InputModeManager
189         get() = TODO("Not yet implemented")
190 
191     override val clipboardManager: ClipboardManager
192         get() = TODO("Not yet implemented")
193 
194     override val clipboard: Clipboard
195         get() = TODO("Not yet implemented")
196 
197     override val accessibilityManager: AccessibilityManager
198         get() = TODO("Not yet implemented")
199 
200     override val graphicsContext: GraphicsContext
201         get() = TODO("Not yet implemented")
202 
203     override val textToolbar: TextToolbar
204         get() = TODO("Not yet implemented")
205 
206     override val density: Density
207         get() = TODO("Not yet implemented")
208 
209     override val textInputService: TextInputService
210         get() = TODO("Not yet implemented")
211 
212     override val softwareKeyboardController: SoftwareKeyboardController
213         get() = TODO("Not yet implemented")
214 
textInputSessionnull215     override suspend fun textInputSession(
216         session: suspend PlatformTextInputSessionScope.() -> Nothing
217     ): Nothing {
218         TODO("Not yet implemented")
219     }
220 
screenToLocalnull221     override fun screenToLocal(positionOnScreen: Offset): Offset {
222         TODO("Not yet implemented")
223     }
224 
localToScreennull225     override fun localToScreen(localPosition: Offset): Offset {
226         TODO("Not yet implemented")
227     }
228 
229     override val pointerIconService: PointerIconService
230         get() = TODO("Not yet implemented")
231 
232     override val focusOwner: FocusOwner
233         get() = TODO("Not yet implemented")
234 
235     override val windowInfo: WindowInfo
236         get() = TODO("Not yet implemented")
237 
238     override val rectManager: RectManager = RectManager()
239 
240     @Deprecated(
241         "fontLoader is deprecated, use fontFamilyResolver",
242         replaceWith = ReplaceWith("fontFamilyResolver")
243     )
244     @Suppress("OverridingDeprecatedMember", "DEPRECATION")
245     override val fontLoader: Font.ResourceLoader
246         get() = TODO("Not yet implemented")
247 
248     override val fontFamilyResolver: FontFamily.Resolver
249         get() = TODO("Not yet implemented")
250 
251     override val layoutDirection: LayoutDirection
252         get() = LayoutDirection.Ltr
253 
254     override val viewConfiguration: ViewConfiguration
255         get() = TODO("Not yet implemented")
256 
257     override val autofillTree: AutofillTree
258         get() = TODO("Not yet implemented")
259 
260     override val autofill: Autofill
261         get() = TODO("Not yet implemented")
262 
263     @ExperimentalComposeUiApi
264     override val autofillManager: AutofillManager?
265         get() = TODO("Not yet implemented")
266 
createLayernull267     override fun createLayer(
268         drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
269         invalidateParentLayer: () -> Unit,
270         explicitLayer: GraphicsLayer?,
271         forceUseOldLayers: Boolean
272     ): OwnedLayer = createLayer()
273 
274     override fun requestOnPositionedCallback(layoutNode: LayoutNode) {
275         TODO("Not yet implemented")
276     }
277 
calculatePositionInWindownull278     override fun calculatePositionInWindow(localPosition: Offset) = TODO("Not yet implemented")
279 
280     override fun calculateLocalPosition(positionInWindow: Offset) = TODO("Not yet implemented")
281 
282     override fun requestFocus() = TODO("Not yet implemented")
283 
284     override fun requestAutofill(node: LayoutNode) {
285         TODO("Not yet implemented")
286     }
287 
onSemanticsChangenull288     override fun onSemanticsChange() {}
289 
getFocusDirectionnull290     override fun getFocusDirection(keyEvent: KeyEvent) = TODO("Not yet implemented")
291 }
292 
293 internal fun defaultRootConstraints() = Constraints(maxWidth = 100, maxHeight = 100)
294 
295 internal fun assertNotRemeasured(node: LayoutNode, block: (LayoutNode) -> Unit) {
296     val measuresCountBefore = node.measuresCount
297     block(node)
298     Truth.assertThat(node.measuresCount).isEqualTo(measuresCountBefore)
299 }
300 
assertRemeasurednull301 internal fun assertRemeasured(
302     node: LayoutNode,
303     times: Int = 1,
304     withDirection: LayoutDirection? = null,
305     block: (LayoutNode) -> Unit
306 ) {
307     val measuresCountBefore = node.measuresCount
308     block(node)
309     Truth.assertThat(node.measuresCount).isEqualTo(measuresCountBefore + times)
310     if (withDirection != null) {
311         Truth.assertThat(node.measuredWithLayoutDirection).isEqualTo(withDirection)
312     }
313     assertMeasuredAndLaidOut(node)
314 }
315 
assertRelaidOutnull316 internal fun assertRelaidOut(node: LayoutNode, times: Int = 1, block: (LayoutNode) -> Unit) {
317     val layoutsCountBefore = node.layoutsCount
318     block(node)
319     Truth.assertThat(node.layoutsCount).isEqualTo(layoutsCountBefore + times)
320     assertMeasuredAndLaidOut(node)
321 }
322 
assertNotRelaidOutnull323 internal fun assertNotRelaidOut(node: LayoutNode, block: (LayoutNode) -> Unit) {
324     val layoutsCountBefore = node.layoutsCount
325     block(node)
326     Truth.assertThat(node.layoutsCount).isEqualTo(layoutsCountBefore)
327 }
328 
assertMeasureRequirednull329 internal fun assertMeasureRequired(node: LayoutNode) {
330     Truth.assertThat(node.measurePending).isTrue()
331 }
332 
assertMeasuredAndLaidOutnull333 internal fun assertMeasuredAndLaidOut(node: LayoutNode) {
334     Truth.assertThat(node.layoutState).isEqualTo(LayoutNode.LayoutState.Idle)
335     Truth.assertThat(node.layoutPending).isFalse()
336     Truth.assertThat(node.measurePending).isFalse()
337 }
338 
assertLayoutRequirednull339 internal fun assertLayoutRequired(node: LayoutNode) {
340     Truth.assertThat(node.layoutPending).isTrue()
341 }
342 
assertRemeasurednull343 internal fun assertRemeasured(modifier: SpyLayoutModifier, block: () -> Unit) {
344     val measuresCountBefore = modifier.measuresCount
345     block()
346     Truth.assertThat(modifier.measuresCount).isEqualTo(measuresCountBefore + 1)
347 }
348 
assertNotRemeasurednull349 internal fun assertNotRemeasured(modifier: SpyLayoutModifier, block: () -> Unit) {
350     val measuresCountBefore = modifier.measuresCount
351     block()
352     Truth.assertThat(modifier.measuresCount).isEqualTo(measuresCountBefore)
353 }
354 
assertRelaidOutnull355 internal fun assertRelaidOut(modifier: SpyLayoutModifier, block: () -> Unit) {
356     val layoutsCountBefore = modifier.layoutsCount
357     block()
358     Truth.assertThat(modifier.layoutsCount).isEqualTo(layoutsCountBefore + 1)
359 }
360 
<lambda>null361 internal fun root(block: LayoutNode.() -> Unit = {}): LayoutNode {
362     return node(block)
363 }
364 
<lambda>null365 internal fun node(block: LayoutNode.() -> Unit = {}): LayoutNode {
<lambda>null366     return LayoutNode().apply {
367         measurePolicy = MeasureInMeasureBlock()
368         block.invoke(this)
369     }
370 }
371 
<lambda>null372 internal fun virtualNode(block: LayoutNode.() -> Unit = {}): LayoutNode {
<lambda>null373     return LayoutNode(isVirtual = true).apply {
374         measurePolicy = MeasureInMeasureBlock()
375         block.invoke(this)
376     }
377 }
378 
addnull379 internal fun LayoutNode.add(child: LayoutNode) = insertAt(foldedChildren.count(), child)
380 
381 internal fun LayoutNode.measureInLayoutBlock() {
382     measurePolicy = MeasureInLayoutBlock()
383 }
384 
doNotMeasurenull385 internal fun LayoutNode.doNotMeasure() {
386     measurePolicy = NoMeasure()
387 }
388 
queryAlignmentLineDuringMeasurenull389 internal fun LayoutNode.queryAlignmentLineDuringMeasure() {
390     (measurePolicy as SmartMeasurePolicy).queryAlignmentLinesDuringMeasure = true
391 }
392 
runDuringMeasurenull393 internal fun LayoutNode.runDuringMeasure(once: Boolean = true, block: () -> Unit) {
394     (measurePolicy as SmartMeasurePolicy).preMeasureCallback = block
395     (measurePolicy as SmartMeasurePolicy).shouldClearPreMeasureCallback = once
396 }
397 
runDuringLayoutnull398 internal fun LayoutNode.runDuringLayout(once: Boolean = true, block: () -> Unit) {
399     (measurePolicy as SmartMeasurePolicy).preLayoutCallback = block
400     (measurePolicy as SmartMeasurePolicy).shouldClearPreLayoutCallback = once
401 }
402 
403 internal val LayoutNode.first: LayoutNode
404     get() = children.first()
405 internal val LayoutNode.second: LayoutNode
406     get() = children[1]
407 internal val LayoutNode.measuresCount: Int
408     get() = (measurePolicy as SmartMeasurePolicy).measuresCount
409 internal val LayoutNode.layoutsCount: Int
410     get() = (measurePolicy as SmartMeasurePolicy).layoutsCount
411 internal var LayoutNode.wrapChildren: Boolean
412     get() = (measurePolicy as SmartMeasurePolicy).wrapChildren
413     set(value) {
414         (measurePolicy as SmartMeasurePolicy).wrapChildren = value
415     }
416 internal val LayoutNode.measuredWithLayoutDirection: LayoutDirection
417     get() = (measurePolicy as SmartMeasurePolicy).measuredLayoutDirection!!
418 internal var LayoutNode.size: Int?
419     get() = (measurePolicy as SmartMeasurePolicy).size
420     set(value) {
421         (measurePolicy as SmartMeasurePolicy).size = value
422     }
423 internal var LayoutNode.childrenDirection: LayoutDirection?
424     get() = (measurePolicy as SmartMeasurePolicy).childrenLayoutDirection
425     set(value) {
426         (measurePolicy as SmartMeasurePolicy).childrenLayoutDirection = value
427     }
428 internal var LayoutNode.shouldPlaceChildren: Boolean
429     get() = (measurePolicy as SmartMeasurePolicy).shouldPlaceChildren
430     set(value) {
431         (measurePolicy as SmartMeasurePolicy).shouldPlaceChildren = value
432     }
433 internal var LayoutNode.placeWithLayer: Boolean
434     get() = (measurePolicy as SmartMeasurePolicy).placeWithLayer
435     set(value) {
436         (measurePolicy as SmartMeasurePolicy).placeWithLayer = value
437     }
438 
439 internal val TestAlignmentLine = HorizontalAlignmentLine(::min)
440 
441 internal abstract class SmartMeasurePolicy : LayoutNode.NoIntrinsicsMeasurePolicy("") {
442     var measuresCount = 0
443         protected set
444 
445     var layoutsCount = 0
446         protected set
447 
448     open var wrapChildren = false
449     open var queryAlignmentLinesDuringMeasure = false
450     var preMeasureCallback: (() -> Unit)? = null
451     var shouldClearPreMeasureCallback = false
452     var preLayoutCallback: (() -> Unit)? = null
453     var shouldClearPreLayoutCallback = false
454     var measuredLayoutDirection: LayoutDirection? = null
455         protected set
456 
457     var childrenLayoutDirection: LayoutDirection? = null
458 
459     // child size is used when null
460     var size: Int? = null
461     var shouldPlaceChildren = true
462     var placeWithLayer = false
463 }
464 
465 internal class MeasureInMeasureBlock : SmartMeasurePolicy() {
measurenull466     override fun MeasureScope.measure(
467         measurables: List<Measurable>,
468         constraints: Constraints
469     ): MeasureResult {
470         measuresCount++
471         preMeasureCallback?.invoke()
472         if (shouldClearPreMeasureCallback) {
473             preMeasureCallback = null
474         }
475         val childConstraints =
476             if (size == null) {
477                 constraints
478             } else {
479                 val size = size!!
480                 constraints.copy(maxWidth = size, maxHeight = size)
481             }
482         val placeables = measurables.map { it.measure(childConstraints) }
483         if (queryAlignmentLinesDuringMeasure) {
484             placeables.forEach { it[TestAlignmentLine] }
485         }
486         var maxWidth = 0
487         var maxHeight = 0
488         if (!wrapChildren) {
489             maxWidth = childConstraints.maxWidth
490             maxHeight = childConstraints.maxHeight
491         } else {
492             placeables.forEach { placeable ->
493                 maxWidth = max(placeable.width, maxWidth)
494                 maxHeight = max(placeable.height, maxHeight)
495             }
496         }
497         return layout(maxWidth, maxHeight) {
498             layoutsCount++
499             preLayoutCallback?.invoke()
500             if (shouldClearPreLayoutCallback) {
501                 preLayoutCallback = null
502             }
503             if (shouldPlaceChildren) {
504                 placeables.forEach { placeable ->
505                     if (placeWithLayer) {
506                         placeable.placeRelativeWithLayer(0, 0)
507                     } else {
508                         placeable.placeRelative(0, 0)
509                     }
510                 }
511             }
512         }
513     }
514 }
515 
516 internal class MeasureInLayoutBlock : SmartMeasurePolicy() {
517 
518     override var wrapChildren: Boolean
519         get() = false
520         set(value) {
521             if (value) {
522                 throw IllegalArgumentException("MeasureInLayoutBlock always fills the parent size")
523             }
524         }
525 
526     override var queryAlignmentLinesDuringMeasure: Boolean
527         get() = false
528         set(value) {
529             if (value) {
530                 throw IllegalArgumentException(
531                     "MeasureInLayoutBlock cannot query alignment " + "lines during measure"
532                 )
533             }
534         }
535 
measurenull536     override fun MeasureScope.measure(
537         measurables: List<Measurable>,
538         constraints: Constraints
539     ): MeasureResult {
540         measuresCount++
541         preMeasureCallback?.invoke()
542         if (shouldClearPreMeasureCallback) {
543             preMeasureCallback = null
544         }
545         val childConstraints =
546             if (size == null) {
547                 constraints
548             } else {
549                 val size = size!!
550                 constraints.copy(maxWidth = size, maxHeight = size)
551             }
552         return layout(childConstraints.maxWidth, childConstraints.maxHeight) {
553             preLayoutCallback?.invoke()
554             if (shouldClearPreLayoutCallback) {
555                 preLayoutCallback = null
556             }
557             layoutsCount++
558             measurables.forEach {
559                 val placeable = it.measure(childConstraints)
560                 if (shouldPlaceChildren) {
561                     if (placeWithLayer) {
562                         placeable.placeRelativeWithLayer(0, 0)
563                     } else {
564                         placeable.placeRelative(0, 0)
565                     }
566                 }
567             }
568         }
569     }
570 }
571 
572 internal class NoMeasure : SmartMeasurePolicy() {
573 
574     override var queryAlignmentLinesDuringMeasure: Boolean
575         get() = false
576         set(value) {
577             if (value) {
578                 throw IllegalArgumentException(
579                     "MeasureInLayoutBlock cannot query alignment " + "lines during measure"
580                 )
581             }
582         }
583 
measurenull584     override fun MeasureScope.measure(
585         measurables: List<Measurable>,
586         constraints: Constraints
587     ): MeasureResult {
588         measuresCount++
589         preMeasureCallback?.invoke()
590         if (shouldClearPreMeasureCallback) {
591             preMeasureCallback = null
592         }
593 
594         val width = size ?: if (!wrapChildren) constraints.maxWidth else constraints.minWidth
595         val height = size ?: if (!wrapChildren) constraints.maxHeight else constraints.minHeight
596         return layout(width, height) {
597             layoutsCount++
598             preLayoutCallback?.invoke()
599             if (shouldClearPreLayoutCallback) {
600                 preLayoutCallback = null
601             }
602         }
603     }
604 }
605 
606 internal class SpyLayoutModifier : LayoutModifier {
607     var measuresCount = 0
608     var layoutsCount = 0
609 
measurenull610     override fun MeasureScope.measure(
611         measurable: Measurable,
612         constraints: Constraints
613     ): MeasureResult {
614         measuresCount++
615         return layout(constraints.maxWidth, constraints.maxHeight) {
616             layoutsCount++
617             measurable.measure(constraints).placeRelative(0, 0)
618         }
619     }
620 }
621 
622 internal open class MockLayer() : OwnedLayer {
623 
updateLayerPropertiesnull624     override fun updateLayerProperties(scope: ReusableGraphicsLayerScope) {}
625 
isInLayernull626     override fun isInLayer(position: Offset) = true
627 
628     override fun move(position: IntOffset) {}
629 
resizenull630     override fun resize(size: IntSize) {}
631 
drawLayernull632     override fun drawLayer(canvas: Canvas, parentLayer: GraphicsLayer?) {}
633 
updateDisplayListnull634     override fun updateDisplayList() {}
635 
invalidatenull636     override fun invalidate() {}
637 
destroynull638     override fun destroy() {}
639 
mapBoundsnull640     override fun mapBounds(rect: MutableRect, inverse: Boolean) {}
641 
reuseLayernull642     override fun reuseLayer(
643         drawBlock: (canvas: Canvas, parentLayer: GraphicsLayer?) -> Unit,
644         invalidateParentLayer: () -> Unit
645     ) {}
646 
transformnull647     override fun transform(matrix: Matrix) {}
648 
649     override val underlyingMatrix: Matrix
650         get() = Matrix()
651 
652     override var frameRate: Float = 0f
653 
654     override var isFrameRateFromParent = false
655 
inverseTransformnull656     override fun inverseTransform(matrix: Matrix) {}
657 
mapOffsetnull658     override fun mapOffset(point: Offset, inverse: Boolean) = point
659 }
660