blob: 9274d67633dce89bb7a7bffd8473887f275c1907 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
part of engine;
/// A monotonically increasing frame number being rendered.
///
/// Used for debugging only.
int _debugFrameNumber = 1;
List<FrameReference<dynamic>> _frameReferences = <FrameReference<dynamic>>[];
/// A temporary reference to a value of type [V].
///
/// The value automatically gets set to null after the current frame is
/// rendered.
///
/// It is useful to think of this as a weak reference that's scoped to a
/// single frame.
class FrameReference<V> {
/// Creates a frame reference to a value.
FrameReference([this.value]) {
_frameReferences.add(this);
}
/// The current value of this reference.
V value;
}
/// Cache where items cached before frame(N) is committed, can be reused in
/// frame(N+1) and are evicted if not.
///
/// A typical use case is image elements. As images are created and added to
/// DOM when painting a scene they are cached and if possible reused on next
/// update. If the next update does not reuse the element, it is evicted.
///
/// Maps are lazily allocated since many pictures don't contain cachable images
/// at all.
class CrossFrameCache<T> {
// Cached items in a scene.
Map<String, List<_CrossFrameCacheItem<T>>> _cache;
// Cached items that have been committed, ready for reuse on next frame.
Map<String, List<_CrossFrameCacheItem<T>>> _reusablePool;
// Called when a scene or picture update is committed.
void commitFrame() {
// Evict unused items from prior frame.
if (_reusablePool != null) {
for (List<_CrossFrameCacheItem<T>> items in _reusablePool.values) {
for (_CrossFrameCacheItem<T> item in items) {
item.evict();
}
}
}
// Move cached items to reusable pool.
_reusablePool = _cache;
_cache = null;
}
/// Caches an item for reuse on next update frame.
///
/// Duplicate keys are allowed. For example the same image url may be used
/// to create multiple instances of [ImageElement] to be reused in the future.
void cache(String key, T value, [CrossFrameCacheEvictCallback<T> callback]) {
_addToCache(key, _CrossFrameCacheItem<T>(value, callback));
}
void _addToCache(String key, _CrossFrameCacheItem<T> item) {
_cache ??= {};
(_cache[key] ??= [])..add(item);
}
/// Given a key, consumes an item that has been cached in a prior frame.
T reuse(String key) {
if (_reusablePool == null) {
return null;
}
List<_CrossFrameCacheItem<T>> items = _reusablePool[key];
if (items == null || items.isEmpty) {
return null;
}
_CrossFrameCacheItem<T> item = items.removeAt(0);
_addToCache(key, item);
return item.value;
}
}
class _CrossFrameCacheItem<T> {
final T value;
final CrossFrameCacheEvictCallback<T> evictCallback;
_CrossFrameCacheItem(this.value, this.evictCallback);
void evict() {
if (evictCallback != null) {
evictCallback(value);
}
}
}
typedef CrossFrameCacheEvictCallback<T> = void Function(T value);