[go: nahoru, domu]

Invalidate closest layer on bounds change

The CL fixes and simplifies the logic of invalidating layers when the bounds
of a modifier or Layout change. Invalidation is now done by each
LayoutNodeWrapper on bounds change, rather than by the LayoutNode.

Relnote: Removed onSizeChange and onPositionChange in Owner.
Bug: 154132854
Test: AndroidLayoutDrawTest
Change-Id: I5c718529e3d46b765d00e307092228dde761ca4d
diff --git a/ui/ui-core/api/0.1.0-dev10.txt b/ui/ui-core/api/0.1.0-dev10.txt
index 4e2a63a..0405755 100644
--- a/ui/ui-core/api/0.1.0-dev10.txt
+++ b/ui/ui-core/api/0.1.0-dev10.txt
@@ -461,7 +461,7 @@
     method protected abstract androidx.ui.unit.IntPxSize getMeasuredSize();
     method protected abstract androidx.ui.core.Constraints getMeasurementConstraints();
     method public final int getWidth();
-    method protected abstract void performPlace(androidx.ui.unit.IntPxPosition position);
+    method protected abstract void place(androidx.ui.unit.IntPxPosition position);
     property protected final androidx.ui.unit.IntPxPosition apparentToRealOffset;
     property public final int height;
     property protected abstract androidx.ui.unit.IntPxSize measuredSize;
diff --git a/ui/ui-core/api/current.txt b/ui/ui-core/api/current.txt
index 4e2a63a..0405755 100644
--- a/ui/ui-core/api/current.txt
+++ b/ui/ui-core/api/current.txt
@@ -461,7 +461,7 @@
     method protected abstract androidx.ui.unit.IntPxSize getMeasuredSize();
     method protected abstract androidx.ui.core.Constraints getMeasurementConstraints();
     method public final int getWidth();
-    method protected abstract void performPlace(androidx.ui.unit.IntPxPosition position);
+    method protected abstract void place(androidx.ui.unit.IntPxPosition position);
     property protected final androidx.ui.unit.IntPxPosition apparentToRealOffset;
     property public final int height;
     property protected abstract androidx.ui.unit.IntPxSize measuredSize;
diff --git a/ui/ui-core/api/public_plus_experimental_0.1.0-dev10.txt b/ui/ui-core/api/public_plus_experimental_0.1.0-dev10.txt
index 4e2a63a..0405755 100644
--- a/ui/ui-core/api/public_plus_experimental_0.1.0-dev10.txt
+++ b/ui/ui-core/api/public_plus_experimental_0.1.0-dev10.txt
@@ -461,7 +461,7 @@
     method protected abstract androidx.ui.unit.IntPxSize getMeasuredSize();
     method protected abstract androidx.ui.core.Constraints getMeasurementConstraints();
     method public final int getWidth();
-    method protected abstract void performPlace(androidx.ui.unit.IntPxPosition position);
+    method protected abstract void place(androidx.ui.unit.IntPxPosition position);
     property protected final androidx.ui.unit.IntPxPosition apparentToRealOffset;
     property public final int height;
     property protected abstract androidx.ui.unit.IntPxSize measuredSize;
diff --git a/ui/ui-core/api/public_plus_experimental_current.txt b/ui/ui-core/api/public_plus_experimental_current.txt
index 4e2a63a..0405755 100644
--- a/ui/ui-core/api/public_plus_experimental_current.txt
+++ b/ui/ui-core/api/public_plus_experimental_current.txt
@@ -461,7 +461,7 @@
     method protected abstract androidx.ui.unit.IntPxSize getMeasuredSize();
     method protected abstract androidx.ui.core.Constraints getMeasurementConstraints();
     method public final int getWidth();
-    method protected abstract void performPlace(androidx.ui.unit.IntPxPosition position);
+    method protected abstract void place(androidx.ui.unit.IntPxPosition position);
     property protected final androidx.ui.unit.IntPxPosition apparentToRealOffset;
     property public final int height;
     property protected abstract androidx.ui.unit.IntPxSize measuredSize;
