Skip to content

Commit

Permalink
After each ComposeScene.render phase, send apply notifications and pe…
Browse files Browse the repository at this point in the history
…rform the corresponding changes. (#563)

# Conflicts:
#	compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/ComposeScene.skiko.kt
  • Loading branch information
m-sasha authored and igordmn committed Jun 8, 2023
1 parent 0151fd3 commit a8c7fe3
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
Expand All @@ -57,6 +58,8 @@ import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.toComposeImageBitmap
import androidx.compose.ui.graphics.toPixelMap
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.keyEvent
Expand Down Expand Up @@ -152,6 +155,22 @@ class ComposeSceneTest {
assertFalse(hasRenders())
}

// https://github.com/JetBrains/compose-multiplatform/issues/3137
@Test
fun `rendering of Text state change`() = renderingTest(width = 400, height = 200) {
var text by mutableStateOf("before")
setContent {
Text(text)
}
awaitNextRender()
val before = surface.makeImageSnapshot().toComposeImageBitmap().toPixelMap().buffer

text = "after"
awaitNextRender()
val after = surface.makeImageSnapshot().toComposeImageBitmap().toPixelMap().buffer
assertThat(after).isNotEqualTo(before)
}

@Test(timeout = 5000)
fun `rendering of Layout state change`() = renderingTest(width = 40, height = 40) {
var width by mutableStateOf(10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,10 @@ class ComposeScene internal constructor(
check(!isClosed) { "ComposeScene is closed" }
isInvalidationDisabled = true
val result = try {
// We must see the actual state before we will do [block]
// TODO(https://github.com/JetBrains/compose-jb/issues/1854) get rid of synchronized.
synchronized(GlobalSnapshotManager.sync) {
Snapshot.sendApplyNotifications()
}
snapshotChanges.perform()
// Try to get see the up-to-date state before running block
// Note that this doesn't guarantee it, if sendApplyNotifications is called concurrently
// in a different thread than this code.
sendAndPerformSnapshotChanges()
block()
} finally {
isInvalidationDisabled = false
Expand Down Expand Up @@ -413,16 +411,26 @@ class ComposeScene internal constructor(
return mainOwner.contentSize
}

/**
* Sends any pending apply notifications and performs the changes they cause.
*/
private fun sendAndPerformSnapshotChanges() {
Snapshot.sendApplyNotifications()
snapshotChanges.perform()
}

/**
* Render the current content on [canvas]. Passed [nanoTime] will be used to drive all
* animations in the content (or any other code, which uses [withFrameNanos]
*/
fun render(canvas: Canvas, nanoTime: Long): Unit = postponeInvalidation {
recomposeDispatcher.flush()
frameClock.sendFrame(nanoTime)
frameClock.sendFrame(nanoTime) // Recomposition
sendAndPerformSnapshotChanges() // Apply changes from recomposition phase to layout phase
needLayout = false
forEachOwner { it.measureAndLayout() }
pointerPositionUpdater.update()
sendAndPerformSnapshotChanges() // Apply changes from layout phase to draw phase
needDraw = false
forEachOwner { it.draw(canvas) }
forEachOwner { it.clearInvalidObservations() }
Expand Down

0 comments on commit a8c7fe3

Please sign in to comment.