runPdfRenderWorker function

void runPdfRenderWorker()

Runs the render worker inside a dedicated Web Worker. A consuming web app ships a tiny worker script that calls this:

// web/pdf_render_worker.dart
import 'package:dart_pdf_editor/render_worker_web.dart';
void main() => runPdfRenderWorker();

compiled with dart compile js web/pdf_render_worker.dart -o web/pdf_render_worker.dart.js and served alongside the app; the app then sets pdfRenderWorkerScriptUrl = 'pdf_render_worker.dart.js' before opening a viewer. See doc/render_worker_web.md for the full wiring.

Protocol (mirrors the native isolate backend):

  • {kind:'init', bytes:ArrayBuffer} → opens the document, replies {kind:'ready'}.
  • {kind:'record', id, page, annotations} → replies {kind:'result', id, buffer:ArrayBuffer|null} (null = the page can't be offloaded; the main thread renders it locally).

Implementation

void runPdfRenderWorker() {
  final scope = globalContext as web.DedicatedWorkerGlobalScope;
  PdfDocument? document;

  scope.onmessage = ((web.MessageEvent event) {
    final data = event.data as JSObject?;
    if (data == null) return;
    final kind = (data.getProperty('kind'.toJS) as JSString?)?.toDart;

    if (kind == 'init') {
      final buffer = data.getProperty('bytes'.toJS) as JSArrayBuffer;
      try {
        document = PdfDocument.open(buffer.toDart.asUint8List());
      } catch (_) {
        document = null; // a broken document fails every page → local renders
      }
      scope.postMessage(JSObject()..setProperty('kind'.toJS, 'ready'.toJS));
      return;
    }

    if (kind != 'record') return;
    final id = (data.getProperty('id'.toJS) as JSNumber).toDartInt;
    final page = (data.getProperty('page'.toJS) as JSNumber).toDartInt;
    final annotations =
        (data.getProperty('annotations'.toJS) as JSBoolean).toDart;

    Uint8List? out;
    // A page can decline (image it can't serialize) or throw; surface the reason
    // to the main thread so it lands in a PdfPerfLog trace instead of being lost
    // in the worker's own console.
    String? error;
    final doc = document;
    try {
      if (doc != null) out = _recordPage(doc, page, annotations);
    } catch (e, st) {
      out = null; // any failure → the main thread renders this page locally
      error = '$e\n$st';
    }

    final result = JSObject()
      ..setProperty('kind'.toJS, 'result'.toJS)
      ..setProperty('id'.toJS, id.toJS);
    if (out == null) {
      result.setProperty('buffer'.toJS, null);
      if (error != null) result.setProperty('error'.toJS, error.toJS);
      scope.postMessage(result);
    } else {
      // Copy to an exact-length buffer, then transfer it (zero-copy).
      final jsBuffer = Uint8List.fromList(out).buffer.toJS;
      result.setProperty('buffer'.toJS, jsBuffer);
      scope.postMessage(result, <JSAny>[jsBuffer].toJS);
    }
  }).toJS;
}