feat(p0): live canvas renders via revision-gated ui.Picture cache (step 3)
Some checks failed
CI / Windows build (push) Has been cancelled

The live PenCanvas committed-ink layer now uses the relocated render/ painters
(render.StaticInkPainter + InkPictureCache + StrokeStore) instead of the old
canvas/ink_painters versions — the P0.5 perf prerequisite. The committed layer's
ui.Picture is recorded once per StrokeStore.revision and replayed on the raster
thread, so pinch / pan / live-stroke frames no longer re-rasterize committed ink.

- pen_canvas mirrors widget.strokes (PenStroke) into a StrokeStore (EditorStroke)
  on every new-list identity (the parent already replaces the list on each
  commit/erase), bumping the revision → cache invalidates → static layer repaints.
- thinning (PenConfig.pressureSensitivity) is threaded into the render painters
  AND folded into the cache key + shouldRepaint, so a sensitivity change can't
  replay a stale Picture built at the old thinning.
- live layer converts _liveStroke→EditorStroke per frame (correct: it must
  repaint every move); eraser preview keeps the existing canvas painter.
- pen_canvas disposes the InkPictureCache.

Equivalent by construction (both paths call buildStrokeOutline with the same
thinning); device confirms final fidelity. The old canvas Static/LiveInkPainter
are now orphaned (buildStrokePath still used by tests) — P1 deletes them.

flutter analyze lib/editor clean; 90/90 tests (+6: thinning repaint/cache + live).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-23 02:59:30 +08:00
parent f64e6561a0
commit eca5141372
4 changed files with 152 additions and 12 deletions

View File

@@ -18,18 +18,25 @@ class LiveInkPainter extends CustomPainter {
const LiveInkPainter({
required this.live,
required this.pageSize,
this.thinning = kDefaultPenThinning,
});
/// The stroke currently being drawn, or null when idle.
final EditorStroke? live;
final Size pageSize;
/// perfect_freehand pressure→width response (from `PenConfig.pressureSensitivity`),
/// kept consistent with the static layer so the stroke doesn't change width
/// the instant it commits.
final double thinning;
@override
void paint(Canvas canvas, Size size) {
final stroke = live;
if (stroke == null || stroke.points.isEmpty) return;
final path = buildStrokeOutline(stroke, pageSize, isComplete: false);
final path = buildStrokeOutline(stroke, pageSize,
isComplete: false, thinning: thinning);
if (path.getBounds().isEmpty) return;
canvas.drawPath(
@@ -43,5 +50,7 @@ class LiveInkPainter extends CustomPainter {
@override
bool shouldRepaint(LiveInkPainter old) =>
!identical(old.live, live) || old.pageSize != pageSize;
!identical(old.live, live) ||
old.pageSize != pageSize ||
old.thinning != thinning;
}