PdfPooledRenderWorker class

Fans record calls across a fixed set of platform workers so up to N pages decode at once instead of one at a time. A single worker serializes every page; on a document whose sheets are each a multi-second image decode that makes the tail crawl. Spreading the work across a pool drains it ~N× faster - the visible burst on load and the background prefetch alike.

New records are dispatched to the least-loaded active worker, where load is the number of queued or in-flight records this pool has handed that worker. A static page % N mapping is used only as the tie-break/fallback, so a cluster of heavy pages that would all hash to one worker can spill onto idle siblings. While a (page, priority) record is outstanding, later records for the same pair reuse its worker; cancel routes through that lease table so it still reaches the worker holding the queued request.

Speculative work (priority greater than zero) may occupy at most N−1 active workers. The final idle lane is left available for a visible request: pure Dart image decoding is synchronous, so a worker inside a large JPEG cannot observe a cooperative cancellation message until the expensive decode returns. This dynamic reservation adds no worker or document copy, and it disappears for a one-worker pool. Priority zero and negative priorities are foreground and may use the whole pool.

Each worker opens its own copy of the document, but the pool does NOT hand each one a private snapshot: it makes ONE read-only copy of the source bytes and seeds every worker (and the lazy urgent one-off lane) from that single instance. Both platform backends copy the buffer internally before handing it to their isolate/worker - native TransferableTypedData.fromList copies into external memory, web copies into a SharedArrayBuffer or a transferred ArrayBuffer - and neither detaches the view it was given, so one shared snapshot is safe. That drops the pool's own source-byte footprint from N+1 copies (a private per-worker copy plus the urgent copy) to exactly one; each worker's materialized copy inside its own isolate is unavoidable and unchanged. A caller whose buffer contents never change under the worker can drop even that one copy with copySource: false (see the factory), which startPdfRenderWorker does - so the pool then adds zero source-byte copies of its own beyond what each isolate must materialize. Size the pool to the platform via pdfRenderWorkerPoolSize.

Normally wrapped in a PdfCachingRenderWorker (see PdfRenderWorker.start), which dedups concurrent requests for one page - so the cache, not the pool, prevents the same page being decoded by its worker twice at once.

Ultra-urgent records (currently the long-jump preview, priority -2000) bypass the ordinary pool through a lazily-created one-off worker. A page jump should not wait behind several already-started background records that cannot receive cancellation until their synchronous parse step yields.

Inheritance

Constructors

PdfPooledRenderWorker(Uint8List bytes, int size, {bool copySource = true, List<int>? populatedRanges, int? imageCacheBytes})
Starts size platform workers, all seeded from ONE read-only snapshot of bytes (see the class doc - the backends copy internally, so the pool keeps just this single source-byte copy instead of one per worker). size is clamped to at least 1; a pool of 1 is just a single worker with this routing wrapper.
factory
PdfPooledRenderWorker.fromWorkers(List<PdfRenderWorker> workers)
Test seam: a pool over already-constructed workers, so the routing and teardown can be exercised with fakes instead of real platform workers.
PdfPooledRenderWorker.withSpawner(Uint8List bytes, int size, PdfRenderWorker spawn(Uint8List), {bool copySource = true, List<int>? populatedRanges})
Test seam: a pool that spawns its workers through spawn instead of the platform startRenderWorker, so the byte-sharing contract - every worker (and the urgent lane) seeded from the SAME snapshot instance, no private per-worker copy - can be asserted with fakes that capture the bytes they are handed.
factory

Properties

concurrentRecordCapacity → int
Maximum number of page records this backend can execute concurrently.
no setteroverride
hashCode → int
The hash code for this object.
no setterinherited
isActive → bool
The pool can offload while any worker is still alive; a worker that dies (e.g. its watchdog gave up) only takes its own share of pages down to local rendering, the rest keep offloading.
no setteroverride
lastRenderTrace → PdfRenderTrace?
The most recent trace across the pool's workers. Best-effort: a pool serves pages on several workers at once, so this is whichever worker most recently reported one, useful for a spot check rather than attribution.
no setteroverride
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
supportsPageSurfaces → bool
Whether this backend can bind a browser-owned zero-copy page surface.
no setteroverride
supportsRevisionUpdate → bool
Whether this backend can absorb an updateRevision in place instead of being torn down and restarted on every edit. The native isolate backend does; so does the web backend once its worker has opened the document and advertised the 'update' message (an older worker bundle does not); the wrappers forward it. The null fallback does not, so its host restarts the worker on a revision change as before.
no setteroverride

Methods

