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>
57 lines
1.7 KiB
Dart
57 lines
1.7 KiB
Dart
// lib/editor/render/live_ink_painter.dart
|
|
//
|
|
// CustomPainter for the in-progress stroke (live) layer.
|
|
//
|
|
// Paints only the single EditorStroke? currently being drawn, with
|
|
// isComplete:false so perfect_freehand tapers the trailing end correctly.
|
|
// Kept in a separate RepaintBoundary so committed strokes are never
|
|
// re-rasterized on pointer-move events.
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../engine/stroke_geometry.dart';
|
|
import '../engine/stroke_model.dart';
|
|
|
|
/// Paints the single in-progress [EditorStroke] (or nothing when [live] is
|
|
/// null / empty). Use alongside [StaticInkPainter] in stacked [CustomPaint]s.
|
|
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, thinning: thinning);
|
|
if (path.getBounds().isEmpty) return;
|
|
|
|
canvas.drawPath(
|
|
path,
|
|
Paint()
|
|
..color = Color(stroke.color)
|
|
..style = PaintingStyle.fill
|
|
..isAntiAlias = true,
|
|
);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(LiveInkPainter old) =>
|
|
!identical(old.live, live) ||
|
|
old.pageSize != pageSize ||
|
|
old.thinning != thinning;
|
|
}
|