Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2ea7e52

Browse files
authored
isCloneOf for Image (#21371)
* isCloneOf for Image * Update docs, add missing impl
1 parent 68f347f commit 2ea7e52

File tree

6 files changed

+52
-0
lines changed

6 files changed

+52
-0
lines changed

lib/ui/painting.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,10 @@ class Image {
16711671
/// It is safe to pass an [Image] handle to another object or method if the
16721672
/// current holder no longer needs it.
16731673
///
1674+
/// To check whether two [Image] references are refering to the same
1675+
/// underlying image memory, use [isCloneOf] rather than the equality operator
1676+
/// or [identical].
1677+
///
16741678
/// The following example demonstrates valid usage.
16751679
///
16761680
/// ```dart
@@ -1740,6 +1744,17 @@ class Image {
17401744
return Image._(_image);
17411745
}
17421746

1747+
/// Returns true if `other` is a [clone] of this and thus shares the same
1748+
/// underlying image memory, even if this or `other` is [dispose]d.
1749+
///
1750+
/// This method may return false for two images that were decoded from the
1751+
/// same underlying asset, if they are not sharing the same memory. For
1752+
/// example, if the same file is decoded using [instantiateImageCodec] twice,
1753+
/// or the same bytes are decoded using [decodeImageFromPixels] twice, there
1754+
/// will be two distinct [Image]s that render the same but do not share
1755+
/// underlying memory, and so will not be treated as clones of each other.
1756+
bool isCloneOf(Image other) => other._image == _image;
1757+
17431758
@override
17441759
String toString() => _image.toString();
17451760
}

lib/web_ui/lib/src/engine/canvaskit/image.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ class CkAnimatedImage implements ui.Image {
5555
@override
5656
ui.Image clone() => this;
5757

58+
@override
59+
bool isCloneOf(ui.Image other) => other == this;
60+
5861
@override
5962
List<StackTrace>? debugGetOpenHandleStackTraces() => null;
6063
int get frameCount => _skAnimatedImage.getFrameCount();
@@ -125,6 +128,9 @@ class CkImage implements ui.Image {
125128
@override
126129
ui.Image clone() => this;
127130

131+
@override
132+
bool isCloneOf(ui.Image other) => other == this;
133+
128134
@override
129135
List<StackTrace>? debugGetOpenHandleStackTraces() => null;
130136

lib/web_ui/lib/src/engine/html_image_codec.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ class HtmlImage implements ui.Image {
125125
@override
126126
ui.Image clone() => this;
127127

128+
@override
129+
bool isCloneOf(ui.Image other) => other == this;
130+
128131
@override
129132
List<StackTrace>? debugGetOpenHandleStackTraces() => null;
130133

lib/web_ui/lib/src/ui/painting.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ abstract class Image {
332332

333333
Image clone() => this;
334334

335+
bool isCloneOf(Image other) => other == this;
336+
335337
List<StackTrace>? debugGetOpenHandleStackTraces() => null;
336338

337339
@override

lib/web_ui/test/golden_tests/engine/recording_canvas_golden_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,9 @@ class TestImage implements Image {
726726
@override
727727
Image clone() => this;
728728

729+
@override
730+
bool isCloneOf(Image other) => other == this;
731+
729732
@override
730733
List<StackTrace>/*?*/ debugGetOpenHandleStackTraces() => <StackTrace>[];
731734
}

testing/dart/image_dispose_test.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,29 @@ void main() {
9191
frame.image.dispose();
9292
expect(frame.image.debugGetOpenHandleStackTraces(), isEmpty);
9393
}, skip: !assertsEnabled);
94+
95+
test('Clones can be compared', () async {
96+
final Uint8List bytes = await readFile('2x2.png');
97+
final Codec codec = await instantiateImageCodec(bytes);
98+
final FrameInfo frame = await codec.getNextFrame();
99+
100+
final Image handle1 = frame.image.clone();
101+
final Image handle2 = handle1.clone();
102+
103+
expect(handle1.isCloneOf(handle2), true);
104+
expect(handle2.isCloneOf(handle1), true);
105+
expect(handle1.isCloneOf(frame.image), true);
106+
107+
handle1.dispose();
108+
expect(handle1.isCloneOf(handle2), true);
109+
expect(handle2.isCloneOf(handle1), true);
110+
expect(handle1.isCloneOf(frame.image), true);
111+
112+
final Codec codec2 = await instantiateImageCodec(bytes);
113+
final FrameInfo frame2 = await codec2.getNextFrame();
114+
115+
expect(frame2.image.isCloneOf(frame.image), false);
116+
});
94117
}
95118

96119
Future<Uint8List> readFile(String fileName) async {

0 commit comments

Comments
 (0)