binStrips(int pageIndex, {required bool annotations, Set<String> hiddenAnnotationSubtypes = const {}, required List<double> pageToDevice, required int deviceWidth, required int deviceHeight, required double pixelRatio, bool slugGlyphs = false, int priority = 0}) → Future<StripPlan?>
Strip binning follows the page's stable worker affinity, not the current least-loaded worker: each worker keeps a small command cache (plus the process-global glyph/shape strip caches) warm for the pages it has binned, and a zoom session hammers ONE page with a fresh geometry per settle - stable affinity turns every settle after the first into a command-cache hit, while least-loaded routing would scatter the settles across workers and re-record the page on each of them.
override
buildRegionIndex(int pageIndex, {required bool annotations, Set<String> hiddenAnnotationSubtypes = const {}, required int maxCommands, required bool buildGrid, int priority = 0}) → Future<PdfRegionReplayIndex?>
Region-index builds follow the page's stable worker affinity like binStrips: both re-record the page, so the second request hits the same worker's warm command cache instead of re-recording on a different one.
override
cancel(int pageIndex, {int priority = 0}) → void
Drops any QUEUED (not yet started) record request for pageIndex at priority, completing its future with null - as if the page had declined to a local render. A cheap no-op when nothing matches.
override
cancelBinStrips(int pageIndex, {int priority = 0}) → void
Drops any QUEUED (not yet started) binStrips request for pageIndex at priority, completing its future with null - and, on the native isolate backend, also preempts a matching IN-FLIGHT bin cooperatively so the worker abandons the stale geometry mid-walk (its future resolves null too). Superseded settles and overtaken speculative bins call this so the worker bins the geometry the user is actually looking at instead of a stale one; the abandoning caller must not fall back to a local bin for the superseded settle (PdfPageView's generation guard takes care of that). Unlike cancel, the in-flight preemption is safe here because strip plans are never shared between callers (the caching wrapper passes bins straight through).
override
createPageSurface(Object surface, {int? pageIndex}) → PdfPageSurfaceSession?
Transfers an opaque browser canvas to this worker and binds it for the lifetime of the returned session. Native and unsupported backends return null. pageIndex lets a pool bind a base canvas and its deep-zoom region to the same worker, reusing that worker's transcript and image samples. See PdfPageSurfaceSession for the correctness-gated fallback.
override
dispose() → void
Tears the worker down (kills the isolate, fails pending requests with null). Idempotent.
override
extractText(int pageIndex, {int priority = 0}) → Future<PdfPageText?>
Extracts pageIndex's text off the UI isolate for search and hover (#396). PdfTextExtractor.extract is pure Dart, so a heavy page's extraction (a full content walk) freezes a frame when it runs on the UI thread; a worker moves it off. priority shares the queue ordering with record.
override
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
promoteTextExtraction(int pageIndex, {int priority = 0}) → void
Raises the priority of an existing text extraction without submitting another walk. A foreground search uses this when it joins speculative text preparation. Lower numbers are more urgent; this never demotes work or starts an extraction when none is pending. Custom backends may ignore the hint. Both built-in worker backends update queued/in-flight requests.
override
record(int pageIndex, {bool annotations = true, Set<String> hiddenAnnotationSubtypes = const {}, int priority = 0, double? imagePixelRatio, bool decodeImages = true, int? commandLimit, PdfRect? imageDecodeRegion, PdfPartialRecordSink? onPartial}) → Future<List<PdfRenderCommand>?>
Records page pageIndex off-thread and returns its replayable command buffer (image XObjects decoded off-thread and attached), or null when the page can't be offloaded - it draws an inline image (BI .. ID .. EI, which can name a page-resource colour space the stream can't reach), the worker failed or was disposed, or this platform has no worker - and the caller must render the page locally.
override
recordStripDetail(int pageIndex, {required bool annotations, Set<String> hiddenAnnotationSubtypes = const {}, required List<double> pageToDevice, required int deviceWidth, required int deviceHeight, required double pixelRatio, required PdfRect imageDecodeRegion, int priority = 0}) → Future<PdfStripDetail?>
Records a region-detail command buffer and bins that exact buffer for a strip-routed deep-zoom patch in one worker job.
override
releaseCachedPage(int pageIndex) → void
Releases completed reusable command records for pageIndex.
inherited
toString() → String
A string representation of this object.
inherited
trimMemory() → void
Every lane trims, the lazy urgent lane included.
override
updateRevision(int baseLength, Uint8List appendedBytes, int newLength, Set<int>? changedPages) → void
Feeds one append-only editor revision into the worker's already-open document instead of disposing and restarting it, then invalidates the worker's cached renders for the changedPages only.
override
updateRevisionTo(Uint8List revisionBytes, int baseLength, Set<int>? changedPages) → void
updateRevision given the whole new revision rather than only its tail: revisionBytes is the complete revision (its length is the new length), and its first baseLength bytes are the prefix the worker already holds. PdfRenderWorkerHost feeds edits through this.
override

Operators

operator ==(Object other) → bool
The equality operator.
inherited