diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index d0c7bc11c..25d8c4baa 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -3619,8 +3619,13 @@ class CursorModel with ChangeNotifier { String nativeKey(CursorData cache, double scale) { final key = '${_keyScope}_${cache.updateGetKey(scale)}'; - // A native cursor at another raster does not hold the pixels this one is made from. - if (!_cacheKeys.contains(key)) _nativeIds.remove(cache.id); + // A shape is held by a native cursor at the raster asked last; one at another raster does + // not hold the pixels this one is made from. + if (_cacheKeys.contains(key)) { + _nativeIds.add(cache.id); + } else { + _nativeIds.remove(cache.id); + } return key; } diff --git a/flutter/test/cursor_replay_test.dart b/flutter/test/cursor_replay_test.dart index 1bccddd7d..5ab9828a5 100644 --- a/flutter/test/cursor_replay_test.dart +++ b/flutter/test/cursor_replay_test.dart @@ -267,6 +267,27 @@ void main() { isNotEmpty); }); + test('a raster returned to counts again as held by its native cursor', + () async { + final cursor = ffi.cursorModel; + await _feed(ffi, 'A', size: 32); + buildCursorOfCache(cursor, 1.0, cursor.cache); + await _settle(); + await _feed(ffi, 'B'); + buildCursorOfCache(cursor, 1.0, cursor.cache); + await _settle(); + + _select(ffi, 'A'); + ffi.cursor.holdFetches = true; + buildCursorOfCache(cursor, 0.5, cursor.cache); // no cursor at 0.5: fetched + buildCursorOfCache(cursor, 1.0, cursor.cache); // back at 1.0, which has one + _select(ffi, 'B'); + ffi.cursor.answerFetches(); + await _settle(); + expect(cursor.cachedShape('A')!.hasPixels, isFalse, + reason: 'its native cursor at the raster asked last holds it'); + }); + test('shapes waiting for a native cursor keep their pixels, within the limit', () async { const max = CursorModel.kRecentShapes;