Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

After each ComposeScene.render phase, send apply notifications and perform the corresponding changes. #563

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -153,8 +153,7 @@ class ComposeScene internal constructor(
// 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.
Snapshot.sendApplyNotifications()
snapshotChanges.perform()
sendAndPerformSnapshotChanges()
block()
} finally {
isInvalidationDisabled = false
Expand Down Expand Up @@ -412,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