beginSlideBaseline method
- required Duration duration,
- required Curve curve,
- Map<
TKey, ({double? x, double y})> ? baselineOverrides,
Captures the current painted offsets so the next performLayout can install a FLIP slide from them to the post-mutation offsets.
Call this BEFORE invoking a structural mutation on the controller
(reorderRoots, reorderChildren, moveNode). Calling it after
the mutation would capture the already-new offsets and produce a
zero-delta (no visible slide).
First-wins semantic: if a baseline is already pending this frame (from a prior call by any entry path, host fan-out OR a direct caller like the reorder controller), this call is a no-op. The first stage captured the truly-painted positions; subsequent stages would read already-mutated controller state and produce wrong deltas for rows touched by earlier same-frame calls.
Caller contract: every successful stage MUST be followed by a structural mutation that triggers a layout pass in the same frame (or via a microtask before the next frame). Otherwise the staged baseline stays pending and blocks all subsequent stages until some other layout-triggering mutation flushes it.
Internal contract: intended for the reorder controller and the controller's host fan-out. External callers should not invoke this directly.
Implementation
@override
void beginSlideBaseline({
required Duration duration,
required Curve curve,
Map<TKey, ({double y, double? x})>? baselineOverrides,
}) {
// Not-laid-out guard: snapshotVisibleOffsets walks visible rows
// accumulating extents from controller state. Before first layout,
// those extents fall through to defaultExtent and the snapshot is
// fictitious. Silently no-op rather than stage a garbage baseline.
if (geometry == null) return;
// First-wins, asked BEFORE the snapshot rather than after it. The
// slot refuses a second stage in the same cycle, so the O(visible)
// walk and its map (one entry and one key hash per row) below would
// be computed only to be discarded. K animated mutations in one
// frame are routine (a batched reparent, a sync diff), and paying
// K snapshots for one baseline was the dominant cost of such a
// batch. Pinned by `slide_baseline_first_wins_cost_test.dart`.
if (_composer.isBaselineStaged) {
return;
}
final offsets = snapshotVisibleOffsets();
// Per-key overrides (proxy drop-settle): the consume path installs
// the FLIP from these positions instead of the painted ones. Only
// keys already in the snapshot participate: an absent key has no
// "current" to diff against. A null x preserves the snapshot's
// captured cross offset (which includes any in-flight x slide, so
// recomputing it from the structural indent here would be wrong):
// the y-only semantics of sessions with no proxy cross-offset
// source.
if (baselineOverrides != null) {
for (final entry in baselineOverrides.entries) {
final existing = offsets[entry.key];
if (existing != null) {
offsets[entry.key] = (
y: entry.value.y,
x: entry.value.x ?? existing.x,
);
}
}
}
// First-wins is enforced by SlideBaselineSlot.stage's bool return.
final staged = _composer.baselineSlot.stage(
offsets: offsets,
viewport: _currentViewportSnapshot(),
duration: duration,
curve: curve,
);
if (staged) {
_scheduleBaselineExpiry(_composer.baselineSlot.pendingStamp);
}
}