beginSlideBaseline method

  1. @override
void beginSlideBaseline({
  1. required Duration duration,
  2. required Curve curve,
  3. Map<TKey, ({double? x, double y})>? baselineOverrides,
})
override

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);
  }
}