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

Commit 8cb07c1

Browse files
committed
disallow double dispose; better assertion messages
1 parent cca7227 commit 8cb07c1

File tree

3 files changed

+28
-22
lines changed

3 files changed

+28
-22
lines changed

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ class CkAnimatedImage implements ui.Codec, StackTraceDebugger {
7070

7171
@override
7272
void dispose() {
73-
if (_disposed) {
74-
// This method is idempotent.
75-
return;
76-
}
73+
assert(
74+
!_disposed,
75+
'Cannot dispose a codec that has already been disposed.',
76+
);
7777
_disposed = true;
7878

7979
// This image is no longer usable. Bump the ref count.
@@ -141,9 +141,10 @@ class CkImage implements ui.Image, StackTraceDebugger {
141141

142142
@override
143143
void dispose() {
144-
if (_disposed) {
145-
return;
146-
}
144+
assert(
145+
!_disposed,
146+
'Cannot dispose an image that has already been disposed.',
147+
);
147148
_disposed = true;
148149
box.unref(this);
149150
}

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

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,9 @@ abstract class StackTraceDebugger {
273273
/// The [delete] method may be called any number of times. The box
274274
/// will only delete the object once.
275275
class SkiaObjectBox<R extends StackTraceDebugger, T> {
276-
SkiaObjectBox(R debugWrapper, this.skiaObject) : _skDeletable = skiaObject as SkDeletable {
276+
SkiaObjectBox(R debugReferrer, this.skiaObject) : _skDeletable = skiaObject as SkDeletable {
277277
if (assertionsEnabled) {
278-
debugReferrers.add(debugWrapper);
278+
debugReferrers.add(debugReferrer);
279279
}
280280
if (browserSupportsFinalizationRegistry) {
281281
boxRegistry.register(this, _skDeletable);
@@ -295,7 +295,7 @@ class SkiaObjectBox<R extends StackTraceDebugger, T> {
295295
/// The length of this list is always identical to [refCount].
296296
///
297297
/// This list can be used for debugging ref counting issues.
298-
final List<R> debugReferrers = <R>[];
298+
final Set<R> debugReferrers = <R>{};
299299

300300
/// If asserts are enabled, the [StackTrace]s representing when a reference
301301
/// was created.
@@ -329,13 +329,14 @@ class SkiaObjectBox<R extends StackTraceDebugger, T> {
329329
/// sharing ownership of the underlying [skiaObject].
330330
///
331331
/// Clones must be [dispose]d when finished.
332-
void ref(R debugWrapper) {
332+
void ref(R debugReferrer) {
333333
assert(!_isDeleted, 'Cannot increment ref count on a deleted handle.');
334334
assert(_refCount > 0);
335+
assert(
336+
debugReferrers.add(debugReferrer),
337+
'Attempted to increment ref count by the same referrer more than once.',
338+
);
335339
_refCount += 1;
336-
if (assertionsEnabled) {
337-
debugReferrers.add(debugWrapper);
338-
}
339340
assert(refCount == debugReferrers.length);
340341
}
341342

@@ -345,10 +346,13 @@ class SkiaObjectBox<R extends StackTraceDebugger, T> {
345346
///
346347
/// If this causes the reference count to drop to zero, deletes the
347348
/// [skObject].
348-
void unref(R debugWrapper) {
349+
void unref(R debugReferrer) {
349350
assert(!_isDeleted, 'Attempted to unref an already deleted Skia object.');
351+
assert(
352+
debugReferrers.remove(debugReferrer),
353+
'Attempted to decrement ref count by the same referrer more than once.',
354+
);
350355
_refCount -= 1;
351-
assert(debugReferrers.remove(debugWrapper));
352356
assert(refCount == debugReferrers.length);
353357
if (_refCount == 0) {
354358
_isDeleted = true;

lib/web_ui/test/canvaskit/image_test.dart

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:test/test.dart';
1010
import 'package:ui/src/engine.dart';
1111
import 'package:ui/ui.dart' as ui;
1212

13+
import '../matchers.dart';
1314
import 'common.dart';
1415
import 'test_data.dart';
1516

@@ -30,9 +31,9 @@ void testMain() {
3031
image.dispose();
3132
expect(image.box.isDeleted, true);
3233
expect(image.debugDisposed, true);
33-
image.dispose();
34-
expect(image.box.isDeleted, true);
35-
expect(image.debugDisposed, true);
34+
35+
// Disallow double-dispose.
36+
expect(() => image.dispose(), throwsAssertionError);
3637
});
3738

3839
test('CkAnimatedImage can be cloned and explicitly disposed of', () async {
@@ -68,9 +69,9 @@ void testMain() {
6869
image.dispose();
6970
expect(image.debugDisposed, true);
7071
expect(image.box.isDeleted, true);
71-
image.dispose();
72-
expect(image.debugDisposed, true);
73-
expect(image.box.isDeleted, true);
72+
73+
// Disallow double-dispose.
74+
expect(() => image.dispose(), throwsAssertionError);
7475
});
7576

7677
test('CkImage can be explicitly disposed of when cloned', () async {

0 commit comments

Comments
 (0)