diff --git a/ui/ui-core/api/restricted_0.1.0-dev10.txt b/ui/ui-core/api/restricted_0.1.0-dev10.txt
index 4e2a63a..0405755 100644
--- a/ui/ui-core/api/restricted_0.1.0-dev10.txt
+++ b/ui/ui-core/api/restricted_0.1.0-dev10.txt
@@ -461,7 +461,7 @@
     method protected abstract androidx.ui.unit.IntPxSize getMeasuredSize();
     method protected abstract androidx.ui.core.Constraints getMeasurementConstraints();
     method public final int getWidth();
-    method protected abstract void performPlace(androidx.ui.unit.IntPxPosition position);
+    method protected abstract void place(androidx.ui.unit.IntPxPosition position);
     property protected final androidx.ui.unit.IntPxPosition apparentToRealOffset;
     property public final int height;
     property protected abstract androidx.ui.unit.IntPxSize measuredSize;
diff --git a/ui/ui-core/api/restricted_current.txt b/ui/ui-core/api/restricted_current.txt
index 4e2a63a..0405755 100644
--- a/ui/ui-core/api/restricted_current.txt
+++ b/ui/ui-core/api/restricted_current.txt
@@ -461,7 +461,7 @@
     method protected abstract androidx.ui.unit.IntPxSize getMeasuredSize();
     method protected abstract androidx.ui.core.Constraints getMeasurementConstraints();
     method public final int getWidth();
-    method protected abstract void performPlace(androidx.ui.unit.IntPxPosition position);
+    method protected abstract void place(androidx.ui.unit.IntPxPosition position);
     property protected final androidx.ui.unit.IntPxPosition apparentToRealOffset;
     property public final int height;
     property protected abstract androidx.ui.unit.IntPxSize measuredSize;
diff --git a/ui/ui-core/src/main/java/androidx/ui/core/LayoutModifier.kt b/ui/ui-core/src/main/java/androidx/ui/core/LayoutModifier.kt
index c954be3..14bb83a 100644
--- a/ui/ui-core/src/main/java/androidx/ui/core/LayoutModifier.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/core/LayoutModifier.kt
@@ -238,7 +238,7 @@
         override fun get(line: AlignmentLine): IntPx? = null
         override val measurementConstraints = Constraints()
         override val measuredSize = IntPxSize(width, height)
-        override fun performPlace(position: IntPxPosition) { }
+        override fun place(position: IntPxPosition) { }
     }
 
     private enum class IntrinsicMinMax { Min, Max }
diff --git a/ui/ui-core/src/main/java/androidx/ui/core/Placeable.kt b/ui/ui-core/src/main/java/androidx/ui/core/Placeable.kt
index 66afb09..fa2f30a 100644
--- a/ui/ui-core/src/main/java/androidx/ui/core/Placeable.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/core/Placeable.kt
@@ -71,7 +71,7 @@
     /**
      * Positions the [Placeable] at [position] in its parent's coordinate system.
      */
-    protected abstract fun performPlace(position: IntPxPosition)
+    protected abstract fun place(position: IntPxPosition)
 
     /**
      * The constraints used for the measurement made to obtain this [Placeable].
@@ -124,15 +124,7 @@
          * automatic position mirroring will not happen and the [Placeable] will be placed at the
          * given [position], similar to the [placeAbsolute] method.
          */
-        fun Placeable.place(position: IntPxPosition) {
-            if (parentLayoutDirection == LayoutDirection.Ltr || parentWidth == IntPx.Zero) {
-                placeAbsolute(position)
-            } else {
-                placeAbsolute(
-                    IntPxPosition(parentWidth - measuredSize.width - position.x, position.y)
-                )
-            }
-        }
+        fun Placeable.place(position: IntPxPosition) = placeAutoMirrored(position)
 
         /**
          * Place a [Placeable] at [position] in its parent's coordinate system.
@@ -143,9 +135,7 @@
          * automatic position mirroring will not happen and the [Placeable] will be placed at the
          * given [position], similar to the [placeAbsolute] method.
          */
