// Double-buffer helper on top of [PageTileCache] to kill zoom white-flash: // keep painting the last good tile while a higher-DPI raster is in flight. import 'dart:ui' as ui; import 'package:flutter/widgets.dart'; import 'page_tile_cache.dart'; /// Holds the "last good" page image for the currently visible page so a zoom /// settle never exposes an empty frame (plan W2 / R11). class PageTileLayer extends ChangeNotifier { PageTileLayer({PageTileCache? cache}) : _cache = cache ?? PageTileCache(); final PageTileCache _cache; ui.Image? _lastGood; TileKey? _lastKey; PageTileCache get cache => _cache; ui.Image? get lastGood => _lastGood; TileKey? get lastKey => _lastKey; /// Snap continuous zoom to a coarse DPI bucket (avoids a tile per frame). static int dpiBucketFor(double zoom, {double baseDpi = 96, double step = 0.5}) { final raw = zoom / step; final snapped = raw.round().clamp(1, 16); return (snapped * step * baseDpi).round(); } /// Promote [image] as the last-good tile for [key]. void put(TileKey key, ui.Image image) { _cache.put(key, image); _lastGood = image; _lastKey = key; notifyListeners(); } /// Prefer exact bucket; else fall back to last-good so zoom never blanks. ui.Image? resolve(TileKey key) { final hit = _cache.get(key); if (hit != null) { _lastGood = hit; _lastKey = key; return hit; } return _lastGood; } void clear() { _lastGood = null; _lastKey = null; _cache.dispose(); notifyListeners(); } @override void dispose() { clear(); super.dispose(); } }