Browse Source
Changes: - added k/wasm target to library and demo - added libs.versions.toml with coroutines version Tested: - using demo project - publishToMavenLocal I'll setup the test separately. --------- Co-authored-by: Oleksandr.Karpovich <oleksandr.karpovich@jetbrains.com>pull/4031/head
Oleksandr Karpovich
12 months ago
committed by
GitHub
13 changed files with 198 additions and 8 deletions
@ -0,0 +1,7 @@ |
|||||||
|
[versions] |
||||||
|
kotlinx-coroutines = "1.8.0-RC" |
||||||
|
|
||||||
|
[libraries] |
||||||
|
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } |
||||||
|
kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } |
||||||
|
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } |
@ -0,0 +1,16 @@ |
|||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi |
||||||
|
import androidx.compose.ui.window.CanvasBasedWindow |
||||||
|
import org.jetbrains.compose.resources.ExperimentalResourceApi |
||||||
|
import org.jetbrains.compose.resources.configureWebResources |
||||||
|
import org.jetbrains.compose.resources.demo.shared.UseResources |
||||||
|
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class, ExperimentalResourceApi::class) |
||||||
|
fun main() { |
||||||
|
configureWebResources { |
||||||
|
// Not necessary - It's the same as the default. We add it here just to present this feature. |
||||||
|
resourcePathMapping { path -> "./$path" } |
||||||
|
} |
||||||
|
CanvasBasedWindow("Resources demo + K/Wasm") { |
||||||
|
UseResources() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<title>Resources demo + K/Wasm</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<canvas id="ComposeTarget"></canvas> |
||||||
|
<script src="shared.js"></script> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,13 @@ |
|||||||
|
package org.jetbrains.compose.resources |
||||||
|
|
||||||
|
import org.jetbrains.compose.resources.vector.xmldom.Element |
||||||
|
import org.jetbrains.compose.resources.vector.xmldom.ElementImpl |
||||||
|
import org.jetbrains.compose.resources.vector.xmldom.MalformedXMLException |
||||||
|
import org.w3c.dom.parsing.DOMParser |
||||||
|
|
||||||
|
internal actual fun ByteArray.toXmlElement(): Element { |
||||||
|
val xmlString = decodeToString() |
||||||
|
val xmlDom = DOMParser().parseFromString(xmlString, "application/xml".toJsString()) |
||||||
|
val domElement = xmlDom.documentElement ?: throw MalformedXMLException("missing documentElement") |
||||||
|
return ElementImpl(domElement.unsafeCast()) |
||||||
|
} |
@ -0,0 +1,51 @@ |
|||||||
|
package org.jetbrains.compose.resources |
||||||
|
|
||||||
|
import kotlinx.browser.window |
||||||
|
import kotlinx.coroutines.await |
||||||
|
import org.khronos.webgl.ArrayBuffer |
||||||
|
import org.khronos.webgl.Int8Array |
||||||
|
import org.w3c.fetch.Response |
||||||
|
import kotlin.wasm.unsafe.UnsafeWasmMemoryApi |
||||||
|
import kotlin.wasm.unsafe.withScopedMemoryAllocator |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads the content of the resource file at the specified path and returns it as a byte array. |
||||||
|
* |
||||||
|
* @param path The path of the file to read in the resource's directory. |
||||||
|
* @return The content of the file as a byte array. |
||||||
|
*/ |
||||||
|
@ExperimentalResourceApi |
||||||
|
actual suspend fun readResourceBytes(path: String): ByteArray { |
||||||
|
val resPath = WebResourcesConfiguration.getResourcePath(path) |
||||||
|
val response = window.fetch(resPath).await<Response>() |
||||||
|
if (!response.ok) { |
||||||
|
throw MissingResourceException(resPath) |
||||||
|
} |
||||||
|
return response.arrayBuffer().await<ArrayBuffer>().toByteArray() |
||||||
|
} |
||||||
|
|
||||||
|
private fun ArrayBuffer.toByteArray(): ByteArray { |
||||||
|
val source = Int8Array(this, 0, byteLength) |
||||||
|
return jsInt8ArrayToKotlinByteArray(source) |
||||||
|
} |
||||||
|
|
||||||
|
@JsFun( |
||||||
|
""" (src, size, dstAddr) => { |
||||||
|
const mem8 = new Int8Array(wasmExports.memory.buffer, dstAddr, size); |
||||||
|
mem8.set(src); |
||||||
|
} |
||||||
|
""" |
||||||
|
) |
||||||
|
internal external fun jsExportInt8ArrayToWasm(src: Int8Array, size: Int, dstAddr: Int) |
||||||
|
|
||||||
|
internal fun jsInt8ArrayToKotlinByteArray(x: Int8Array): ByteArray { |
||||||
|
val size = x.length |
||||||
|
|
||||||
|
@OptIn(UnsafeWasmMemoryApi::class) |
||||||
|
return withScopedMemoryAllocator { allocator -> |
||||||
|
val memBuffer = allocator.allocate(size) |
||||||
|
val dstAddress = memBuffer.address.toInt() |
||||||
|
jsExportInt8ArrayToWasm(x, size, dstAddress) |
||||||
|
ByteArray(size) { i -> (memBuffer + i).loadByte() } |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
package org.jetbrains.compose.resources.vector.xmldom |
||||||
|
|
||||||
|
import org.w3c.dom.Element as DomElement |
||||||
|
|
||||||
|
internal class ElementImpl(val element: DomElement): NodeImpl(element), Element { |
||||||
|
override val textContent: String? |
||||||
|
get() = element.textContent |
||||||
|
|
||||||
|
override val localName: String |
||||||
|
get() = element.localName |
||||||
|
|
||||||
|
override val namespaceURI: String |
||||||
|
get() = element.namespaceURI ?: "" |
||||||
|
|
||||||
|
override fun getAttributeNS(nameSpaceURI: String, localName: String): String = |
||||||
|
element.getAttributeNS(nameSpaceURI, localName) ?: "" |
||||||
|
|
||||||
|
override fun getAttribute(name: String): String = element.getAttribute(name) ?: "" |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
package org.jetbrains.compose.resources.vector.xmldom |
||||||
|
|
||||||
|
import org.w3c.dom.Element as DomElement |
||||||
|
import org.w3c.dom.Node as DomNode |
||||||
|
|
||||||
|
internal open class NodeImpl(val n: DomNode): Node { |
||||||
|
override val textContent: String? |
||||||
|
get() = n.textContent |
||||||
|
|
||||||
|
override val nodeName: String |
||||||
|
get() = n.nodeName |
||||||
|
|
||||||
|
override val localName = "" /* localName is not a Node property, only applies to Elements and Attrs */ |
||||||
|
|
||||||
|
override val namespaceURI = "" /* namespaceURI is not a Node property, only applies to Elements and Attrs */ |
||||||
|
|
||||||
|
override val childNodes: NodeList by lazy { |
||||||
|
object: NodeList { |
||||||
|
override fun item(i: Int): Node { |
||||||
|
val child = n.childNodes.item(i) |
||||||
|
?: throw IndexOutOfBoundsException("no child node accessible at index=$i") |
||||||
|
return if (child is DomElement) ElementImpl(child) else NodeImpl(child) |
||||||
|
} |
||||||
|
|
||||||
|
override val length: Int = n.childNodes.length |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun lookupPrefix(namespaceURI: String): String = n.lookupPrefix(namespaceURI) ?: "" |
||||||
|
|
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
package org.jetbrains.compose.resources |
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope |
||||||
|
|
||||||
|
actual fun runBlockingTest(block: suspend CoroutineScope.() -> Unit) { |
||||||
|
TODO("To be implemented in PR 4031") |
||||||
|
} |
Loading…
Reference in new issue