finish method
Decodes every batch's alpha atlas, then replays the tape onto
canvas: fallback ops drive a real CanvasPdfDevice, strip batches
draw as shader-carrying drawVertices under the device->page transform.
Await before endRecording(); the device is unusable afterwards.
Implementation
Future<void> finish() async {
assert(!_finished, 'StripPdfDevice.finish() called twice');
_finished = true;
flushPending();
_flushSlug(flushPointCount - 1);
final plan = _plan;
if (plan != null &&
(flushPointCount != plan.totalFlushPoints ||
_planNext != plan.batches.length ||
_planSlugNext != plan.slugBatches.length ||
_planSlugFallbackNext != plan.slugFallbackOrdinals.length)) {
// Desync is only detectable once the walk is complete; nothing has
// painted yet (painting starts below), so the caller can discard the
// recording and re-run with local binning.
totalPlanMismatches++;
throw StripPlanMismatchError(
'flush points: device $flushPointCount vs plan '
'${plan.totalFlushPoints}; consumed $_planNext of '
'${plan.batches.length} strip and $_planSlugNext of '
'${plan.slugBatches.length} Slug batches; consumed '
'$_planSlugFallbackNext of ${plan.slugFallbackOrdinals.length} '
'Slug fallbacks');
}
if (plan != null && !debugVerifyPrecomputed) totalPlanPictures++;
final sw = Stopwatch()..start();
final program = await _loadProgram();
final slugProgram = _slugBatches.isEmpty ? null : await _loadSlugProgram();
await Future.wait([
for (final b in _batches) b.decodeAtlas(),
for (final b in _slugBatches) b.decodeAtlas(),
]);
totalAtlasDecodeMicros += sw.elapsedMicroseconds;
sw.reset();
final fallback = CanvasPdfDevice(canvas, images: images);
for (final entry in _tape) {
if (entry is StripBatch) {
_drawBatch(program, entry);
} else if (entry is SlugBatch) {
_drawSlugBatch(slugProgram!, entry);
} else {
(entry as void Function(CanvasPdfDevice))(fallback);
}
}
totalReplayMicros += sw.elapsedMicroseconds;
}