PdfPageView class
Displays a single PDF page, rendered natively in Dart.
The page is interpreted once into a ui.Picture and, by default, its command transcript is retained as a PdfRetainedScene; changing scale replays that scene into a fresh flat picture at the new resolution - no re-interpretation, no image re-decoding, and no nested-picture re-raster (which Impeller rasterizes several times slower than a flat replay of the same draws). Past the full-page raster caps, a detail patch covering the visible part of the page (inflated for panning headroom) renders at full resolution on top of the capped base - single patch, not a tile grid, so the page is never interpreted more than once per zoom level.
- Inheritance
-
- Object
- DiagnosticableTree
- Widget
- StatefulWidget
- PdfPageView
Constructors
-
PdfPageView({Key? key, required PdfPage page, int? rotation, double scale = 1, double? baseRasterScale, int settleGeneration = 0, Color pageColor = const Color(0xFFFFFFFF), bool showAnnotations = true, VoidCallback? onRasterReady, ValueListenable<
bool> ? renderHold, PdfPageRenderScheduler? renderScheduler, int renderPriority = 0, int focusDistance = 0, bool onScreen = true, bool qualityVisible = true, int qualityPageCount = 1, PdfPagePreviewCache? previewCache, int previewIndex = 0, int pageEpoch = 0, int contentStamp = 0, bool trustContentStamp = false, int destructiveStamp = 0, PdfRenderWorker? renderWorker, PdfPerformanceController? performance, double? workerImagePixelRatioCap, ValueListenable<double> ? transformScale, Listenable? transformChanges, PdfTileRasterBackend tileRasterBackend = const PdfCanvasTileRasterBackend(), Object? tileCacheNamespace}) -
const
Properties
- baseRasterScale → double?
-
Optional scale ceiling for the whole-page backing raster.
final
- contentStamp → int
-
This page's content stamp (see
_PdfViewerPage.contentStamp). Unlike pageEpoch it is per-page, so a content-only same-geometry edit that changed this page advances it while leaving untouched pages alone. When it changes the page re-renders, but the held raster and preview stay painted until the fresh render replaces them - an additive edit (ink, a highlight, a shape) on a heavy page must not flash the page blank, and the just-added markup rides on top through the editing overlay until the new raster (with it baked in) lands. 0 outside an editing session (never changes).final - destructiveStamp → int
-
This page's PdfEditingController.pageDestructiveStamp. Unlike
contentStamp it advances only when an edit removed content from
this page (a redaction burn). When it changes the held raster and
preview are dropped immediately - keeping the pre-edit (un-redacted)
content up, even for the frame before the re-render lands or in a
fast-scroll preview, would expose the very content the burn deleted.
0 outside an editing session (never changes).
final
- focusDistance → int
-
Distance in pages from the focused page (0 = the page the viewport is on).
Off-focus neighbours are prefetched, so their embedded images are decoded
and shipped at a reduced resolution (prefetchImagePixelRatioFactor) to
keep record traffic down (a Flate raster underlay ships as full RGBA - a
single page can reach tens of MB, starving the visible page, #451). The
page re-renders at full image resolution the moment a meaningful share
of it becomes visible (see qualityVisible).
final
- hashCode → int
-
The hash code for this object.
no setterinherited
- key → Key?
-
Controls how one widget replaces another widget in the tree.
finalinherited
- onRasterReady → VoidCallback?
-
Called whenever a full-page raster for the current page object
lands on screen. Lets the editing overlay hold its just-committed
preview exactly until the new revision is actually visible.
final
- onScreen → bool
-
Whether any part of this page currently overlaps the viewport.
final
- page → PdfPage
-
final
- pageColor → Color
-
The paper color the page renders on (see
PdfPageRenderer.renderPicture). Changing it re-renders the page.
final
- pageEpoch → int
-
Bumped by the viewer whenever the document is swapped for a revision
whose page structure differs (insert, remove, reorder). The lazy list
has no per-page key, so it reconciles States by slot: after pages
shift, a reused State keeps the same previewIndex while page
silently becomes a different page, and its already-rastered
_image/ preview would otherwise keep painting the old page during a fast scroll. A changed epoch forces the stale rasters to drop and re-render. Unchanged across same-geometry (content-only) edits, so those keep re-rendering in place without a blank flash.final - performance → PdfPerformanceController?
-
Optional adaptive policy receiving first-render latency samples.
final
- previewCache → PdfPagePreviewCache?
-
Shared low-res previews (see PdfPagePreviewCache): while this
page's full render is pending - most visibly under renderHold
during fast scrolling - the cached preview paints instead of the
blank paper placeholder. When the full render lands, its picture
refreshes the cache, so a page seen once keeps a preview after
this state is long disposed.
final
- previewIndex → int
-
This page's index in previewCache.
final
- qualityPageCount → int
-
Number of pages simultaneously receiving foreground-quality rendering.
final
- qualityVisible → bool
-
Whether enough of this page is visible to require foreground-quality
image decoding and zoom detail. A narrow page-edge sliver may be false
while onScreen remains true; when the viewport rests between two pages,
both pages are true. Standalone page views default to foreground quality.
final
-
renderHold
→ ValueListenable<
bool> ? -
While true, a page that has not been interpreted yet keeps its
paper placeholder instead of starting the (UI-thread) interpreter
walk - the viewer raises it during fast scrolling so heavy pages
flying past can't stall the frame rate. Held pages render as soon
as it drops back to false. Pages that already have a picture are
unaffected (re-rasters reuse it).
final
- renderPriority → int
-
Worker queue priority for this page's on-screen record requests. Lower
values win. The viewer ranks the page nearest the viewport above cache-
window neighbours so a long jump paints the destination first.
final
- renderScheduler → PdfPageRenderScheduler?
-
Paces this page's first (UI-thread) interpret against every other
page's, so a settling fast scroll can't fire them all in one frame.
When set, the page registers its first render here instead of
interpreting directly; the scheduler grants it a turn (see
PdfPageRenderScheduler). Re-rasters of an already-interpreted page
bypass it. Null falls back to renderHold.
final
- renderWorker → PdfRenderWorker?
-
Offloads this page's interpretation (the content-stream parse + walk)
to a background isolate when set and showAnnotations matches a
serializable page - the picture is then replayed cheaply on this
thread. Image-bearing pages and the null fallback render locally. Must
be a worker started over the same bytes page belongs to.
final
- rotation → int?
-
Display rotation override. When set, the page renders at this
rotation instead of its own /Rotate - the view rotation feature
rotates the display without modifying the document. Null (the
default) uses the page's own /Rotate.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- scale → double
-
Resolution multiplier on top of the device pixel ratio. The viewer
raises it to the settled zoom level so pages stay sharp.
final
- settleGeneration → int
-
Bumped by the viewer when scrolling/zooming settles, so the detail
patch can follow the viewport without the viewer knowing about it.
final
- showAnnotations → bool
-
Whether the page's annotations render (see
PdfPageRenderer.renderPicture). Changing it re-renders the page.
final
- tileCacheNamespace → Object?
-
Stable owner identity for entries in the process-wide tile cache.
final
- tileRasterBackend → PdfTileRasterBackend
-
Scene-scoped renderer for deep-zoom tile slabs.
final
- transformChanges → Listenable?
-
The viewer's complete live transform notifier (scale and translation).
final
-
transformScale
→ ValueListenable<
double> ? -
The viewer's LIVE zoom scale (the InteractiveViewer matrix's scale on
every change), as opposed to scale, which the viewer only updates at
the debounced zoom settle. When set alongside renderWorker, a dense
strip-routed page uses it to bin its strip plan speculatively while the
gesture quiesces: the settle then consumes the already-in-flight worker
plan instead of starting the ~290 ms bin from scratch. Null (the
default) disables speculation; settles behave exactly as before.
final
- trustContentStamp → bool
-
When true, a new page object with the same contentStamp is treated as
the same base page image. Editing revisions reopen the document and give
every page a new object even for annotation-only changes; the viewer uses
this flag when annotations are painted in a separate overlay.
final
- workerImagePixelRatioCap → double?
-
Caps speculative/off-screen full-page image decode requests. Every page
intersecting the viewport keeps focusedImageDecodeHeadroom over its
base raster's physical resolution; deep-zoom region requests likewise
stay uncapped so visible content can sharpen on demand.
final
Methods
-
createElement(
) → StatefulElement -
Creates a StatefulElement to manage this widget's location in the tree.
inherited
-
createState(
) → State< PdfPageView> -
Creates the mutable state for this widget at a given location in the tree.
override
-
debugDescribeChildren(
) → List< DiagnosticsNode> -
Returns a list of DiagnosticsNode objects describing this node's
children.
inherited
-
debugFillProperties(
DiagnosticPropertiesBuilder properties) → void -
Add additional properties associated with the node.
inherited
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
inherited
-
toString(
{DiagnosticLevel minLevel = DiagnosticLevel.info}) → String -
A string representation of this object.
inherited
-
toStringDeep(
{String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String -
Returns a string representation of this node and its descendants.
inherited
-
toStringShallow(
{String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String -
Returns a one-line detailed description of the object.
inherited
-
toStringShort(
) → String -
A short, textual description of this widget.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited
Static Properties
- boundedFinalSinglePassMaxRawContentBytes ↔ int
-
Encoded-content ceiling for starting the complete worker record directly
when prioritizeBoundedFinalPicture is enabled.
getter/setter pair
- debugDetailPatchReuses ↔ int
-
Single-patch scroll settles satisfied by the raster's retained guard
band instead of issuing another region render.
getter/setter pair
- debugSpeculativeDetailHits ↔ int
-
Deep-zoom settles that consumed a combined region-detail request issued
while a live pan was quiescing.
getter/setter pair
- debugSpeculativeDetailMisses ↔ int
-
Region-detail speculations that were stale, cancelled, or declined.
getter/setter pair
- debugSpeculativePlanHits ↔ int
-
Settles that consumed a speculatively-binned worker strip plan (the
transformScale-driven pre-request matched the settle's geometry
exactly and resolved to a plan). Test telemetry, following the
StripPdfDevice.totalPlanMismatches pattern.
getter/setter pair
- debugSpeculativePlanMisses ↔ int
-
Speculative worker strip plans that were dropped unconsumed (the
settle asked for a different geometry, a region bin superseded them,
or the scene changed) or resolved null when consumed.
getter/setter pair
- debugStripZoomReplayBackendOverride ↔ bool?
-
Test hook for the shader-capability half of the backend gate:
flutter testruns on software Skia whereui.ImageFilter.isShaderFilterSupportedis false, so strip router tests force the decision. The iOS safety gate still applies when this is true. Null (production) asks the engine.getter/setter pair - debugTileImageDetailAdoptions ↔ int
-
Region-scoped image-detail scenes the tile path adopted, and the ratio
the most recent one decoded its images at (see
_adoptTileDetailScene).getter/setter pair - debugTileImageDetailRatio ↔ double?
-
getter/setter pair
- debugTileImageDetailRegion ↔ Rect?
-
getter/setter pair
- debugTileStoreOverride ↔ PdfTileStore?
-
Test seam: the store the tile layer draws from. Null uses the shared
PdfTileStore.instance.
getter/setter pair
- debugWebLocalFirstPaintBackendOverride ↔ bool?
-
Test hook for the web half of webLocalFirstPaintMaxRawContentBytes.
getter/setter pair
- debugWebSlugGlyphLayerBackendOverride ↔ bool?
-
Test hook for webSlugGlyphLayer. Null uses kIsWeb.
getter/setter pair
- deferFullRenderUntilDetailPaint ↔ bool
-
Defers a cold deep-zoom page's ordinary full-image refinement until its
visible detail patch has rasterized and reached a frame.
getter/setter pair
- directPicturePresentation ↔ bool
-
Presents a bounded completed page picture directly instead of first
flattening it through
Picture.toImage.getter/setter pair - directPicturePresentationMaxCommands ↔ int
-
Maximum retained-scene command count eligible for
directPicturePresentation.
getter/setter pair
- earlyPrefixCommandLimit ↔ int
-
Commands in that first bounded record - large enough for the prefix to be
recognizable, small enough to land in a fraction of a dense page's walk.
getter/setter pair
- earlyPrefixMinContentBytes ↔ int
-
Only pages whose raw (still-encoded) content exceeds this pay the extra
record.
PdfPage.rawContentLengthis an O(streams) size proxy that costs no decode, so an ordinary few-KB page skips the prefix entirely and is never charged a second worker job.getter/setter pair - earlyPrefixPaint ↔ bool
-
Paints a bounded command prefix before the full vector record, so a
dense sheet shows real ink instead of blank paper while its whole-page
transcript is still being built.
getter/setter pair
- fusedProgressiveRecord ↔ bool
-
Uses one decoding worker record for both a page's progressive
linework reveal and its final image-bearing render.
getter/setter pair
- motionSafeLocalBudgetMs ↔ double
-
UI-thread budget for a local motion-safe interpret. A page whose walk
overruns it is never granted the lane again (see
_recordKnownHeld) - the measured cost, unlike its encoded size, is the truth.getter/setter pair - motionSafeLocalMaxRawContentBytes ↔ int
-
Content-stream ceiling for entering the motion-safe lane with no render
worker attached, where the walk itself runs on the UI thread.
getter/setter pair
- motionSafeMaxCommands ↔ int
-
Command ceiling for replaying a completed record while a scroll is still
in flight (motionSafeRenders).
getter/setter pair
- motionSafeMaxImagePixels ↔ int
-
Embedded-image pixels a page may carry and still render through a scroll.
getter/setter pair
- motionSafeRenders ↔ bool
-
Lets ordinary pages render through a scroll instead of waiting for it
to settle (the render scheduler's motion-safe lane).
getter/setter pair
- prefetchImagePixelRatioFactor ↔ double
-
Factor applied to a prefetched off-screen page's image-decode resolution,
relative to a visible page's. Off-screen pages aren't being looked at, so
shipping their embedded images at full display resolution wastes record
bandwidth (a Flate raster underlay ships as full RGBA - tens of MB) and
competes with the visible page on the worker (#451). 0.5 halves the image
ratio (~4x smaller image payload); the page re-decodes at full resolution
the moment it becomes visible. Only images are affected - vectors and text
are resolution-independent commands. 1.0 disables the reduction.
getter/setter pair
- prioritizeBoundedFinalPicture ↔ bool
-
Prioritizes a bounded page's complete display list after its image-free
worker transcript has warmed, instead of spending UI/GPU time flattening
that intermediate vector preview.
getter/setter pair
- progressivePartialUiBudget ↔ Duration?
-
UI-time ceiling for progressive prefix replay. Once one prefix costs at
least this long, larger cumulative prefixes from the same record are
skipped and the final worker result is allowed to land next.
getter/setter pair
- progressiveStreamingPaint ↔ bool
-
Progressively reveals a dense page top-down (#564): the vector-first record
streams the growing linework prefix the worker records, and each prefix is
rasterized into the preview slot, so the page fills in as it records instead
of appearing all at once when the whole-page walk finishes. This replaces
the single bounded earlyPrefixPaint on a dense page - a growing sequence
of prefixes rather than one snapshot - and lands before the vector-first
full raster, so it is strictly more information sooner.
getter/setter pair
- retainDenseScenesOffFocus ↔ bool
-
Whether dense scenes used only by the tile/strip routes stay retained on
pages that do not own viewport focus.
getter/setter pair
- retainedZoomReplay ↔ bool
-
Kill switch for the retained-scene zoom replay. When true (the
default) the page's recorded command buffer and decoded images are
retained alongside the cached picture, and zoom re-rasters replay them
into a flat picture at the new ratio - byte-identical output
(retained_scene_test.dart), several times faster under Impeller. Set
false to restore the previous behavior (re-rasterize the cached
ui.Picture) if a regression is ever suspected in the field.
getter/setter pair
- retainedZoomReplayMaxCommands ↔ int
-
Command-count ceiling above which a page does NOT retain its scene and
keeps the classic cached-picture zoom path.
getter/setter pair
- retainedZoomReplayTileMaxCommands ↔ int
-
Command-count ceiling for retaining a scene solely to drive the deep-zoom
tile path (tileStoreDetail), above retainedZoomReplayMaxCommands.
getter/setter pair
- stripZoomReplay ↔ bool
-
Strip routing for pages ABOVE retainedZoomReplayMaxCommands whose
topology stays under stripZoomReplayMaxEstimatedBatches: they retain
their scene, and zoom-driven re-rasters (full page and deep-zoom detail
patch) replay it through the sparse-strip shader device
(PdfRetainedScene.rasterizeStrips) at the new ratio instead of
re-rasterizing the cached nested picture. Pages under the ceiling keep
the flat canvas replay - strips lose on office pages (fixed
atlas-decode/replay overhead, and Impeller already rasterizes light
flat pictures quickly).
getter/setter pair
- stripZoomReplayMaxEstimatedBatches ↔ int
-
Maximum estimated atlas batches allowed on the dense-page strip route.
getter/setter pair
- tileStoreDetail ↔ bool
-
Composite deep-zoom detail from the PdfTileStore zoom-bucket pyramid
instead of the single unbudgeted detail patch. When true (and the page
retains a region-cullable scene), the visible slice is tiled: panning at
deep zoom draws cached tiles with zero re-raster and a settle only
rasterizes the missing tiles (batched into slab readbacks), all under one
shared byte budget that evicts by least-recently used and drops under
memory pressure.
getter/setter pair
- webDomRasterPresentation ↔ bool
-
Experimental web benchmark path: transfers a DOM canvas to the render
worker and paints supported pages there without a
dart:uiimage or SkWasm presentation frame.getter/setter pair - webDomSurfaceScrollSettleDelay ↔ Duration
-
Quiet window after the last wheel/list scroll event before a worker-owned
DOM surface sharpens its focused page. The ordinary 500 ms window protects
the UI isolate from a CAD interpretation starting between delayed wheel
acknowledgements; a surface paints on the dedicated worker and needs only
enough debounce to avoid repainting every input tick. Two 60 Hz frames
let a delayed final wheel acknowledgement join the burst without adding
a visibly separate post-scroll pause; the worker queue still coalesces
obsolete requests.
getter/setter pair
- webLocalFirstPaintMaxRawContentBytes ↔ int
-
Small, resource-simple web pages may take their first recorded picture
locally instead of waiting for a newly-started render worker. Worker boot
is roughly 150 ms in real Chromium while an ordinary text page records in
about 10 ms; the full raster still runs through the engine either way.
Pages with XObjects or larger content stay on the worker path so image
decode and dense interpreter walks never move onto the UI isolate.
Set to zero to disable.
getter/setter pair
- webSlugGlyphLayer ↔ bool
-
Keeps a Slug-routed retained picture live on web for ordinary-size
pages instead of flattening it into a bitmap on every zoom settle.
CanvasKit evaluates the curve shader under the current canvas transform,
so outline text stays sharp throughout a pinch and the page pays no
settle readback. The complete painter-order picture stays live (rather
than lifting glyphs into one topmost overlay), preserving text/vector
occlusion, clips, groups, and soft masks exactly.
getter/setter pair
Static Methods
-
debugResetSpeculativeStats(
) → void
Constants
- focusedImageDecodeHeadroom → const double
- Linear embedded-image resolution retained above a visible page's physical raster footprint.