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