-        fun Placeable.place(position: PxPosition) {
-            place(position.round())
-        }
+        fun Placeable.place(position: PxPosition) = placeAutoMirrored(position.round())
 
         /**
          * Place a [Placeable] at [x], [y] in its parent's coordinate system.
@@ -156,7 +146,7 @@
          * automatic position mirroring will not happen and the [Placeable] will be placed at the
          * given position, similar to the [placeAbsolute] method.
          */
-        fun Placeable.place(x: IntPx, y: IntPx) = place(IntPxPosition(x, y))
+        fun Placeable.place(x: IntPx, y: IntPx) = placeAutoMirrored(IntPxPosition(x, y))
 
         /**
          * Place a [Placeable] at [x], [y] in its parent's coordinate system.
@@ -167,16 +157,14 @@
          * automatic position mirroring will not happen and the [Placeable] will be placed at the
          * given position, similar to the [placeAbsolute] method.
          */
-        fun Placeable.place(x: Px, y: Px) = place(IntPxPosition(x.round(), y.round()))
+        fun Placeable.place(x: Px, y: Px) = placeAutoMirrored(IntPxPosition(x.round(), y.round()))
 
         /**
          * Place a [Placeable] at [position] in its parent's coordinate system.
          * Unlike [place], the given [position] will not implicitly react in RTL layout direction
          * contexts.
          */
-        fun Placeable.placeAbsolute(position: PxPosition) {
-            placeAbsolute(position.round())
-        }
+        fun Placeable.placeAbsolute(position: PxPosition) = placeAbsolute(position.round())
 
         /**
          * Place a [Placeable] at [x], [y] in its parent's coordinate system.
@@ -198,8 +186,17 @@
          * Unlike [place], the given [position] will not implicitly react in RTL layout direction
          * contexts.
          */
