Skip to content

perf(web): zero-copy pixel path + consolidate js/wasmJs into webMain#2

Merged
kdroidFilter merged 2 commits into
masterfrom
feat/web-zero-copy
Apr 24, 2026
Merged

perf(web): zero-copy pixel path + consolidate js/wasmJs into webMain#2
kdroidFilter merged 2 commits into
masterfrom
feat/web-zero-copy

Conversation

@kdroidFilter
Copy link
Copy Markdown
Collaborator

@kdroidFilter kdroidFilter commented Apr 24, 2026

Summary

  • Zero-copy pixel path on web: the ArrayBuffer transferred back from the pdfium worker is now written straight into Skia's wasm linear memory via Data.makeUninitialized + Int8Array.set on the buffer returned by org.jetbrains.skiko.wasm.awaitSkiko. Pattern lifted from coil3.decode.WebWorker. One main-thread memcpy instead of two (dropped the intermediate Kotlin ByteArray + installPixels copy).
  • Consolidated jsMain + wasmJsMain into webMain: the PdfDocument actual, the pdfium_glue.mjs externals, ClipEntryText, and the Skiko zero-copy helper are now shared. Each leaf target keeps a ~30-line PlatformBridge that covers only the genuine structural differences — typed-array conversion, kotlinx.coroutines.await signature mismatch, and Skiko's platform-specific awaitSkiko.
  • pdfium js target switched to useEsModules() so a single @file:JsModule(\"./pdfium_glue.mjs\") declaration works for both targets without a jsMain-only @JsNonModule companion.

Test plan

  • ./gradlew :pdfium:compileKotlinJs :pdfium:compileKotlinWasmJs passes.
  • ./gradlew :example:jsBrowserDevelopmentExecutableDistribution :example:wasmJsBrowserDevelopmentExecutableDistribution produces a working bundle for both targets.
  • Open a PDF in the example app on Chrome/Firefox on both the wasmJs and js builds — pages render with correct colours (BGRA/N32 on wasm) and text selection still works.
  • Full CI run across all platforms.

Write pdfium's pixel ArrayBuffer straight into Skia's wasm linear memory
(via Data.makeUninitialized + Int8Array.set on awaitSkiko's memory buffer,
pattern from coil3.decode.WebWorker), removing the intermediate Kotlin
ByteArray + installPixels copy. One memcpy on the main thread instead of
two.

Also consolidate the js + wasmJs sources into a shared webMain:

- PdfDocument, PdfiumGlue externals, ClipEntryText, and the Skiko
  zero-copy helper all live in webMain
- jsMain/wasmJsMain reduced to a ~30-line PlatformBridge covering the
  three structural differences between the targets: typed-array to
  Kotlin primitive conversion (zero-cost unsafeCast on js vs bulk copy
  on wasmJs), the kotlinx.coroutines.await signature mismatch (papered
  over by an awaitTyped<T>() expect/actual), and Skiko's platform-
  specific awaitSkiko
- pdfium js target switched to useEsModules() so a single @jsmodule
  annotation works for both targets without a jsMain-only @JsNonModule
…specifics

Expand README to include clarification on web zero-copy rendering via Skia's wasm heap and the use of `Data.makeUninitialized`. Consolidate and refine platform-specific implementation details for `jvmMain`, `androidMain`, `iosMain`, and `webMain`.
@kdroidFilter kdroidFilter merged commit 0bc630a into master Apr 24, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant