mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
recall the last frame in the animated image after resurrection (flutter/engine#26277)
This commit is contained in:
parent
28e7fbfd72
commit
e3646a04a3
@ -101,6 +101,11 @@ class CkAnimatedImage extends ManagedSkiaObject<SkAnimatedImage>
|
||||
|
||||
final String src;
|
||||
final Uint8List _bytes;
|
||||
int _frameCount = 0;
|
||||
int _repetitionCount = -1;
|
||||
|
||||
/// The index to the next frame to be decoded.
|
||||
int _nextFrameIndex = 0;
|
||||
|
||||
@override
|
||||
SkAnimatedImage createDefault() {
|
||||
@ -112,12 +117,24 @@ class CkAnimatedImage extends ManagedSkiaObject<SkAnimatedImage>
|
||||
'Image source: $src',
|
||||
);
|
||||
}
|
||||
|
||||
_frameCount = animatedImage.getFrameCount();
|
||||
_repetitionCount = animatedImage.getRepetitionCount();
|
||||
|
||||
// If the object has been deleted then resurrected, it may already have
|
||||
// iterated over some frames. We need to skip over them.
|
||||
for (int i = 0; i < _nextFrameIndex; i++) {
|
||||
animatedImage.decodeNextFrame();
|
||||
}
|
||||
return animatedImage;
|
||||
}
|
||||
|
||||
@override
|
||||
SkAnimatedImage resurrect() => createDefault();
|
||||
|
||||
@override
|
||||
bool get isResurrectionExpensive => true;
|
||||
|
||||
@override
|
||||
void delete() {
|
||||
rawSkiaObject?.delete();
|
||||
@ -144,13 +161,13 @@ class CkAnimatedImage extends ManagedSkiaObject<SkAnimatedImage>
|
||||
@override
|
||||
int get frameCount {
|
||||
assert(_debugCheckIsNotDisposed());
|
||||
return skiaObject.getFrameCount();
|
||||
return _frameCount;
|
||||
}
|
||||
|
||||
@override
|
||||
int get repetitionCount {
|
||||
assert(_debugCheckIsNotDisposed());
|
||||
return skiaObject.getRepetitionCount();
|
||||
return _repetitionCount;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -159,6 +176,7 @@ class CkAnimatedImage extends ManagedSkiaObject<SkAnimatedImage>
|
||||
final int durationMillis = skiaObject.decodeNextFrame();
|
||||
final Duration duration = Duration(milliseconds: durationMillis);
|
||||
final CkImage image = CkImage(skiaObject.getCurrentFrame());
|
||||
_nextFrameIndex = (_nextFrameIndex + 1) % _frameCount;
|
||||
return Future<ui.FrameInfo>.value(AnimatedImageFrameInfo(duration, image));
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +43,34 @@ void testMain() {
|
||||
testCollector.collectNow();
|
||||
});
|
||||
|
||||
test('CkAnimatedImage remembers last animation position after resurrection', () async {
|
||||
browserSupportsFinalizationRegistry = false;
|
||||
|
||||
Future<void> expectFrameData(ui.FrameInfo frame, List<int> data) async {
|
||||
final ByteData frameData = await frame.image.toByteData();
|
||||
expect(frameData.buffer.asUint8List(), Uint8List.fromList(data));
|
||||
}
|
||||
|
||||
final CkAnimatedImage image = CkAnimatedImage.decodeFromBytes(kAnimatedGif, 'test');
|
||||
expect(image.frameCount, 3);
|
||||
expect(image.repetitionCount, -1);
|
||||
|
||||
final ui.FrameInfo frame1 = await image.getNextFrame();
|
||||
expectFrameData(frame1, <int>[0, 255, 0, 255]);
|
||||
final ui.FrameInfo frame2 = await image.getNextFrame();
|
||||
expectFrameData(frame2, <int>[0, 0, 255, 255]);
|
||||
|
||||
// Pretend that the image is temporarily deleted.
|
||||
image.delete();
|
||||
image.didDelete();
|
||||
|
||||
// Check that we got the 3rd frame after resurrection.
|
||||
final ui.FrameInfo frame3 = await image.getNextFrame();
|
||||
expectFrameData(frame3, <int>[255, 0, 0, 255]);
|
||||
|
||||
testCollector.collectNow();
|
||||
});
|
||||
|
||||
test('CkImage toString', () {
|
||||
final SkImage skImage =
|
||||
canvasKit.MakeAnimatedImageFromEncoded(kTransparentImage)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user