jet_cad_2d_flutter library

Flutter rendering layer for the jet_cad_2d engine.

Classes

ArcOp
ArcTool
Spec 05 D8: centre, start, end. The start sets the radius and the start angle; the end sets only the end angle. The sweep follows the angle the pointer travelled around the centre (SweepTracker). Fill does not apply.
BeginDashOp
BeginResidualOp
CameraController
The camera. A ValueNotifier so a change repaints inside a RepaintBoundary without rebuilding the widget tree.
CameraGestureDetector
Pans and zooms a CameraController from pointer input, wrapping the view it drives.
CanvasDrawSink
Writes to dart:ui.
ChromePalette
The canvas chrome's colours: what surrounds and frames the paper (dark theme spec D2). They follow the host's theme, not the paper.
CircleOp
CircleTool
Spec 05 D7: the centre, then a point on the circle.
ClassifyStats
What one classifyTextPatches call did -- diagnostics, for the tests and the harness. Zero everywhere when there are no labels.
CollectionFrame
The camera and viewport one rebuild walks under (Ruling F2).
DarkCanvasStyleResolver
A StyleResolver that re-tones inner's colours for the dark paper (K3). inner resolves the drawing as it is on white paper (ACI 7 black), so ACI 7 and a black TrueColor take the same road to white. Alpha, lineweight, linetype and scale pass through untouched.
DocChangeNotifier
Bridges the document's asynchronous change stream to a Listenable.
DraftCanvas
Draws a document, repainting on camera and document changes and on nothing else.
DraftCanvasState
Public so a test — or a tool that needs the painter's counters — can reach the derived state this widget owns.
DraftPainter
Walks the document and writes to a DrawSink. No cache of any kind.
DrawOp
One recorded call. Compared by value, so two painters that agree produce two equal op lists.
DrawSink
Where the painter writes.
EndDashOp
EndResidualOp
FillCircleOp
FillPolygonOp
FlutterTextMeasurer
Lays a string out once, at kNominalTextPixels, behind two caches.
GalleryCategory
One collapsible group of the gallery, in the caller's order.
GallerySymbol
One symbol as the gallery shows it.
GeometryCollector
Collects a document's stroked segments into one buffer, in walk order.
GesturePolicy
The per-platform half of camera gestures, as a value the widget is given rather than a kIsWeb it reads.
GripCache
The selection's grips and box, in world doubles (spec D6).
GripDrag
One drag's state and its one command (spec D2, D4).
GripRef
One grip of one selected root leaf, or — with object — one grip an ObjectGripProvider gives a selected root-level group. For a root leaf, owner space is world, so grip's coordinates are world; a provider's grips are world too.
InputClaim
Marks a subtree whose pointers are its own (host embedding API spec G-5): a widget a host lays over the canvas -- a badge on a table -- that takes the pointers landing on it, so the canvas under it does not act on them too.
InstanceFieldOffset
The record's field layout, as an offset in floats from the record's start — the writers below index by float, not byte.
InteractionLayer
Turns Flutter's pointer and key events into calls on the active Tool.
LineTool
Spec 05 D6: AutoCAD's LINE. Each click commits one segment, and its end is the next segment's start: the same stored values. Fill does not apply.
MoveAdjuster
What a body move's target may be replaced with, after the snap chain and before the move (alignment guides spec, C-8). An application seam: generic, the render layer knows no guides.
MoveResolver
Spec 09c D8: what a body drag of exactly one root-level node asks, on every retarget, for the transform the node should take instead of the plain move's. An application seam: the render layer knows no walls.
NullDrawSink
Counts ops and keeps none, so a measurement rig can time the walk without timing the rasteriser.
ObjectGripProvider
Grips for a selected root-level group that an application object type owns — a parametric object, whose own leaves are generated and carry none (spec 07 D11). GripCache consults it; GripDrag builds a reshape's command through it.
OutlineCache
The overlay's outlines: world geometry in Float64Lists, ui.Paths in the space rebased by the frame's origin (spec D9, review ruling B2).
PageCamera
The camera an export paints a page through (spec 13 D2).
PageChromePainter
The sheet, the grid and the page breaks, under DraftCanvas in its own RepaintBoundary (spec D8). Everything it hands dart:ui is a screen coordinate; the grid is enumerated over visibleWorld ∩ sheet, never over the sheet, which is what bounds the line count at every zoom.
PageNotifier
The document's page as a listenable (spec D10): seeded in the constructor, re-read on any change that touches the root, on a load and on a purge. ValueNotifier skips the notification when the value is ==, so an unrelated root edit costs its listeners nothing.
PageUnderlayCircle
A circle of radius r about (cx, cy) in its own space.
PageUnderlayFill
A fill under a page export's drawing (plan colours spec PC-7): a closed shape in its own space, placed in world by placement, in argb (0xAARRGGBB, drawn as given).
PageUnderlayPolygon
A closed polygon: xy interleaved x, y with the first point repeated as the last; count the point count including that duplicate; triangles its triangulation (triangulateSimplePolygon), never empty.
PaperPalette
The colours of everything drawn on the paper: the grid, the page breaks and the interaction overlays (dark theme spec D3). They follow the paper, not the theme, so they stay legible on any paper in either theme.
PatchImage
One patch's image and where it goes this frame.
PatchRegion
Where a patch draws on screen this frame: device pixels, on the viewport.
PdfDrawSink
A DrawSink that writes PDF operators onto one page (spec 13 D3).
PlacementTool
Spec 05 D3: what every drawing tool shares.
PointOp
PolylineOp
PolylineTool
Spec 05 D6. Each click appends a vertex:
RecordingDrawSink
Keeps every op, for tests and for the differential oracle.
RectangleTool
Spec 05 D7: two opposite corners, world-axis aligned, committed as a closed polyline whose every coordinate is a copy of a corner's.
RenderInputClaim
The render object of an InputClaim: a RenderProxyBox that records, in handleEvent, the pointers whose down reached it and the last hover or signal that did.
ResidentCollection
One rebuild's GPU-free product: what ResidentGeometry.create uploads, plus what the three frame-read triggers compare against.
ResidentFramePainter
What the frame path paints through once a rebuild has landed.
ResidentGpu
The seam between this package and a GPU that can serve RenderBackend.residentGpu.
ResidentLayout
The resident backend's buffer layout that needs no GPU: the corner table every instance is expanded over, and what a buffer of instance records costs.
ResidentRebuilder
Owns the resident backend's lifecycle for one DraftCanvas attachment: when to rebuild, and what the frame paints through meanwhile.
ResidentTextRecord
One text op, as the resident backend keeps it between rebuilds.
RulerCornerPainter
The 24 × 24 box where the bars meet: the unit's symbol.
RulerFrame
Two ruler bars and a corner around a drawing area (spec D11). Each bar is exactly co-extensive with the child on its own axis. A translucent Listener over the child feeds RulerFrameState.pointer; the child's own listeners still receive every event. The labels take the font family of the ambient DefaultTextStyle: under a Material Scaffold the app's font, directly under a MaterialApp the debug fallback's.
RulerFrameState
RulerPainter
One ruler bar (spec D11): ticks from the shared ladder, zero at the sheet corner, labels in the display unit, a pointer marker. The bar is co-extensive with the drawing area on its axis, so size on that axis is the child's, and every tick is placed through camera.worldToScreen.
SelectGates
What the select tool and the grip cache may do, asked live (host embedding API spec C-5, F-15; Slice 4's S-9 and S-15): a pick override, a band filter, and the move, rotate, reshape, delete and idle-key gates.
SelectionBandPainter
Paints a selection band over a rect in screen pixels: the band colour at kBandFillAlpha, a 1 px outline, solid for a window, dashed 6 on and 4 off for a crossing, walking the edges clockwise from the top-left.
SelectionController
Application-only selection state (spec D6, D11).
SelectionKey
A selectable object, identified by the chain of instances a viewer descended through to reach it plus the handle it bottoms out on.
SelectionOverlayPainter
Draws the selected and hovered outlines, then lets the active tool draw its own overlay — and never touches the drawing underneath.
SelectTool
Hover, click, shift-click and rubber-band selection (spec 02 D1, D2, D7, D8), Escape and Delete/Backspace (02 D3, D10) — and, since 03, grips:
SnapSettings
F3's object-snap toggle (spec D10). The shell owns it; a drag reads it per event through ToolContext.snap.
SymbolGallery
Spec 09b D4: the symbols, grouped by category, as a scrollable column of collapsible headers over two-column grids of thumbnail cells.
SymbolThumbnails
Thumbnails of small documents, painted by DraftPainter and cached.
TextCompositor
Composites one frame: the main image, then the resident text list in emission order, with a patch composited over each covered label.
TextOp
TextPatch
A label some later instance reaches, and the instances that reach it.
TextPlacement
Where a pending text will go, and how tall (spec 05 D9).
TextTool
Spec 05 D9. A click sets pending; the app's field edits controller.
TileBand
One tile row of the visible region: every key in it, and the device rectangle they span.
TileCache
A cache of rasterised viewport tiles.
TileGrid
One scale generation's lattice.
TileKey
One tile's position in its generation's grid. Not world coordinates: the grid is anchored to the generation's own device-pixel lattice.
Tool
The interface every interactive tool implements. A ChangeNotifier so ToolController can forward a tool's own notifications (an overlay change, a phase change) without polling.
ToolContext
Everything a Tool needs to act: the document to mutate, the index to query, the camera to read, the selection to update — and, since 03, the page, the snap settings and the grips, each optional so every 02 call site still compiles (spec D10).
ToolController
Holds the active Tool and forwards its notifications, so a widget can listen to the controller alone rather than re-subscribing on every swap.
ToolPointerEvent
One pointer sample handed to a Tool, already resolved into both screen and world space so a tool never has to invert the camera itself.
VerticesDrawSink
Builds each stroked segment's two triangles itself and submits the whole frame's strokes as one drawVertices, instead of one drawPath per segment.
ViewportTransform
The world→screen affine, held in Float64 for its whole life.

Enums

DragKind
What a SelectTool drag is doing (spec D5).
ExportDpi
The resolutions a PNG export offers (spec 13 decision 6, D5).
PressClass
What a press landed on (spec 03 D2). The first class that hits wins.
RebuildTrigger
Why a rebuild ran. The spec's five triggers, plus the first build.
RenderBackend
Which sink DraftCanvas draws through.
RulerAxis
ScrollSignalAction
What a bare scroll signal does to the camera.
ToolPhase
TouchPress
How InteractionLayer hands a tool a finger's press (spec 14t R-1).

Constants

kAnisotropyThreshold → const double
How far from conformal a curve's screen transform may be before its baked stroke width stops being close enough.
kBakeBudgetDevicePixels → const int
The device-pixel area a frame may spend baking tiles, while a generation fills in.
kBandFillAlpha → const int
Alpha of the band's fill, out of 255. The stroke stays fully opaque.
kBandLowerScale → const double
The band WAS measured (Plan F, Task 7, flutter test), and these two stay where they were. On straight geometry (crossingGrid) criterion 1 holds across the whole [0.25, 4.0] sweep -- no constant limits it there. On a corpus that carries a curve or a near-threshold label, criterion 1 is a step at each frozen watermark decision (the chord count; text culling), not a drift that a wider or narrower band would trade off against, so the reported band is the degenerate [1.0, 1.0]. The constants below stay at 0.5 / 2.0 under Ruling F6-a: shrinking them would rebuild after every zoom step, which is a design change, not a controller tuning -- whether to unfreeze either watermark row is the human's decision, not this plan's. See docs/superpowers/notes/2026-09-05-plan-f-results.md.
kBandSlopPixels → const double
A press that moves less than this many screen pixels stays a click (M-02f); past it, a press becomes the drag its class names (spec 03 D2).
kBandUpperScale → const double
kBreaksMinSheetPixels → const double
Below this on-screen sheet size the page-break tiling is not drawn: the bound at extreme zoom-out (spec D8).
kClassifyOverflowCells → const int
Cells an instance's reach-expanded box may span before it leaves the grid for the overflow list, which every label tests. A long wall through a floor plan would otherwise be appended to hundreds of buckets.
kDarkCanvasColouredChroma → const double
The OKLab chroma from which a colour is treated as coloured (K3): it is never darkened. Every saturated ACI colour (1–6, chroma ≥ 0.155) sits here. Between the two the cases blend linearly.
kDarkCanvasNeutralChroma → const double
The OKLab chroma up to which a colour is treated as neutral (K3): it takes the exact contrast mirror, so it may darken. Pale tints (a pale zone fill, chroma 0.03–0.09) sit here, so a subtle fill stays subtle.
kDarkCanvasPaper → const int
The sheet a dark theme shows in place of a light document paper, ARGB (dark canvas decision note K1): a neutral dark, as in AutoCAD.
kFloatsPerInstance → const int
Floats per instance record.
kGalleryThumbnailAspect → const double
The logical width-to-height ratio of a cell's thumbnail.
kGridMarkerPixels → const double
kGripHitPixels → const double
A press or hover within this many screen pixels of a grip's centre hits it (spec D2).
kGripPixels → const double
Grip squares (spec D6): side in screen pixels, drawn by drawRawPoints with a square cap at this stroke width.
kHoverStrokePixels → const double
kLogicalPixelsPerMm → const double
Logical pixels per millimetre at Flutter's nominal 96 dpi.
kMajorTickPixels → const double
kMaxGrips → const int
Past this many grips in the selection, no leaf grip is shown (spec D6). Body move and rotate still work.
kMetricsCacheLimit → const int
The metrics cache's entry ceiling.
kMetricsProbeArgb → const int
The colour a metrics-only request is built with.
kMinorTickPixels → const double
kMinTextCapPixels → const double
Text whose on-screen cap height is below this many logical pixels is not drawn, and not laid out either.
kMiterLimit → const double
The miter limit the shader's join branch is bounded by -- a miter tip is never further than halfWidth * kMiterLimit from its vertex (vertices_draw_sink.dart:460, 544-552). A copy, not a reference, by the same rule GeometryCollector.kMinStrokeDevicePixels states: the two arms arrive at their numbers separately and the differential is what catches a drift. resident_text_test.dart pins this to VerticesDrawSink.kMiterLimit.
kParagraphCacheLimit → const int
The paragraph cache's entry ceiling.
kPickRadiusPixels → const double
Pick radius in screen pixels (spec D7).
kPinchMinSpan → const double
Below this span, in screen pixels, two fingers pan but do not zoom (spec 14t T2): a ratio of near-coincident fingers is noise.
kPreviewStrokePixels → const double
The drag preview's and its guide line's stroke (spec D7).
kRestGateFrames → const int
Consecutive unchanged frames before a rest bake is permitted.
kRotationGripOffset → const double
kRotationGripPixels → const double
The rotation grip: a disc of this diameter, kRotationGripOffset screen pixels above the top-centre of the selection's screen box (spec D6).
kRotationStep → const double
Shift's rotation step (spec D8): 15°.
kRulerLabelSize → const double
kRulerThickness → const double
Thickness of each ruler bar and the corner box, logical pixels.
kScreenClipInflate → const double
How far past the viewport, in device pixels, the frame's clip reaches.
kSelectionStrokePixels → const double
Outline stroke widths in screen pixels. The overlay divides each by camera.scale per frame, so the width on screen holds at any zoom.
kSnapMarkerPixels → const double
Snap markers (spec D9).
kSnapMarkerStrokePixels → const double
kStatusCaptionOnDark → const Color
A table status caption's colour where the paper it lies on takes white ink (dark theme spec D6c, as amended by P7).
kStatusCaptionOnLight → const Color
A table status caption's colour where the paper it lies on takes black ink (dark theme spec D6c, as amended by P7): today's caption. A group chip's text, which lies on the chip, takes the same two colours from the chip's own ink.
kTextBoxPadDevicePixels → const double
The label box is padded by this many device pixels, taken at the band's LOWER scale (Ruling E9): one device pixel is most collection units at the band's floor, so that is the conservative pad. It covers antialiased glyph edges and glyph overhang past the advance box.
kThumbnailPadding → const double
The fraction of a document's larger side added as a margin on every side before the thumbnail camera fits it.
kTileCacheBytes → const int
The cache's byte ceiling, counting the carry-over composite and every generation's tiles together.
kTileDevicePixels → const int
A tile's side, in device pixels.
kTileSlack → const double
The slack a tile's arrival rule and its invalidation rule share, in logical pixels.
kTouchGripHitPixels → const double
A fingertip's reach to a grip or the rotation grip (spec 14t T4b).
kTouchHoldBack → const Duration
How long a finger is held back before a TouchPress.press tool sees its down (spec 14t T3): long enough for a pinch's second finger to land.
kTouchPickRadiusPixels → const double
How far a fingertip's miss may reach, in screen pixels (spec 14t R-3): a 48 px target.

Properties

registeredResidentGpu → ResidentGpu?
The registered resident GPU, or null when none is installed.
no setter

Functions

bandModeFor(Offset start, Offset end) → BandMode
The band's mode by its drag direction (interaction-core D1): left to right is a window, right to left a crossing.
boundTransformedBox(double minX, double minY, double maxX, double maxY, Transform2 t, Float64List out) → void
The axis-aligned bound of the box (minX, minY)..(maxX, maxY) under t: all four corners transformed and re-bounded, so a rotated, sheared or mirrored box bounds correctly (Aabb2.transformedBy's own rule), written into out as [minX, minY, maxX, maxY]. Allocation-free -- out is caller-owned and reused. Called from the rebuild walk (the collector's text(), sizing a label's box) and, per frame, from patchRegionFor and text_compositor.dart's labelBoundsLogical -- the frame-path callers this doc once named as future work.
buildFrameInfo(Transform2 collectionToDevice, int widthPx, int heightPx, {required double dashScale, ByteData? out}) → ByteData
The uniform block: mat4 mvp, vec2 half_viewport, then float dash_scale, std140, 80 bytes.
canvasResolverFor(DraftDocument document, {required int paper, required bool dark}) → StyleResolver
The canvas's resolver for document on the display paper (ARGB, from displayPaperFor). On a dark canvas (dark, from darkCanvasFor) it is a DarkCanvasStyleResolver over the drawing as it is on white paper (K3); otherwise ACI 7 takes paper's foreground, as before.
classifyTextPatches(Float32List data, int instanceCount, List<ResidentTextRecord> texts, {required double devicePixelRatio, double bandLowerScale = kBandLowerScale, ClassifyStats? stats}) → List<TextPatch>
Classifies every label in texts against every instance written after it, in collection space -- the spec's "conservative, box on box" test.
classifyTextPatchesBruteForce(Float32List data, int instanceCount, List<ResidentTextRecord> texts, {required double devicePixelRatio, double bandLowerScale = kBandLowerScale}) → List<TextPatch>
Classifies every label in texts against every instance written after it, in collection space -- the spec's "conservative, box on box" test.
collectionFrameFor(ViewportTransform live, Aabb2 extents, {double margin = kScreenClipInflate}) → CollectionFrame
The frame a rebuild at live walks under, covering extents.
composeTransforms(Transform2 outer, Transform2 inner) → Transform2
outer ∘ inner.
darkCanvasFor({required int? page, required Brightness brightness}) → bool
True when the canvas re-tones: a dark theme over a page whose paper takes black ink (White, Ivory, Grey, or any light custom paper). A dark paper (Blueprint) and a document with no page are shown as they are (K1).
darkCanvasTone(int rgb, int paperRgb) → int
rgb (0xRRGGBB) as shown on the dark paperRgb (K3): the colour whose WCAG contrast against paperRgb equals rgb's contrast against white, at rgb's OKLab hue. A neutral colour takes it exactly, so light grey goes dark grey and black goes white; a coloured one is never darkened, so yellow stays yellow; between them the two blend by chroma. The result is brought into sRGB by reducing chroma, never by clipping a channel. White, whose contrast on white is 1, shows as paperRgb itself, so a white mask is the paper, as it is on white paper.
dashScaleFor(ViewportTransform camera, Transform2 collectionInverse) → double
Live logical pixels per collection unit -- the factor the shader compares a dash period against kDashCollapsePx.
defaultRenderBackend() → RenderBackend
The backend a platform gets when the caller does not say.
displayPaperFor({required int? page, required int surface, required Brightness brightness}) → int
The paper the canvas shows, ARGB (K1, K2): kDarkCanvasPaper on a dark canvas, else the page's background, else, with no page, the theme's surface. Everything that keys on the paper reads this one value.
drawPageUnderlay(DrawSink sink, ViewportTransform camera, List<PageUnderlayFill> fills) → void
Draws fills in order through sink under camera: each under the residual camera.worldToScreenMatrix · placement, as DraftPainter draws a leaf.
drawSnapMarker(Canvas canvas, Offset at, SnapKind? kind, {required bool grid, required Paint paint}) → void
Spec D9's marker at at, in screen space: a fixed, small number of draw calls. kind non-null means an object snap won; otherwise grid draws the grid's +, and nothing is drawn when the raw point won.
exportPagePdf({required DraftDocument document, required PageComponent page, required Uint8List fontBytes, Set<Handle> omitOwners = const {}, List<PageUnderlayFill> underlay = const [], bool compress = true}) → Future<Uint8List>
The page of document as a one-page vector PDF (spec 13 D4).
exportPagePng({required DraftDocument document, required PageComponent page, ExportDpi dpi = ExportDpi.d150, Set<Handle> omitOwners = const {}, List<PageUnderlayFill> underlay = const []}) → Future<Uint8List>
The page of document as a PNG at dpi (spec 13 D5).
fitToPage(PageComponent page, Size viewport) → ViewportTransform
The camera that shows the whole sheet with fit's 5 % margin (spec D4).
labelBoundsLogical(ResidentTextRecord t, Transform2 m, {Float64List? scratch}) → Rect
The label's box under the outer transform, as a logical-pixel Rect.
movableKey(DraftDocument d, SelectionKey key, ObjectGripProvider? objects) → bool
Whether the select tool may move or rotate key (spec 08 D16): false only for a root-level group that objects calls immovable. Everything else is decided where it always was (a fill or an attrib is skipped by the capture itself, spec 03 D4).
pageCamera(PageComponent page, double unitsPerPaperMm) → PageCamera
The page camera for page at unitsPerPaperMm (u), spec D2: with S = sheetWorldRect(page) and k = u / page.scaleDenominator, x' = (x - S.minX) * k and y' = (S.maxY - y) * k.
patchRegionFor(ResidentTextRecord t, Transform2 collectionToDevice, int widthPx, int heightPx, {required int maxWidth, required int maxHeight, Float64List? scratch, PatchRegion? out}) → PatchRegion?
The label's box under the live camera, intersected with the viewport, rounded outward and clamped to the patch target's size (Ruling E8).
patchTargetSizeFor(ResidentTextRecord t, double devicePixelRatio, {double bandUpperScale = kBandUpperScale, required int maxWidth, required int maxHeight}) → (int, int)
The patch target's size: the label's box at the band's CEILING, in device pixels, rounded up and clamped to the viewport -- the largest region patchRegionFor can return inside the band, so a zoom inside it resizes the region and never the texture. Never zero in either dimension: a zero-sized texture is a per-backend question this plan does not ask (the same rule ResidentGeometry._upload applies to an empty instance buffer).
quantiseCamera(ViewportTransform camera, double devicePixelRatio) → ViewportTransform
Snaps a camera's screen translation to whole device pixels.
rebaseOriginFor(Aabb2 visibleWorld) → Vector2
The rebase origin for one frame: the view's centre snapped to a power-of-two world grid whose step is derived from the view span.
referenceWalk(DraftDocument doc, DrawSink sink, ViewportTransform camera, Size viewport, StyleResolver resolver, {double minTextCapPixels = kMinTextCapPixels, Set<Handle> omitOwners = const {}}) → void
Draws the document the slow, obvious way, so DraftPainter can be compared against it.
registerResidentGpu(ResidentGpu? gpu) → void
Registers gpu as the process's resident GPU; null clears the registration. The last registration wins.
resolveBackend(RenderBackend requested) → RenderBackend
The backend that will actually run, given what the caller asked for.
resolveHit(HitPath hit, DraftDocument document) → SelectionKey?
Spec D2: the root-level object under a hit, or null for a miss or a truncated chain. Never throws at hover rate.
rootLevelNodeOf(DraftDocument document, Handle owner, List<Handle> ancestors) → Handle
The last handle in [owner, ...ancestors] before the root: the root-level node owner sits under, or owner itself when it is one. ancestors is tree.ancestorsOf(owner), nearest first.
rotationGripOf(Aabb2 box, Transform2 worldToScreen, [Transform2? frame, Transform2? after]) → ({Offset anchor, Offset centre, Offset stem})
Where the rotation grip sits (spec D6). box is in frame's coordinates; frame maps them to world and defaults to the identity.
sameQuantisedCamera(ViewportTransform a, ViewportTransform b) → bool
Whether two quantised cameras describe the same view, field by field.
stripFor(Rect uncovered, Size viewport) → Rect
The rectangle the live fallback walks: uncovered grown by kTileSlack on every side, then clamped to viewport.
topmostGroupOf(DraftDocument document, Handle owner, List<Handle> ancestors) → Handle?
The last group in [owner, ...ancestors] before the root, or null when none is a group. ancestors is tree.ancestorsOf(owner), nearest first.
withPhysChunk(Uint8List png, int dpi) → Uint8List
png with one pHYs chunk of round(dpi / 0.0254) pixels per metre on both axes (unit 1, the metre) right after IHDR; any pHYs already in png is dropped, so exactly one remains.

Typedefs

FlushObserver = void Function(Float32List positions, Int32List colors)
Handed the position and colour views a VerticesDrawSink.flush submitted, before it rewinds the buffer.
ResidentUploader = Future<ResidentFramePainter?> Function(ResidentCollection collection, Size viewport)
Turns one collection into a frame painter, or null when it cannot.