-        fun Placeable.placeAbsolute(position: IntPxPosition) {
-            performPlace(position + apparentToRealOffset)
+        fun Placeable.placeAbsolute(position: IntPxPosition) =
+            place(position + apparentToRealOffset)
+
+        private fun Placeable.placeAutoMirrored(position: IntPxPosition) {
+            if (parentLayoutDirection == LayoutDirection.Ltr || parentWidth == IntPx.Zero) {
+                placeAbsolute(position)
+            } else {
+                placeAbsolute(
+                    IntPxPosition(parentWidth - measuredSize.width - position.x, position.y)
+                )
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
index bfddd33..c9215b3 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
@@ -41,6 +41,7 @@
 import androidx.ui.core.DrawLayerModifier
 import androidx.ui.core.DrawModifier
 import androidx.ui.core.ContentDrawScope
+import androidx.ui.core.DensityAmbient
 import androidx.ui.core.HorizontalAlignmentLine
 import androidx.ui.core.Layout
 import androidx.ui.core.LayoutDirection
@@ -69,13 +70,19 @@
 import androidx.ui.graphics.PaintingStyle
 import androidx.ui.graphics.Path
 import androidx.ui.graphics.Shape
+import androidx.ui.layout.Column
+import androidx.ui.layout.Stack
+import androidx.ui.layout.height
 import androidx.ui.layout.ltr
+import androidx.ui.layout.preferredSize
+import androidx.ui.layout.preferredWidth
 import androidx.ui.layout.rtl
 import androidx.ui.unit.Density
 import androidx.ui.unit.IntPx
 import androidx.ui.unit.IntPxPosition
 import androidx.ui.unit.IntPxSize
 import androidx.ui.unit.PxSize
+import androidx.ui.unit.dp
 import androidx.ui.unit.ipx
 import androidx.ui.unit.max
 import androidx.ui.unit.min
@@ -2270,6 +2277,55 @@
         validateSquareColors(outerColor = Color.Blue, innerColor = Color.White, size = 10)
     }
 
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    fun testInvalidateLayer_whenOnlyModifierPositionChanges() {
+        val size1 = mutableStateOf(20.dp)
+        val size2 = 20.dp
+        lateinit var density: Density
+
+        activityTestRule.runOnUiThread {
+            activity.setContent {
+                Stack(Modifier.drawLayer()) {
+                    Column(Modifier.height(200.dp)) {
+                        Stack(Modifier.preferredWidth(100.dp).drawLayer()) {
+                            Padding(
+                                0.ipx,
+                                Modifier.background(Color.Gray)
+                                    .preferredSize(100.dp, size1.value)
+                            ) {}
+                        }
+                        Stack(
+                            Modifier.preferredSize(size2)
+                                .background(Color.Blue)
+                                .drawLatchModifier()
+                        ) {}
+                    }
+                }
+                density = DensityAmbient.current
+            }
+        }
+        assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
+
+        var size1Px = with(density) { 20.dp.toIntPx().value }
+        val size2Px = with(density) { size2.toIntPx().value }
+        activityTestRule.waitAndScreenShot().apply {
+            assertRect(Color.Gray, 0, size1Px, size1Px / 2, size1Px / 2)
+            assertRect(Color.Blue, 0, size2Px, size2Px / 2, size1Px + size2Px / 2)
+        }
+
+        drawLatch = CountDownLatch(1)
+        activityTestRule.runOnUiThread {
+            size1.value = 40.dp
+        }
+
+        size1Px = with(density) { 40.dp.toIntPx().value }
+        activityTestRule.waitAndScreenShot().apply {
+            assertRect(Color.Gray, 0, size1Px, size1Px / 2, size1Px / 2)
+            assertRect(Color.Blue, 0, size2Px, size2Px / 2, size1Px + size2Px / 2)
+        }
+    }
+
     private fun composeSquares(model: SquareModel) {
         activityTestRule.runOnUiThreadIR {
             activity.setContent {
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Layout.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Layout.kt
index 4849b47..32afa7a 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Layout.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Layout.kt
@@ -206,7 +206,7 @@
     override fun get(line: AlignmentLine): IntPx? = null
     override val measurementConstraints = Constraints()
     override val measuredSize = IntPxSize(width, height)
-    override fun performPlace(position: IntPxPosition) { }
+    override fun place(position: IntPxPosition) { }
 }
 
 /**
diff --git a/ui/ui-platform/api/0.1.0-dev10.txt b/ui/ui-platform/api/0.1.0-dev10.txt
index 9a86f8a..36d7415 100644
--- a/ui/ui-platform/api/0.1.0-dev10.txt
+++ b/ui/ui-platform/api/0.1.0-dev10.txt
@@ -259,9 +259,7 @@
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onInvalidate(androidx.ui.core.DrawNode drawNode);
     method public void onInvalidate(androidx.ui.core.LayoutNode layoutNode);
-    method public void onPositionChange(androidx.ui.core.LayoutNode layoutNode);
     method public void onRequestMeasure(androidx.ui.core.LayoutNode layoutNode);
-    method public void onSizeChange(androidx.ui.core.LayoutNode layoutNode);
     method public void pauseModelReadObserveration(kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public boolean requestFocus();
     method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function0<kotlin.Unit> p);
diff --git a/ui/ui-platform/api/current.txt b/ui/ui-platform/api/current.txt
index 9a86f8a..36d7415 100644
--- a/ui/ui-platform/api/current.txt
+++ b/ui/ui-platform/api/current.txt
@@ -259,9 +259,7 @@
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onInvalidate(androidx.ui.core.DrawNode drawNode);
     method public void onInvalidate(androidx.ui.core.LayoutNode layoutNode);
-    method public void onPositionChange(androidx.ui.core.LayoutNode layoutNode);
     method public void onRequestMeasure(androidx.ui.core.LayoutNode layoutNode);
-    method public void onSizeChange(androidx.ui.core.LayoutNode layoutNode);
     method public void pauseModelReadObserveration(kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public boolean requestFocus();
     method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function0<kotlin.Unit> p);
diff --git a/ui/ui-platform/api/public_plus_experimental_0.1.0-dev10.txt b/ui/ui-platform/api/public_plus_experimental_0.1.0-dev10.txt
index cbefb31..9e4e151 100644
--- a/ui/ui-platform/api/public_plus_experimental_0.1.0-dev10.txt
+++ b/ui/ui-platform/api/public_plus_experimental_0.1.0-dev10.txt
@@ -260,9 +260,7 @@
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onInvalidate(androidx.ui.core.DrawNode drawNode);
     method public void onInvalidate(androidx.ui.core.LayoutNode layoutNode);
-    method public void onPositionChange(androidx.ui.core.LayoutNode layoutNode);
     method public void onRequestMeasure(androidx.ui.core.LayoutNode layoutNode);
-    method public void onSizeChange(androidx.ui.core.LayoutNode layoutNode);
     method public void pauseModelReadObserveration(kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public boolean requestFocus();
     method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function0<kotlin.Unit> p);
diff --git a/ui/ui-platform/api/public_plus_experimental_current.txt b/ui/ui-platform/api/public_plus_experimental_current.txt
index cbefb31..9e4e151 100644
--- a/ui/ui-platform/api/public_plus_experimental_current.txt
+++ b/ui/ui-platform/api/public_plus_experimental_current.txt
@@ -260,9 +260,7 @@
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onInvalidate(androidx.ui.core.DrawNode drawNode);
     method public void onInvalidate(androidx.ui.core.LayoutNode layoutNode);
-    method public void onPositionChange(androidx.ui.core.LayoutNode layoutNode);
     method public void onRequestMeasure(androidx.ui.core.LayoutNode layoutNode);
-    method public void onSizeChange(androidx.ui.core.LayoutNode layoutNode);
     method public void pauseModelReadObserveration(kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public boolean requestFocus();
     method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function0<kotlin.Unit> p);
diff --git a/ui/ui-platform/api/restricted_0.1.0-dev10.txt b/ui/ui-platform/api/restricted_0.1.0-dev10.txt
index 3c624ff..905bd31 100644
--- a/ui/ui-platform/api/restricted_0.1.0-dev10.txt
+++ b/ui/ui-platform/api/restricted_0.1.0-dev10.txt
@@ -268,9 +268,7 @@
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onInvalidate(androidx.ui.core.DrawNode drawNode);
     method public void onInvalidate(androidx.ui.core.LayoutNode layoutNode);
-    method public void onPositionChange(androidx.ui.core.LayoutNode layoutNode);
     method public void onRequestMeasure(androidx.ui.core.LayoutNode layoutNode);
-    method public void onSizeChange(androidx.ui.core.LayoutNode layoutNode);
     method public void pauseModelReadObserveration(kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public boolean requestFocus();
     method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function0<kotlin.Unit> p);
diff --git a/ui/ui-platform/api/restricted_current.txt b/ui/ui-platform/api/restricted_current.txt
index 3c624ff..905bd31 100644
--- a/ui/ui-platform/api/restricted_current.txt
+++ b/ui/ui-platform/api/restricted_current.txt
@@ -268,9 +268,7 @@
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onInvalidate(androidx.ui.core.DrawNode drawNode);
     method public void onInvalidate(androidx.ui.core.LayoutNode layoutNode);
-    method public void onPositionChange(androidx.ui.core.LayoutNode layoutNode);
     method public void onRequestMeasure(androidx.ui.core.LayoutNode layoutNode);
-    method public void onSizeChange(androidx.ui.core.LayoutNode layoutNode);
     method public void pauseModelReadObserveration(kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public boolean requestFocus();
     method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function0<kotlin.Unit> p);
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt b/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
index 8c4d0a8..474a333 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
@@ -256,20 +256,6 @@
         }
     }
 
-    override fun onSizeChange(layoutNode: LayoutNode) {
-        // TODO(mount): use ownerScope. This isn't supported by IR compiler yet
-        // ownerScope.launch {
-        onInvalidate(layoutNode)
-        // }
-    }
-
-    override fun onPositionChange(layoutNode: LayoutNode) {
-        // TODO(mount): use ownerScope. This isn't supported by IR compiler yet
-        // ownerScope.launch {
-        onInvalidate(layoutNode)
-        // }
-    }
-
     override fun onRequestMeasure(layoutNode: LayoutNode) {
         trace("AndroidOwner:onRequestMeasure") {
             layoutNode.requireOwner()
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt b/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt
index 522257e..af36a5d 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt
@@ -1290,9 +1290,6 @@
 
     internal fun handleMeasureResult(measureResult: MeasureScope.MeasureResult) {
         innerLayoutNodeWrapper.measureResult = measureResult
-        if (layoutNodeWrapper.hasDirtySize()) {
-            owner?.onSizeChange(this@LayoutNode)
-        }
         this.providedAlignmentLines.clear()
         this.providedAlignmentLines += measureResult.alignmentLines
     }
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/DelegatingLayoutNodeWrapper.kt b/ui/ui-platform/src/main/java/androidx/ui/core/DelegatingLayoutNodeWrapper.kt
index ea94729..609b9e9 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/DelegatingLayoutNodeWrapper.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/DelegatingLayoutNodeWrapper.kt
@@ -89,10 +89,6 @@
         return this
     }
 
-    override fun findLayer(): OwnedLayer? {
-        return wrappedBy?.findLayer()
-    }
-
     override fun findFocusWrapperWrappingThisWrapper() =
         wrappedBy?.findFocusWrapperWrappingThisWrapper()
 
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/InnerPlaceable.kt b/ui/ui-platform/src/main/java/androidx/ui/core/InnerPlaceable.kt
index 23d6677..c1f7b4d0 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/InnerPlaceable.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/InnerPlaceable.kt
@@ -63,10 +63,6 @@
     override val layoutDirection: LayoutDirection
         get() = layoutNode.layoutDirection!!
 
-    override fun findLayer(): OwnedLayer? {
-        return wrappedBy?.findLayer()
-    }
-
     override fun findFocusWrapperWrappingThisWrapper() =
         wrappedBy?.findFocusWrapperWrappingThisWrapper()
 
@@ -112,11 +108,7 @@
 
     override fun place(position: IntPxPosition) {
         layoutNode.isPlaced = true
-        val wasMoved = position != this.position
         this.position = position
-        if (wasMoved) {
-            layoutNode.owner?.onPositionChange(layoutNode)
-        }
         layoutNode.layout()
     }
 
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/LayerWrapper.kt b/ui/ui-platform/src/main/java/androidx/ui/core/LayerWrapper.kt
index 412637e..3412df0 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/LayerWrapper.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/LayerWrapper.kt
@@ -30,6 +30,9 @@
     private var _layer: OwnedLayer? = null
     private var layerDestroyed = false
 
+    // Do not invalidate itself on position change.
+    override val invalidateLayerOnBoundsChange get() = false
+
     private val invalidateParentLayer: () -> Unit = {
         wrappedBy?.findLayer()?.invalidate()
     }
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/LayoutNodeWrapper.kt b/ui/ui-platform/src/main/java/androidx/ui/core/LayoutNodeWrapper.kt
index 2c38036..ebf38985 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/LayoutNodeWrapper.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/LayoutNodeWrapper.kt
@@ -39,10 +39,7 @@
 ) : Placeable(), Measurable, LayoutCoordinates {
     internal open val wrapped: LayoutNodeWrapper? = null
     internal var wrappedBy: LayoutNodeWrapper? = null
-    var position = IntPxPosition.Origin
 
-    protected var dirtySize: Boolean = false
-    fun hasDirtySize(): Boolean = dirtySize || (wrapped?.hasDirtySize() ?: false)
     // TODO(popam): avoid allocation here
     final override val measuredSize: IntPxSize
         get() = IntPxSize(measureResult.width, measureResult.height)
@@ -53,16 +50,27 @@
 
     abstract val layoutDirection: LayoutDirection
 
+    open val invalidateLayerOnBoundsChange = true
+
     private var _measureResult: MeasureScope.MeasureResult? = null
     var measureResult: MeasureScope.MeasureResult
         get() = _measureResult ?: error(UnmeasuredError)
         internal set(value) {
-            if (value.width != _measureResult?.width || value.height != _measureResult?.height) {
-                dirtySize = true
+            if (invalidateLayerOnBoundsChange &&
+                (value.width != _measureResult?.width || value.height != _measureResult?.height)) {
+                findLayer()?.invalidate()
             }
             _measureResult = value
         }
 
+    var position: IntPxPosition = IntPxPosition.Origin
+        internal set(value) {
+            if (invalidateLayerOnBoundsChange && value != field) {
+                findLayer()?.invalidate()
+            }
+            field = value
+        }
+
     override val parentCoordinates: LayoutCoordinates?
         get() {
             check(isAttached) { ExpectAttachedLayoutCoordinates }
@@ -102,15 +110,7 @@
     /**
      * Places the modified child.
      */
-    abstract fun place(position: IntPxPosition)
-
-    /**
-     * Places the modified child.
-     */
-    final override fun performPlace(position: IntPxPosition) {
-        place(position)
-        dirtySize = false
-    }
+    abstract override fun place(position: IntPxPosition)
 
     /**
      * Draws the content of the LayoutNode
@@ -258,7 +258,7 @@
     /**
      * Returns the layer that this wrapper will draw into.
      */
-    abstract fun findLayer(): OwnedLayer?
+    open fun findLayer(): OwnedLayer? = wrappedBy?.findLayer()
 
     /**
      * Returns the first [ModifiedFocusNode] in the wrapper list that wraps this
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/ModifiedDrawNode.kt b/ui/ui-platform/src/main/java/androidx/ui/core/ModifiedDrawNode.kt
index 9ba9c33..8374294 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/ModifiedDrawNode.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/ModifiedDrawNode.kt
@@ -40,15 +40,6 @@
     private val drawScope = DrawScopeImpl()
     private var canvas: Canvas? = null
 
-    override fun performMeasure(constraints: Constraints): Placeable {
-        val thisPlaceable = super.performMeasure(constraints)
-        if (dirtySize) {
-            // In case there is a layer between this modifier and the layout node.
-            findLayer()?.invalidate()
-        }
-        return thisPlaceable
-    }
-
     // This is not thread safe
     override fun draw(canvas: Canvas) {
         withPositionTranslation(canvas) {
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/Owner.kt b/ui/ui-platform/src/main/java/androidx/ui/core/Owner.kt
index d3f3803..1ede264 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/Owner.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/Owner.kt
@@ -127,18 +127,6 @@
     fun onInvalidate(layoutNode: LayoutNode)
 
     /**
-     * Called by [LayoutNode] to indicate the new size of [layoutNode].
-     * The owner may need to track updated layouts.
-     */
-    fun onSizeChange(layoutNode: LayoutNode)
-
-    /**
-     * Called by [LayoutNode] to indicate the new position of [layoutNode].
-     * The owner may need to track updated layouts.
-     */
-    fun onPositionChange(layoutNode: LayoutNode)
-
-    /**
      * Called by [LayoutNode] to request the Owner a new measurement+layout.
      */
     fun onRequestMeasure(layoutNode: LayoutNode)
diff --git a/ui/ui-platform/src/test/java/androidx/ui/core/ComponentNodeTest.kt b/ui/ui-platform/src/test/java/androidx/ui/core/ComponentNodeTest.kt
index d6595de..e2d0980 100644
--- a/ui/ui-platform/src/test/java/androidx/ui/core/ComponentNodeTest.kt
+++ b/ui/ui-platform/src/test/java/androidx/ui/core/ComponentNodeTest.kt
@@ -360,31 +360,6 @@
     }
 
     @Test
-    fun countChange() {
-        val (node, _, _) = createSimpleLayout()
-        val owner = mock(Owner::class.java)
-        node.attach(owner)
-        verify(owner, times(0)).onSizeChange(node)
-        node.handleMeasureResult(object : MeasureScope.MeasureResult {
-            override val width: IntPx = 10.ipx
-            override val height: IntPx = 10.ipx
-            override val alignmentLines: Map<AlignmentLine, IntPx> = emptyMap()
-            override fun placeChildren(layoutDirection: LayoutDirection) {}
-        })
-        verify(owner, times(1)).onSizeChange(node)
-    }
-
-    @Test
-    fun place() {
-        val (node, _, _) = createSimpleLayout()
-        val owner = mock(Owner::class.java)
-        node.attach(owner)
-        verify(owner, times(0)).onPositionChange(node)
-        node.place(10.ipx, 10.ipx)
-        verify(owner, times(1)).onPositionChange(node)
-    }
-
-    @Test
     fun testLayoutNodeAdd() {
         val (layout, child1, child2) = createSimpleLayout()
         val inserted = DrawNode()