<lambda>null1package kotlinx.coroutines 2 3 import org.w3c.dom.Window 4 5 /** 6 * Converts an instance of [Window] to an implementation of [CoroutineDispatcher]. 7 */ 8 public fun Window.asCoroutineDispatcher(): CoroutineDispatcher = 9 @Suppress("UnsafeCastFromDynamic") 10 asDynamic().coroutineDispatcher ?: WindowDispatcher(this).also { 11 asDynamic().coroutineDispatcher = it 12 } 13 14 /** 15 * Suspends coroutine until next JS animation frame and returns frame time on resumption. 16 * The time is consistent with [window.performance.now()][org.w3c.performance.Performance.now]. 17 * This function is cancellable. If the [Job] of the current coroutine is completed while this suspending 18 * function is waiting, this function immediately resumes with [CancellationException]. 19 */ contnull20public suspend fun Window.awaitAnimationFrame(): Double = suspendCancellableCoroutine { cont -> 21 asWindowAnimationQueue().enqueue(cont) 22 } 23 Windownull24private fun Window.asWindowAnimationQueue(): WindowAnimationQueue = 25 @Suppress("UnsafeCastFromDynamic") 26 asDynamic().coroutineAnimationQueue ?: WindowAnimationQueue(this).also { 27 asDynamic().coroutineAnimationQueue = it 28 } 29 30 private class WindowAnimationQueue(private val window: Window) { 31 private val dispatcher = window.asCoroutineDispatcher() 32 private var scheduled = false 33 private var current = ArrayDeque<CancellableContinuation<Double>>() 34 private var next = ArrayDeque<CancellableContinuation<Double>>() 35 private var timestamp = 0.0 36 enqueuenull37 fun enqueue(cont: CancellableContinuation<Double>) { 38 next.addLast(cont) 39 if (!scheduled) { 40 scheduled = true 41 window.requestAnimationFrame { ts -> 42 timestamp = ts 43 val prev = current 44 current = next 45 next = prev 46 scheduled = false 47 process() 48 } 49 } 50 } 51 processnull52 fun process() { 53 while(true) { 54 val element = current.removeFirstOrNull() ?: return 55 with(element) { dispatcher.resumeUndispatched(timestamp) } 56 } 57 } 58 } 59