From eb5cc0e3698dd6700e35f861b2390ca39b854b44 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 9 Aug 2022 11:01:34 -0700 Subject: [PATCH 01/43] Update painting.dart --- lib/ui/painting.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 8be9426168858..6c3afeb93d690 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1648,6 +1648,9 @@ class Image { _debugStack = StackTrace.current; return true; }()); + if (onCreate != null) { + onCreate!(); + } _image._handles.add(this); } @@ -1663,6 +1666,20 @@ class Image { /// The number of image pixels along the image's vertical axis. final int height; + /// A callback that is invoked to report an object creation. + /// + /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart + /// than to use [onCreate] directly because [MemoryAllocations] + /// allows multiple callbacks. + void Function()? onCreate; + + /// A callback that is invoked to report the object disposal. + /// + /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart + /// than to use [onDispose] directly because [MemoryAllocations] + /// allows multiple callbacks. + void Function()? onDispose; + bool _disposed = false; /// Release this handle's claim on the underlying Image. This handle is no /// longer usable after this method is called. From 401a169066f2a6a6a73810eb70a0815d5c06f676 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 9 Aug 2022 11:16:54 -0700 Subject: [PATCH 02/43] Update painting.dart --- lib/ui/painting.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 6c3afeb93d690..c92bc7148ac9c 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1648,10 +1648,10 @@ class Image { _debugStack = StackTrace.current; return true; }()); + _image._handles.add(this); if (onCreate != null) { - onCreate!(); + onCreate!(this); } - _image._handles.add(this); } // C++ unit tests access this. @@ -1671,14 +1671,14 @@ class Image { /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onCreate] directly because [MemoryAllocations] /// allows multiple callbacks. - void Function()? onCreate; + static void Function(Object)? onCreate; /// A callback that is invoked to report the object disposal. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onDispose] directly because [MemoryAllocations] /// allows multiple callbacks. - void Function()? onDispose; + static void Function(Object)? onDispose; bool _disposed = false; /// Release this handle's claim on the underlying Image. This handle is no @@ -1692,6 +1692,9 @@ class Image { /// useful when trying to determine what parts of the program are keeping an /// image resident in memory. void dispose() { + if (onDispose != null) { + onDispose!(this); + } assert(!_disposed && !_image._disposed); assert(_image._handles.contains(this)); _disposed = true; From d6df6b8cdffbfe37db07ec4c48967e96fb4459ec Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 08:48:07 -0700 Subject: [PATCH 03/43] - --- lib/ui/painting.dart | 24 ++++++++++-------------- lib/web_ui/lib/painting.dart | 9 ++++++++- lib/web_ui/lib/src/engine/embedder.dart | 4 +--- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index c92bc7148ac9c..eec74cb76f807 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1649,23 +1649,13 @@ class Image { return true; }()); _image._handles.add(this); - if (onCreate != null) { - onCreate!(this); - } + onCreate?.call(this); } // C++ unit tests access this. @pragma('vm:entry-point') final _Image _image; - StackTrace? _debugStack; - - /// The number of image pixels along the image's horizontal axis. - final int width; - - /// The number of image pixels along the image's vertical axis. - final int height; - /// A callback that is invoked to report an object creation. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart @@ -1680,6 +1670,14 @@ class Image { /// allows multiple callbacks. static void Function(Object)? onDispose; + StackTrace? _debugStack; + + /// The number of image pixels along the image's horizontal axis. + final int width; + + /// The number of image pixels along the image's vertical axis. + final int height; + bool _disposed = false; /// Release this handle's claim on the underlying Image. This handle is no /// longer usable after this method is called. @@ -1692,9 +1690,7 @@ class Image { /// useful when trying to determine what parts of the program are keeping an /// image resident in memory. void dispose() { - if (onDispose != null) { - onDispose!(this); - } + onDispose?.call(this); assert(!_disposed && !_image._disposed); assert(_image._handles.contains(this)); _disposed = true; diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 40bc7fb65e31c..b2952d1a2f251 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -332,10 +332,17 @@ abstract class Gradient extends Shader { } abstract class Image { + Image() { + onCreate?.call(this); + } + + static void Function(Object)? onCreate; + static void Function(Object)? onDispose; + int get width; int get height; Future toByteData({ImageByteFormat format = ImageByteFormat.rawRgba}); - void dispose(); + void dispose() => onDispose?.call(this); bool get debugDisposed; Image clone() => this; diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart index ef6107e3a6023..3556ad77feb38 100644 --- a/lib/web_ui/lib/src/engine/embedder.dart +++ b/lib/web_ui/lib/src/engine/embedder.dart @@ -419,9 +419,7 @@ class FlutterViewEmbedder { /// Called immediately after browser window language change. void _languageDidChange(DomEvent event) { EnginePlatformDispatcher.instance.updateLocales(); - if (ui.window.onLocaleChanged != null) { - ui.window.onLocaleChanged!(); - } + ui.window.onLocaleChanged?.call(); } static const String orientationLockTypeAny = 'any'; From eaf2ec894b801bc38d41216468cc3dcbb8a86434 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 15:01:05 -0700 Subject: [PATCH 04/43] - --- testing/dart/image_dispose_test.dart | 44 ++++++++-- testing/dart/image_test.dart | 117 +++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 testing/dart/image_test.dart diff --git a/testing/dart/image_dispose_test.dart b/testing/dart/image_dispose_test.dart index fe0d11fda832a..9a98cc643b5a4 100644 --- a/testing/dart/image_dispose_test.dart +++ b/testing/dart/image_dispose_test.dart @@ -16,8 +16,13 @@ void main() { return true; }()); + tearDown((){ + Image.onDispose = null; + Image.onCreate = null; + }); + test('Handles are distinct', () async { - final Uint8List bytes = await readFile('2x2.png'); + final Uint8List bytes = await _readFile('2x2.png'); final Codec codec = await instantiateImageCodec(bytes); final FrameInfo frame = await codec.getNextFrame(); @@ -36,7 +41,7 @@ void main() { }); test('Canvas can paint image from handle and byte data from handle', () async { - final Uint8List bytes = await readFile('2x2.png'); + final Uint8List bytes = await _readFile('2x2.png'); final Codec codec = await instantiateImageCodec(bytes); final FrameInfo frame = await codec.getNextFrame(); @@ -66,7 +71,7 @@ void main() { }); test('Records stack traces', () async { - final Uint8List bytes = await readFile('2x2.png'); + final Uint8List bytes = await _readFile('2x2.png'); final Codec codec = await instantiateImageCodec(bytes); final FrameInfo frame = await codec.getNextFrame(); @@ -92,7 +97,7 @@ void main() { }, skip: !assertsEnabled); test('Clones can be compared', () async { - final Uint8List bytes = await readFile('2x2.png'); + final Uint8List bytes = await _readFile('2x2.png'); final Codec codec = await instantiateImageCodec(bytes); final FrameInfo frame = await codec.getNextFrame(); @@ -115,7 +120,7 @@ void main() { }); test('debugDisposed works', () async { - final Uint8List bytes = await readFile('2x2.png'); + final Uint8List bytes = await _readFile('2x2.png'); final Codec codec = await instantiateImageCodec(bytes); final FrameInfo frame = await codec.getNextFrame(); @@ -132,9 +137,36 @@ void main() { expect(() => frame.image.debugDisposed, throwsStateError); } }); + + test('dispose() invokes onDispose once', () async { + int onDisposeInvokedCount = 0; + int instanceHashCode = 0; + Image.onDispose = (obj) { + onDisposeInvokedCount++; + instanceHashCode = identityHashCode(obj); + }; + + final image1 = _createPicture().toImage()..dispose(); + + expect(onDisposeInvokedCount, 1); + expect(instanceHashCode, identityHashCode(image1)); + + final image2 = _createPicture().toImage()..dispose(); + + expect(onDisposeInvokedCount, 2); + expect(instanceHashCode, identityHashCode(image2)); + } +} + +Picture _createPicture() { + final recorder = PictureRecorder(); + final canvas = Canvas(recorder); + var rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); + canvas.clipRect(rect); + return recorder.endRecording(); } -Future readFile(String fileName) async { +Future _readFile(String fileName) async { final File file = File(path.join( 'flutter', 'testing', diff --git a/testing/dart/image_test.dart b/testing/dart/image_test.dart new file mode 100644 index 0000000000000..529886c41344f --- /dev/null +++ b/testing/dart/image_test.dart @@ -0,0 +1,117 @@ +// 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. + +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:litetest/litetest.dart'; +import 'package:path/path.dart' as path; + +void main() { + tearDown((){ + Image.onDispose = null; + Image.onCreate = null; + }); + + test('basic image descriptor - encoded - greyscale', () async { + final Uint8List bytes = await readFile('2x2.png'); + final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); + final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer); + + expect(descriptor.width, 2); + expect(descriptor.height, 2); + expect(descriptor.bytesPerPixel, 1); + + final Codec codec = await descriptor.instantiateCodec(); + expect(codec.frameCount, 1); + }); + + test('basic image descriptor - encoded - square', () async { + final Uint8List bytes = await readFile('square.png'); + final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); + final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer); + + expect(descriptor.width, 10); + expect(descriptor.height, 10); + expect(descriptor.bytesPerPixel, 4); + + final Codec codec = await descriptor.instantiateCodec(); + expect(codec.frameCount, 1); + }); + + test('basic image descriptor - encoded - animated', () async { + final Uint8List bytes = await _getSkiaResource('test640x479.gif').readAsBytes(); + final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); + final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer); + + expect(descriptor.width, 640); + expect(descriptor.height, 479); + expect(descriptor.bytesPerPixel, 4); + + final Codec codec = await descriptor.instantiateCodec(); + expect(codec.frameCount, 4); + expect(codec.repetitionCount, -1); + }); + + test('basic image descriptor - raw', () async { + final Uint8List bytes = Uint8List.fromList(List.filled(16, 0xFFABCDEF)); + final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); + final ImageDescriptor descriptor = ImageDescriptor.raw( + buffer, + width: 4, + height: 4, + rowBytes: 4 * 4, + pixelFormat: PixelFormat.rgba8888, + ); + + expect(descriptor.width, 4); + expect(descriptor.height, 4); + expect(descriptor.bytesPerPixel, 4); + + final Codec codec = await descriptor.instantiateCodec(); + expect(codec.frameCount, 1); + }); + + test('HEIC image', () async { + final Uint8List bytes = await readFile('grill_chicken.heic'); + final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); + final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer); + + expect(descriptor.width, 300); + expect(descriptor.height, 400); + expect(descriptor.bytesPerPixel, 4); + + final Codec codec = await descriptor.instantiateCodec(); + expect(codec.frameCount, 1); + }, skip: !(Platform.isAndroid || Platform.isIOS || Platform.isMacOS || Platform.isWindows)); + + test('Image constructor invokes onCreate once', () async { + int onCreateInvokedCount = 0; + int instanceHashCode = 0; + Image.onCreate = (obj) { + onCreateInvokedCount++; + instanceHashCode = identityHashCode(obj); + }; + + final image1 = _createPicture().toImage(); + + expect(onCreateInvokedCount, 1); + expect(instanceHashCode, identityHashCode(image1)); + + final image2 = _createPicture().toImage(); + + expect(onCreateInvokedCount, 2); + expect(instanceHashCode, identityHashCode(image2)); + } +} + +Picture _createPicture() { + final recorder = PictureRecorder(); + final canvas = Canvas(recorder); + var rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); + canvas.clipRect(rect); + return recorder.endRecording(); +} From 3e17cd17cada6ef1121f3b4db0bfc9614c9331ee Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 16:09:16 -0700 Subject: [PATCH 05/43] Update image_test.dart --- testing/dart/image_test.dart | 72 ------------------------------------ 1 file changed, 72 deletions(-) diff --git a/testing/dart/image_test.dart b/testing/dart/image_test.dart index 529886c41344f..122dde6b9281c 100644 --- a/testing/dart/image_test.dart +++ b/testing/dart/image_test.dart @@ -16,78 +16,6 @@ void main() { Image.onCreate = null; }); - test('basic image descriptor - encoded - greyscale', () async { - final Uint8List bytes = await readFile('2x2.png'); - final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); - final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer); - - expect(descriptor.width, 2); - expect(descriptor.height, 2); - expect(descriptor.bytesPerPixel, 1); - - final Codec codec = await descriptor.instantiateCodec(); - expect(codec.frameCount, 1); - }); - - test('basic image descriptor - encoded - square', () async { - final Uint8List bytes = await readFile('square.png'); - final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); - final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer); - - expect(descriptor.width, 10); - expect(descriptor.height, 10); - expect(descriptor.bytesPerPixel, 4); - - final Codec codec = await descriptor.instantiateCodec(); - expect(codec.frameCount, 1); - }); - - test('basic image descriptor - encoded - animated', () async { - final Uint8List bytes = await _getSkiaResource('test640x479.gif').readAsBytes(); - final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); - final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer); - - expect(descriptor.width, 640); - expect(descriptor.height, 479); - expect(descriptor.bytesPerPixel, 4); - - final Codec codec = await descriptor.instantiateCodec(); - expect(codec.frameCount, 4); - expect(codec.repetitionCount, -1); - }); - - test('basic image descriptor - raw', () async { - final Uint8List bytes = Uint8List.fromList(List.filled(16, 0xFFABCDEF)); - final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); - final ImageDescriptor descriptor = ImageDescriptor.raw( - buffer, - width: 4, - height: 4, - rowBytes: 4 * 4, - pixelFormat: PixelFormat.rgba8888, - ); - - expect(descriptor.width, 4); - expect(descriptor.height, 4); - expect(descriptor.bytesPerPixel, 4); - - final Codec codec = await descriptor.instantiateCodec(); - expect(codec.frameCount, 1); - }); - - test('HEIC image', () async { - final Uint8List bytes = await readFile('grill_chicken.heic'); - final ImmutableBuffer buffer = await ImmutableBuffer.fromUint8List(bytes); - final ImageDescriptor descriptor = await ImageDescriptor.encoded(buffer); - - expect(descriptor.width, 300); - expect(descriptor.height, 400); - expect(descriptor.bytesPerPixel, 4); - - final Codec codec = await descriptor.instantiateCodec(); - expect(codec.frameCount, 1); - }, skip: !(Platform.isAndroid || Platform.isIOS || Platform.isMacOS || Platform.isWindows)); - test('Image constructor invokes onCreate once', () async { int onCreateInvokedCount = 0; int instanceHashCode = 0; From b47c31efc94070912e16d10ee7f095d888be8832 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 16:20:15 -0700 Subject: [PATCH 06/43] - --- lib/ui/painting.dart | 19 ++++++++++++++++++- lib/web_ui/lib/canvas.dart | 5 ++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index eec74cb76f807..58c81aa431f82 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5602,7 +5602,23 @@ class Picture extends NativeFieldWrapperClass1 { /// /// To create a [Picture], use a [PictureRecorder]. @pragma('vm:entry-point') - Picture._(); + Picture._() { + onCreate?.call(this); + } + + /// A callback that is invoked to report an object creation. + /// + /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart + /// than to use [onCreate] directly because [MemoryAllocations] + /// allows multiple callbacks. + static void Function(Object)? onCreate; + + /// A callback that is invoked to report the object disposal. + /// + /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart + /// than to use [onDispose] directly because [MemoryAllocations] + /// allows multiple callbacks. + static void Function(Object)? onDispose; /// Creates an image from this picture. /// @@ -5667,6 +5683,7 @@ class Picture extends NativeFieldWrapperClass1 { _disposed = true; return true; }()); + onDispose?.call(this); _dispose(); } diff --git a/lib/web_ui/lib/canvas.dart b/lib/web_ui/lib/canvas.dart index c9359b6930781..796300d03a5ea 100644 --- a/lib/web_ui/lib/canvas.dart +++ b/lib/web_ui/lib/canvas.dart @@ -154,9 +154,12 @@ abstract class Canvas { } abstract class Picture { + Picture() { onCreate?.call(this); } + static void Function(Object)? onCreate; + static void Function(Object)? onDispose; Future toImage(int width, int height); Image toImageSync(int width, int height); - void dispose(); + void dispose() { onDispose?.call(this); } bool get debugDisposed; int get approximateBytesUsed; } From 427592e26e5a4cf6132f30240e1856422a9ced6a Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 16:23:55 -0700 Subject: [PATCH 07/43] Update painting.dart --- lib/ui/painting.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 58c81aa431f82..55a855f346a5a 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5602,9 +5602,7 @@ class Picture extends NativeFieldWrapperClass1 { /// /// To create a [Picture], use a [PictureRecorder]. @pragma('vm:entry-point') - Picture._() { - onCreate?.call(this); - } + Picture._() { onCreate?.call(this); } /// A callback that is invoked to report an object creation. /// From 1434af975104c65130521c7226520a80170ac16e Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 21:26:04 -0700 Subject: [PATCH 08/43] Update painting.dart --- lib/ui/painting.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 512bb254bb7e8..ea2c0adef37a6 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1658,14 +1658,14 @@ class Image { /// A callback that is invoked to report an object creation. /// - /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart + /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onCreate] directly because [MemoryAllocations] /// allows multiple callbacks. static void Function(Object)? onCreate; /// A callback that is invoked to report the object disposal. /// - /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart + /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onDispose] directly because [MemoryAllocations] /// allows multiple callbacks. static void Function(Object)? onDispose; @@ -5611,14 +5611,14 @@ class Picture extends NativeFieldWrapperClass1 { /// A callback that is invoked to report an object creation. /// - /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart + /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onCreate] directly because [MemoryAllocations] /// allows multiple callbacks. static void Function(Object)? onCreate; /// A callback that is invoked to report the object disposal. /// - /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart + /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onDispose] directly because [MemoryAllocations] /// allows multiple callbacks. static void Function(Object)? onDispose; From 60a95a010517e0e82a921538c11518a3ea99d7b4 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 21:35:49 -0700 Subject: [PATCH 09/43] Update image_test.dart --- testing/dart/image_test.dart | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/testing/dart/image_test.dart b/testing/dart/image_test.dart index 122dde6b9281c..eb0c9e9898b5a 100644 --- a/testing/dart/image_test.dart +++ b/testing/dart/image_test.dart @@ -3,43 +3,36 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:io'; -import 'dart:typed_data'; import 'dart:ui'; import 'package:litetest/litetest.dart'; -import 'package:path/path.dart' as path; void main() { - tearDown((){ - Image.onDispose = null; - Image.onCreate = null; - }); - test('Image constructor invokes onCreate once', () async { int onCreateInvokedCount = 0; int instanceHashCode = 0; - Image.onCreate = (obj) { - onCreateInvokedCount++; + Image.onCreate = (Object obj) { + onCreateInvokedCount++; instanceHashCode = identityHashCode(obj); }; - final image1 = _createPicture().toImage(); + final Future image1 = _createPicture().toImage(10, 10); expect(onCreateInvokedCount, 1); expect(instanceHashCode, identityHashCode(image1)); - final image2 = _createPicture().toImage(); + final Future image2 = _createPicture().toImage(10, 10); expect(onCreateInvokedCount, 2); expect(instanceHashCode, identityHashCode(image2)); - } + Image.onCreate = null; + }); } Picture _createPicture() { - final recorder = PictureRecorder(); - final canvas = Canvas(recorder); - var rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); canvas.clipRect(rect); return recorder.endRecording(); } From e2a1f76f43f76a4f90fb44680310d3c0c4300156 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 21:43:40 -0700 Subject: [PATCH 10/43] - --- lib/web_ui/lib/src/engine/embedder.dart | 2 +- testing/dart/image_dispose_test.dart | 23 +++++++++++------------ testing/dart/image_test.dart | 6 ++++-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart index 3556ad77feb38..25f334bea491b 100644 --- a/lib/web_ui/lib/src/engine/embedder.dart +++ b/lib/web_ui/lib/src/engine/embedder.dart @@ -419,7 +419,7 @@ class FlutterViewEmbedder { /// Called immediately after browser window language change. void _languageDidChange(DomEvent event) { EnginePlatformDispatcher.instance.updateLocales(); - ui.window.onLocaleChanged?.call(); + ui.window.onLocaleChanged?.call(); } static const String orientationLockTypeAny = 'any'; diff --git a/testing/dart/image_dispose_test.dart b/testing/dart/image_dispose_test.dart index 9a98cc643b5a4..ab3b8d22bcb57 100644 --- a/testing/dart/image_dispose_test.dart +++ b/testing/dart/image_dispose_test.dart @@ -16,11 +16,6 @@ void main() { return true; }()); - tearDown((){ - Image.onDispose = null; - Image.onCreate = null; - }); - test('Handles are distinct', () async { final Uint8List bytes = await _readFile('2x2.png'); final Codec codec = await instantiateImageCodec(bytes); @@ -141,27 +136,31 @@ void main() { test('dispose() invokes onDispose once', () async { int onDisposeInvokedCount = 0; int instanceHashCode = 0; - Image.onDispose = (obj) { + Image.onDispose = (Object obj) { onDisposeInvokedCount++; instanceHashCode = identityHashCode(obj); }; - final image1 = _createPicture().toImage()..dispose(); + final Image image1 = await _createImage()..dispose(); expect(onDisposeInvokedCount, 1); expect(instanceHashCode, identityHashCode(image1)); - final image2 = _createPicture().toImage()..dispose(); + final Image image2 = await _createImage()..dispose(); expect(onDisposeInvokedCount, 2); expect(instanceHashCode, identityHashCode(image2)); - } + + Image.onDispose = null; + }); } +Future _createImage() async => _createPicture().toImage(10, 10); + Picture _createPicture() { - final recorder = PictureRecorder(); - final canvas = Canvas(recorder); - var rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); canvas.clipRect(rect); return recorder.endRecording(); } diff --git a/testing/dart/image_test.dart b/testing/dart/image_test.dart index eb0c9e9898b5a..51afddf5c3f04 100644 --- a/testing/dart/image_test.dart +++ b/testing/dart/image_test.dart @@ -16,12 +16,12 @@ void main() { instanceHashCode = identityHashCode(obj); }; - final Future image1 = _createPicture().toImage(10, 10); + final Image image1 = await _createImage(); expect(onCreateInvokedCount, 1); expect(instanceHashCode, identityHashCode(image1)); - final Future image2 = _createPicture().toImage(10, 10); + final Image image2 = await _createImage(); expect(onCreateInvokedCount, 2); expect(instanceHashCode, identityHashCode(image2)); @@ -29,6 +29,8 @@ void main() { }); } +Future _createImage() async => _createPicture().toImage(10, 10); + Picture _createPicture() { final PictureRecorder recorder = PictureRecorder(); final Canvas canvas = Canvas(recorder); From ca996358736ffc1e77d1d9f4d2a88700a8d4d470 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 21:46:23 -0700 Subject: [PATCH 11/43] Update image_dispose_test.dart --- testing/dart/image_dispose_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/dart/image_dispose_test.dart b/testing/dart/image_dispose_test.dart index ab3b8d22bcb57..642512e8e859f 100644 --- a/testing/dart/image_dispose_test.dart +++ b/testing/dart/image_dispose_test.dart @@ -137,7 +137,7 @@ void main() { int onDisposeInvokedCount = 0; int instanceHashCode = 0; Image.onDispose = (Object obj) { - onDisposeInvokedCount++; + onDisposeInvokedCount++; instanceHashCode = identityHashCode(obj); }; @@ -147,7 +147,7 @@ void main() { expect(instanceHashCode, identityHashCode(image1)); final Image image2 = await _createImage()..dispose(); - + expect(onDisposeInvokedCount, 2); expect(instanceHashCode, identityHashCode(image2)); From 1f85ecf017222fe51b7ed243d3fd890510713279 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 10 Aug 2022 21:48:10 -0700 Subject: [PATCH 12/43] Update image_test.dart --- testing/dart/image_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/dart/image_test.dart b/testing/dart/image_test.dart index 51afddf5c3f04..c144ce1375b5b 100644 --- a/testing/dart/image_test.dart +++ b/testing/dart/image_test.dart @@ -22,7 +22,7 @@ void main() { expect(instanceHashCode, identityHashCode(image1)); final Image image2 = await _createImage(); - + expect(onCreateInvokedCount, 2); expect(instanceHashCode, identityHashCode(image2)); Image.onCreate = null; From b5771074de99c12fe76df8bf3257117e6a7ca150 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 11 Aug 2022 09:10:18 -0700 Subject: [PATCH 13/43] - --- lib/ui/painting.dart | 8 ++-- lib/web_ui/lib/canvas.dart | 4 +- lib/web_ui/lib/painting.dart | 4 +- testing/dart/BUILD.gn | 2 + testing/dart/image_dispose_test.dart | 10 ++--- testing/dart/image_test.dart | 10 ++--- testing/dart/picture_test.dart | 58 ++++++++++++++++++++++++++++ 7 files changed, 78 insertions(+), 18 deletions(-) create mode 100644 testing/dart/picture_test.dart diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index ea2c0adef37a6..2c27361c64b90 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1661,14 +1661,14 @@ class Image { /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onCreate] directly because [MemoryAllocations] /// allows multiple callbacks. - static void Function(Object)? onCreate; + static void Function(Image)? onCreate; /// A callback that is invoked to report the object disposal. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onDispose] directly because [MemoryAllocations] /// allows multiple callbacks. - static void Function(Object)? onDispose; + static void Function(Image)? onDispose; StackTrace? _debugStack; @@ -5614,14 +5614,14 @@ class Picture extends NativeFieldWrapperClass1 { /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onCreate] directly because [MemoryAllocations] /// allows multiple callbacks. - static void Function(Object)? onCreate; + static void Function(Picture)? onCreate; /// A callback that is invoked to report the object disposal. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onDispose] directly because [MemoryAllocations] /// allows multiple callbacks. - static void Function(Object)? onDispose; + static void Function(Picture)? onDispose; /// Creates an image from this picture. /// diff --git a/lib/web_ui/lib/canvas.dart b/lib/web_ui/lib/canvas.dart index 796300d03a5ea..e0788aeb33cbd 100644 --- a/lib/web_ui/lib/canvas.dart +++ b/lib/web_ui/lib/canvas.dart @@ -155,8 +155,8 @@ abstract class Canvas { abstract class Picture { Picture() { onCreate?.call(this); } - static void Function(Object)? onCreate; - static void Function(Object)? onDispose; + static void Function(Picture)? onCreate; + static void Function(Picture)? onDispose; Future toImage(int width, int height); Image toImageSync(int width, int height); void dispose() { onDispose?.call(this); } diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index b2952d1a2f251..7946c3d726a63 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -336,8 +336,8 @@ abstract class Image { onCreate?.call(this); } - static void Function(Object)? onCreate; - static void Function(Object)? onDispose; + static void Function(Image)? onCreate; + static void Function(Image)? onDispose; int get width; int get height; diff --git a/testing/dart/BUILD.gn b/testing/dart/BUILD.gn index 4321cd37f55ae..38586f6e0e4d8 100644 --- a/testing/dart/BUILD.gn +++ b/testing/dart/BUILD.gn @@ -20,6 +20,7 @@ tests = [ "gradient_test.dart", "http_allow_http_connections_test.dart", "http_disallow_http_connections_test.dart", + "image_test.dart", "image_descriptor_test.dart", "image_dispose_test.dart", "image_filter_test.dart", @@ -33,6 +34,7 @@ tests = [ "paragraph_builder_test.dart", "paragraph_test.dart", "path_test.dart", + "picture_test.dart", "platform_view_test.dart", "plugin_utilities_test.dart", "semantics_test.dart", diff --git a/testing/dart/image_dispose_test.dart b/testing/dart/image_dispose_test.dart index 642512e8e859f..3f5087930993d 100644 --- a/testing/dart/image_dispose_test.dart +++ b/testing/dart/image_dispose_test.dart @@ -135,21 +135,21 @@ void main() { test('dispose() invokes onDispose once', () async { int onDisposeInvokedCount = 0; - int instanceHashCode = 0; - Image.onDispose = (Object obj) { + Image? disposedImage; + Image.onDispose = (Image image) { onDisposeInvokedCount++; - instanceHashCode = identityHashCode(obj); + disposedImage = image; }; final Image image1 = await _createImage()..dispose(); expect(onDisposeInvokedCount, 1); - expect(instanceHashCode, identityHashCode(image1)); + expect(disposedImage, image1); final Image image2 = await _createImage()..dispose(); expect(onDisposeInvokedCount, 2); - expect(instanceHashCode, identityHashCode(image2)); + expect(disposedImage, image2); Image.onDispose = null; }); diff --git a/testing/dart/image_test.dart b/testing/dart/image_test.dart index c144ce1375b5b..ff2778dbdb69d 100644 --- a/testing/dart/image_test.dart +++ b/testing/dart/image_test.dart @@ -10,21 +10,21 @@ import 'package:litetest/litetest.dart'; void main() { test('Image constructor invokes onCreate once', () async { int onCreateInvokedCount = 0; - int instanceHashCode = 0; - Image.onCreate = (Object obj) { + Image? createdImage; + Image.onCreate = (Image image) { onCreateInvokedCount++; - instanceHashCode = identityHashCode(obj); + createdImage = image; }; final Image image1 = await _createImage(); expect(onCreateInvokedCount, 1); - expect(instanceHashCode, identityHashCode(image1)); + expect(createdImage, image1); final Image image2 = await _createImage(); expect(onCreateInvokedCount, 2); - expect(instanceHashCode, identityHashCode(image2)); + expect(createdImage, image2); Image.onCreate = null; }); } diff --git a/testing/dart/picture_test.dart b/testing/dart/picture_test.dart new file mode 100644 index 0000000000000..256e204e996b6 --- /dev/null +++ b/testing/dart/picture_test.dart @@ -0,0 +1,58 @@ +// 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. + +import 'dart:ui'; + +import 'package:litetest/litetest.dart'; + +void main() { + test('Picture constructor invokes onCreate once', () async { + int onCreateInvokedCount = 0; + Picture? createdPicture; + Picture.onCreate = (Picture picture) { + onCreateInvokedCount++; + createdPicture = picture; + }; + + final Picture picture1 = _createPicture(); + + expect(onCreateInvokedCount, 1); + expect(createdPicture, picture1); + + final Picture picture2 = _createPicture(); + + expect(onCreateInvokedCount, 2); + expect(createdPicture, picture2); + Picture.onCreate = null; + }); + + test('dispose() invokes onDispose once', () async { + int onDisposeInvokedCount = 0; + Picture? disposedPicture; + Picture.onDispose = (Picture picture) { + onDisposeInvokedCount++; + disposedPicture = picture; + }; + + final Picture picture1 = _createPicture()..dispose(); + + expect(onDisposeInvokedCount, 1); + expect(disposedPicture, identityHashCode(picture1)); + + final Picture picture2 = _createPicture()..dispose(); + + expect(onDisposeInvokedCount, 2); + expect(disposedPicture, identityHashCode(picture2)); + + Picture.onDispose = null; + }); +} + +Picture _createPicture() { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); + canvas.clipRect(rect); + return recorder.endRecording(); +} From 1e902a10c3cac3ab60c768e92ea6b30ed225ec04 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 11 Aug 2022 09:42:48 -0700 Subject: [PATCH 14/43] Update picture_test.dart --- testing/dart/picture_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/dart/picture_test.dart b/testing/dart/picture_test.dart index 256e204e996b6..badd3da3a39d8 100644 --- a/testing/dart/picture_test.dart +++ b/testing/dart/picture_test.dart @@ -38,12 +38,12 @@ void main() { final Picture picture1 = _createPicture()..dispose(); expect(onDisposeInvokedCount, 1); - expect(disposedPicture, identityHashCode(picture1)); + expect(disposedPicture, picture1); final Picture picture2 = _createPicture()..dispose(); expect(onDisposeInvokedCount, 2); - expect(disposedPicture, identityHashCode(picture2)); + expect(disposedPicture, picture2); Picture.onDispose = null; }); From b6ff393d4bccaf7c32270412ae350c0fe33f93a9 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 11 Aug 2022 14:38:47 -0700 Subject: [PATCH 15/43] - --- lib/web_ui/lib/painting.dart | 6 +- .../lib/src/engine/canvaskit/image.dart | 12 ++-- .../lib/src/engine/html_image_codec.dart | 5 +- lib/web_ui/test/engine/image/image_test.dart | 60 +++++++++++++++++++ lib/web_ui/test/engine/picture_test.dart | 57 ++++++++++++++++++ testing/dart/picture_test.dart | 2 +- 6 files changed, 131 insertions(+), 11 deletions(-) create mode 100644 lib/web_ui/test/engine/image/image_test.dart create mode 100644 lib/web_ui/test/engine/picture_test.dart diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 7946c3d726a63..ba242d8169405 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -332,17 +332,13 @@ abstract class Gradient extends Shader { } abstract class Image { - Image() { - onCreate?.call(this); - } - static void Function(Image)? onCreate; static void Function(Image)? onDispose; int get width; int get height; Future toByteData({ImageByteFormat format = ImageByteFormat.rawRgba}); - void dispose() => onDispose?.call(this); + void dispose(); bool get debugDisposed; Image clone() => this; diff --git a/lib/web_ui/lib/src/engine/canvaskit/image.dart b/lib/web_ui/lib/src/engine/canvaskit/image.dart index 921d5fe024f48..e7bf0b68dbf2d 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -149,9 +149,7 @@ Future fetchImage( /// A [ui.Image] backed by an `SkImage` from Skia. class CkImage implements ui.Image, StackTraceDebugger { CkImage(SkImage skImage, { this.videoFrame }) { - if (assertionsEnabled) { - _debugStackTrace = StackTrace.current; - } + _init(); if (browserSupportsFinalizationRegistry) { box = SkiaObjectBox(this, skImage); } else { @@ -200,10 +198,15 @@ class CkImage implements ui.Image, StackTraceDebugger { } CkImage.cloneOf(this.box) { + _init(); + box.ref(this); + } + + void _init() { if (assertionsEnabled) { _debugStackTrace = StackTrace.current; } - box.ref(this); + ui.Image.onCreate?.call(this); } @override @@ -237,6 +240,7 @@ class CkImage implements ui.Image, StackTraceDebugger { @override void dispose() { + ui.Image.onDispose?.call(this); assert( !_disposed, 'Cannot dispose an image that has already been disposed.', diff --git a/lib/web_ui/lib/src/engine/html_image_codec.dart b/lib/web_ui/lib/src/engine/html_image_codec.dart index 0011196fafac5..dfb3c3657d46c 100644 --- a/lib/web_ui/lib/src/engine/html_image_codec.dart +++ b/lib/web_ui/lib/src/engine/html_image_codec.dart @@ -140,7 +140,9 @@ class SingleFrameInfo implements ui.FrameInfo { } class HtmlImage implements ui.Image { - HtmlImage(this.imgElement, this.width, this.height); + HtmlImage(this.imgElement, this.width, this.height) { + ui.Image.onCreate?.call(this); + } final DomHTMLImageElement imgElement; bool _requiresClone = false; @@ -148,6 +150,7 @@ class HtmlImage implements ui.Image { bool _disposed = false; @override void dispose() { + ui.Image.onDispose?.call(this); // Do nothing. The codec that owns this image should take care of // releasing the object url. if (assertionsEnabled) { diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart new file mode 100644 index 0000000000000..66acd9622e241 --- /dev/null +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -0,0 +1,60 @@ +// Copyright 2022 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. + +import 'package:test/test.dart'; +import 'package:ui/ui.dart'; + +void main() { + test('Image constructor invokes onCreate once', () async { + int onCreateInvokedCount = 0; + Image? createdImage; + Image.onCreate = (Image image) { + onCreateInvokedCount++; + createdImage = image; + }; + + final Image image1 = await _createImage(); + + expect(onCreateInvokedCount, 1); + expect(createdImage, image1); + + final Image image2 = await _createImage(); + + expect(onCreateInvokedCount, 2); + expect(createdImage, image2); + Image.onCreate = null; + }); + + test('dispose() invokes onDispose once', () async { + int onDisposeInvokedCount = 0; + Image? disposedImage; + Image.onDispose = (Image image) { + onDisposeInvokedCount++; + disposedImage = image; + }; + + final Image image1 = await _createImage()..dispose(); + + expect(onDisposeInvokedCount, 1); + expect(disposedImage, image1); + + final Image image2 = await _createImage()..dispose(); + + expect(onDisposeInvokedCount, 2); + expect(disposedImage, image2); + + Image.onDispose = null; + }); +} + + +Future _createImage() async => _createPicture().toImage(10, 10); + +Picture _createPicture() { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); + canvas.clipRect(rect); + return recorder.endRecording(); +} \ No newline at end of file diff --git a/lib/web_ui/test/engine/picture_test.dart b/lib/web_ui/test/engine/picture_test.dart new file mode 100644 index 0000000000000..cf841c6e4aea1 --- /dev/null +++ b/lib/web_ui/test/engine/picture_test.dart @@ -0,0 +1,57 @@ +// Copyright 2022 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. + +import 'package:test/test.dart'; +import 'package:ui/ui.dart'; + +void main() { + test('Picture constructor invokes onCreate once', () async { + int onCreateInvokedCount = 0; + Picture? createdPicture; + Picture.onCreate = (Picture picture) { + onCreateInvokedCount++; + createdPicture = picture; + }; + + final Picture picture1 = _createPicture(); + + expect(onCreateInvokedCount, 1); + expect(createdPicture, picture1); + + final Picture picture2 = _createPicture(); + + expect(onCreateInvokedCount, 2); + expect(createdPicture, picture2); + Picture.onCreate = null; + }); + + test('dispose() invokes onDispose once', () async { + int onDisposeInvokedCount = 0; + Picture? disposedPicture; + Picture.onDispose = (Picture picture) { + onDisposeInvokedCount++; + disposedPicture = picture; + }; + + final Picture picture1 = _createPicture()..dispose(); + + expect(onDisposeInvokedCount, 1); + expect(disposedPicture, picture1); + + final Picture picture2 = _createPicture()..dispose(); + + expect(onDisposeInvokedCount, 2); + expect(disposedPicture, picture2); + + Picture.onDispose = null; + }); +} + +Picture _createPicture() { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); + canvas.clipRect(rect); + return recorder.endRecording(); +} diff --git a/testing/dart/picture_test.dart b/testing/dart/picture_test.dart index badd3da3a39d8..77635252a7e03 100644 --- a/testing/dart/picture_test.dart +++ b/testing/dart/picture_test.dart @@ -1,4 +1,4 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. +// Copyright 2022 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. From f03e228acb0eef9b60f0dead572a1e01ae2a255c Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 11 Aug 2022 14:42:36 -0700 Subject: [PATCH 16/43] Update image_test.dart --- lib/web_ui/test/engine/image/image_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index 66acd9622e241..2f6e6c3a58cda 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -57,4 +57,4 @@ Picture _createPicture() { const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); canvas.clipRect(rect); return recorder.endRecording(); -} \ No newline at end of file +} From 6832d11b668072455a8b36c9df53ab542a08e76c Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 11 Aug 2022 15:37:00 -0700 Subject: [PATCH 17/43] Update picture_test.dart --- lib/web_ui/test/engine/picture_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/test/engine/picture_test.dart b/lib/web_ui/test/engine/picture_test.dart index cf841c6e4aea1..d83a6442411bb 100644 --- a/lib/web_ui/test/engine/picture_test.dart +++ b/lib/web_ui/test/engine/picture_test.dart @@ -1,4 +1,4 @@ -// Copyright 2022 The Flutter Authors. All rights reserved. +// 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. From 2ef20d048b74eeeb6cfff07b564d59a025d042e5 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 11 Aug 2022 15:57:13 -0700 Subject: [PATCH 18/43] Update image_test.dart --- lib/web_ui/test/engine/image/image_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index 2f6e6c3a58cda..c21ae0726e5bc 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -1,4 +1,4 @@ -// Copyright 2022 The Flutter Authors. All rights reserved. +// 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. From 932932fdcf929f562d58eb34f37ee79c45162547 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 11 Aug 2022 16:57:30 -0700 Subject: [PATCH 19/43] Update image_test.dart --- lib/web_ui/test/engine/image/image_test.dart | 26 ++++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index c21ae0726e5bc..88cd41f468756 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -3,53 +3,53 @@ // found in the LICENSE file. import 'package:test/test.dart'; -import 'package:ui/ui.dart'; +import 'package:ui/ui.dart' as ui; void main() { test('Image constructor invokes onCreate once', () async { int onCreateInvokedCount = 0; - Image? createdImage; - Image.onCreate = (Image image) { + ui.Image? createdImage; + ui.Image.onCreate = (ui.Image image) { onCreateInvokedCount++; createdImage = image; }; - final Image image1 = await _createImage(); + final ui.Image image1 = await _createImage(); expect(onCreateInvokedCount, 1); expect(createdImage, image1); - final Image image2 = await _createImage(); + final ui.Image image2 = await _createImage(); expect(onCreateInvokedCount, 2); expect(createdImage, image2); - Image.onCreate = null; + + ui.Image.onCreate = null; }); test('dispose() invokes onDispose once', () async { int onDisposeInvokedCount = 0; - Image? disposedImage; - Image.onDispose = (Image image) { + ui.Image? disposedImage; + ui.Image.onDispose = (ui.Image image) { onDisposeInvokedCount++; disposedImage = image; }; - final Image image1 = await _createImage()..dispose(); + final ui.Image image1 = await _createImage()..dispose(); expect(onDisposeInvokedCount, 1); expect(disposedImage, image1); - final Image image2 = await _createImage()..dispose(); + final ui.Image image2 = await _createImage()..dispose(); expect(onDisposeInvokedCount, 2); expect(disposedImage, image2); - Image.onDispose = null; + ui.Image.onDispose = null; }); } - -Future _createImage() async => _createPicture().toImage(10, 10); +Future _createImage() async => _createPicture().toImage(10, 10); Picture _createPicture() { final PictureRecorder recorder = PictureRecorder(); From 4ea889edece77ad16107c487d66c3071fe5dd73d Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 12 Aug 2022 21:33:11 -0700 Subject: [PATCH 20/43] - --- lib/web_ui/test/engine/image/image_test.dart | 4 ++++ lib/web_ui/test/engine/picture_test.dart | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index 88cd41f468756..5fd1376d5cea2 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -6,6 +6,10 @@ import 'package:test/test.dart'; import 'package:ui/ui.dart' as ui; void main() { + internalBootstrapBrowserTest(() => testMain); +} + +Future testMain() async { test('Image constructor invokes onCreate once', () async { int onCreateInvokedCount = 0; ui.Image? createdImage; diff --git a/lib/web_ui/test/engine/picture_test.dart b/lib/web_ui/test/engine/picture_test.dart index d83a6442411bb..c83384d85b925 100644 --- a/lib/web_ui/test/engine/picture_test.dart +++ b/lib/web_ui/test/engine/picture_test.dart @@ -6,6 +6,10 @@ import 'package:test/test.dart'; import 'package:ui/ui.dart'; void main() { + internalBootstrapBrowserTest(() => testMain); +} + +Future testMain() async { test('Picture constructor invokes onCreate once', () async { int onCreateInvokedCount = 0; Picture? createdPicture; From 0f53a5b89d3bd366c5592fc6df8b4da70a79bafa Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 12 Aug 2022 21:50:09 -0700 Subject: [PATCH 21/43] - --- lib/web_ui/test/engine/image/image_test.dart | 1 + lib/web_ui/test/engine/picture_test.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index 5fd1376d5cea2..63503fa176f81 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/ui.dart' as ui; diff --git a/lib/web_ui/test/engine/picture_test.dart b/lib/web_ui/test/engine/picture_test.dart index c83384d85b925..90b2809b6830b 100644 --- a/lib/web_ui/test/engine/picture_test.dart +++ b/lib/web_ui/test/engine/picture_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/ui.dart'; From c9df53e7c4a69ecfc9882dcda3b1be89444a973b Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 12 Aug 2022 22:24:24 -0700 Subject: [PATCH 22/43] Update image_test.dart --- lib/web_ui/test/engine/image/image_test.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index 63503fa176f81..29ffe6b13b6d0 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -54,12 +54,12 @@ Future testMain() async { }); } -Future _createImage() async => _createPicture().toImage(10, 10); +Future _createImage() async => await _createPicture().toImage(10, 10); -Picture _createPicture() { - final PictureRecorder recorder = PictureRecorder(); - final Canvas canvas = Canvas(recorder); - const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); +ui.Picture _createPicture() { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + const ui.Rect rect = ui.Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); canvas.clipRect(rect); return recorder.endRecording(); } From 3f258cdc84a3e666535c5ee63640495f251b9ec8 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 24 Aug 2022 16:15:08 -0700 Subject: [PATCH 23/43] Update image_test.dart --- lib/web_ui/test/engine/image/image_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index 29ffe6b13b6d0..b37dcdb320ed4 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -54,7 +54,7 @@ Future testMain() async { }); } -Future _createImage() async => await _createPicture().toImage(10, 10); +Future _createImage() => _createPicture().toImage(10, 10); ui.Picture _createPicture() { final ui.PictureRecorder recorder = ui.PictureRecorder(); From f951116dab6fb7aa2e731111a328db5aed26fd99 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 24 Aug 2022 16:51:14 -0700 Subject: [PATCH 24/43] Update picture_test.dart --- lib/web_ui/test/engine/picture_test.dart | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/web_ui/test/engine/picture_test.dart b/lib/web_ui/test/engine/picture_test.dart index 90b2809b6830b..9a95a1bf55e07 100644 --- a/lib/web_ui/test/engine/picture_test.dart +++ b/lib/web_ui/test/engine/picture_test.dart @@ -4,7 +4,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/ui.dart'; +import 'package:ui/ui.dart' as ui; void main() { internalBootstrapBrowserTest(() => testMain); @@ -13,50 +13,50 @@ void main() { Future testMain() async { test('Picture constructor invokes onCreate once', () async { int onCreateInvokedCount = 0; - Picture? createdPicture; - Picture.onCreate = (Picture picture) { + ui.Picture? createdPicture; + ui.Picture.onCreate = (ui.Picture picture) { onCreateInvokedCount++; createdPicture = picture; }; - final Picture picture1 = _createPicture(); + final ui.Picture picture1 = _createPicture(); expect(onCreateInvokedCount, 1); expect(createdPicture, picture1); - final Picture picture2 = _createPicture(); + final ui.Picture picture2 = _createPicture(); expect(onCreateInvokedCount, 2); expect(createdPicture, picture2); - Picture.onCreate = null; + ui.Picture.onCreate = null; }); test('dispose() invokes onDispose once', () async { int onDisposeInvokedCount = 0; - Picture? disposedPicture; - Picture.onDispose = (Picture picture) { + ui.Picture? disposedPicture; + ui.Picture.onDispose = (ui.Picture picture) { onDisposeInvokedCount++; disposedPicture = picture; }; - final Picture picture1 = _createPicture()..dispose(); + final ui.Picture picture1 = _createPicture()..dispose(); expect(onDisposeInvokedCount, 1); expect(disposedPicture, picture1); - final Picture picture2 = _createPicture()..dispose(); + final ui.Picture picture2 = _createPicture()..dispose(); expect(onDisposeInvokedCount, 2); expect(disposedPicture, picture2); - Picture.onDispose = null; + ui.Picture.onDispose = null; }); } -Picture _createPicture() { - final PictureRecorder recorder = PictureRecorder(); - final Canvas canvas = Canvas(recorder); - const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); +ui.Picture _createPicture() { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + const ui.Rect rect = ui.Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); canvas.clipRect(rect); return recorder.endRecording(); } From 7940b1eb71a101bddd0073d75114781f6b96f9e0 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 24 Aug 2022 17:06:23 -0700 Subject: [PATCH 25/43] Update image_test.dart --- lib/web_ui/test/engine/image/image_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index b37dcdb320ed4..7f3815913fe25 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -4,7 +4,7 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/ui.dart' as ui; +import 'package:ui/ui.dart' as ui; void main() { internalBootstrapBrowserTest(() => testMain); From cc9912fe1decab31f03de98384b35a1b75f4e3c3 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 25 Aug 2022 15:57:19 -0700 Subject: [PATCH 26/43] - --- lib/ui/painting.dart | 1 + lib/web_ui/lib/canvas.dart | 3 +-- lib/web_ui/lib/src/engine/canvaskit/picture.dart | 1 + lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart | 5 ++++- lib/web_ui/lib/src/engine/picture.dart | 5 ++++- lib/web_ui/test/engine/picture_test.dart | 2 ++ 6 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 2c27361c64b90..e2f0f30ac715b 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5753,6 +5753,7 @@ class PictureRecorder extends NativeFieldWrapperClass1 { _endRecording(picture); _canvas!._recorder = null; _canvas = null; + Picture.onCreate?.call(picture); return picture; } diff --git a/lib/web_ui/lib/canvas.dart b/lib/web_ui/lib/canvas.dart index e0788aeb33cbd..5c989e557d26f 100644 --- a/lib/web_ui/lib/canvas.dart +++ b/lib/web_ui/lib/canvas.dart @@ -154,12 +154,11 @@ abstract class Canvas { } abstract class Picture { - Picture() { onCreate?.call(this); } static void Function(Picture)? onCreate; static void Function(Picture)? onDispose; Future toImage(int width, int height); Image toImageSync(int width, int height); - void dispose() { onDispose?.call(this); } + void dispose(); bool get debugDisposed; int get approximateBytesUsed; } diff --git a/lib/web_ui/lib/src/engine/canvaskit/picture.dart b/lib/web_ui/lib/src/engine/canvaskit/picture.dart index 0e55fe8f8634e..32d807bc53eff 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/picture.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/picture.dart @@ -78,6 +78,7 @@ class CkPicture extends ManagedSkiaObject implements ui.Picture { _debugDisposalStackTrace = StackTrace.current; return true; }()); + ui.Picture.onDispose?.call(this); if (Instrumentation.enabled) { Instrumentation.instance.incrementCounter('Picture disposed'); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart b/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart index 1b63de0693384..5a291ab960fd2 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart @@ -38,7 +38,10 @@ class CkPictureRecorder implements ui.PictureRecorder { final SkPicture skPicture = recorder.finishRecordingAsPicture(); recorder.delete(); _skRecorder = null; - return CkPicture(skPicture, _cullRect, _recordingCanvas!.pictureSnapshot); + final CkPicture result = + CkPicture(skPicture, _cullRect, _recordingCanvas!.pictureSnapshot); + ui.Picture.onCreate?.call(result); + return result; } @override diff --git a/lib/web_ui/lib/src/engine/picture.dart b/lib/web_ui/lib/src/engine/picture.dart index dc432b2b9f34c..7476b3a3a55cf 100644 --- a/lib/web_ui/lib/src/engine/picture.dart +++ b/lib/web_ui/lib/src/engine/picture.dart @@ -40,7 +40,9 @@ class EnginePictureRecorder implements ui.PictureRecorder { } _isRecording = false; _canvas!.endRecording(); - return EnginePicture(_canvas, cullRect); + final EnginePicture result = EnginePicture(_canvas, cullRect); + ui.Picture.onCreate?.call(result); + return result; } } @@ -97,6 +99,7 @@ class EnginePicture implements ui.Picture { @override void dispose() { + ui.Picture.onDispose?.call(this); _disposed = true; } diff --git a/lib/web_ui/test/engine/picture_test.dart b/lib/web_ui/test/engine/picture_test.dart index 9a95a1bf55e07..da9576783a637 100644 --- a/lib/web_ui/test/engine/picture_test.dart +++ b/lib/web_ui/test/engine/picture_test.dart @@ -12,6 +12,7 @@ void main() { Future testMain() async { test('Picture constructor invokes onCreate once', () async { + print('!!!!! picture onCreate start'); int onCreateInvokedCount = 0; ui.Picture? createdPicture; ui.Picture.onCreate = (ui.Picture picture) { @@ -29,6 +30,7 @@ Future testMain() async { expect(onCreateInvokedCount, 2); expect(createdPicture, picture2); ui.Picture.onCreate = null; + print('!!!!! picture onCreate end'); }); test('dispose() invokes onDispose once', () async { From 5ae80a63a629c934e4988cd683dc4ec1237e4e5f Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 25 Aug 2022 16:00:01 -0700 Subject: [PATCH 27/43] Update painting.dart --- lib/ui/painting.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index e2f0f30ac715b..3bb1586e026f4 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5607,7 +5607,7 @@ class Picture extends NativeFieldWrapperClass1 { /// /// To create a [Picture], use a [PictureRecorder]. @pragma('vm:entry-point') - Picture._() { onCreate?.call(this); } + Picture._(); /// A callback that is invoked to report an object creation. /// From ba7d0a52f98268a261c77e0d1807c6af30ca648f Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 25 Aug 2022 16:26:29 -0700 Subject: [PATCH 28/43] - --- lib/ui/painting.dart | 2 ++ .../src/engine/canvaskit/picture_recorder.dart | 2 ++ lib/web_ui/lib/src/engine/picture.dart | 2 ++ lib/web_ui/test/engine/picture_test.dart | 16 +++++++++++++--- testing/dart/picture_test.dart | 14 +++++++++++++- 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 3bb1586e026f4..7f229c566199b 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5753,6 +5753,8 @@ class PictureRecorder extends NativeFieldWrapperClass1 { _endRecording(picture); _canvas!._recorder = null; _canvas = null; + // We invoke the handler here, not in the Picture constructor, because we want + // [picture.approximateBytesUsed] to be available for the handler. Picture.onCreate?.call(picture); return picture; } diff --git a/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart b/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart index 5a291ab960fd2..7a0d11e433548 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart @@ -40,6 +40,8 @@ class CkPictureRecorder implements ui.PictureRecorder { _skRecorder = null; final CkPicture result = CkPicture(skPicture, _cullRect, _recordingCanvas!.pictureSnapshot); + // We invoke the handler here, not in the picture constructor, because we want + // [result.approximateBytesUsed] to be available for the handler. ui.Picture.onCreate?.call(result); return result; } diff --git a/lib/web_ui/lib/src/engine/picture.dart b/lib/web_ui/lib/src/engine/picture.dart index 7476b3a3a55cf..074dc9f27856d 100644 --- a/lib/web_ui/lib/src/engine/picture.dart +++ b/lib/web_ui/lib/src/engine/picture.dart @@ -41,6 +41,8 @@ class EnginePictureRecorder implements ui.PictureRecorder { _isRecording = false; _canvas!.endRecording(); final EnginePicture result = EnginePicture(_canvas, cullRect); + // We invoke the handler here, not in the Picture constructor, because we want + // [result.approximateBytesUsed] to be available for the handler. ui.Picture.onCreate?.call(result); return result; } diff --git a/lib/web_ui/test/engine/picture_test.dart b/lib/web_ui/test/engine/picture_test.dart index da9576783a637..d4c5928d38fdb 100644 --- a/lib/web_ui/test/engine/picture_test.dart +++ b/lib/web_ui/test/engine/picture_test.dart @@ -11,8 +11,7 @@ void main() { } Future testMain() async { - test('Picture constructor invokes onCreate once', () async { - print('!!!!! picture onCreate start'); + test('Picture construction invokes onCreate once', () async { int onCreateInvokedCount = 0; ui.Picture? createdPicture; ui.Picture.onCreate = (ui.Picture picture) { @@ -30,7 +29,18 @@ Future testMain() async { expect(onCreateInvokedCount, 2); expect(createdPicture, picture2); ui.Picture.onCreate = null; - print('!!!!! picture onCreate end'); + }); + + test('approximateBytesUsed is available for onCreate', () async { + int pictureSize = -1; + + ui.Picture.onCreate = (ui.Picture picture) => + pictureSize = picture.approximateBytesUsed; + + _createPicture(); + + expect(pictureSize >= 0, true); + ui.Picture.onCreate = null; }); test('dispose() invokes onDispose once', () async { diff --git a/testing/dart/picture_test.dart b/testing/dart/picture_test.dart index 77635252a7e03..4ea13962fcaa8 100644 --- a/testing/dart/picture_test.dart +++ b/testing/dart/picture_test.dart @@ -7,7 +7,7 @@ import 'dart:ui'; import 'package:litetest/litetest.dart'; void main() { - test('Picture constructor invokes onCreate once', () async { + test('Picture construction invokes onCreate once', () async { int onCreateInvokedCount = 0; Picture? createdPicture; Picture.onCreate = (Picture picture) { @@ -27,6 +27,18 @@ void main() { Picture.onCreate = null; }); + test('approximateBytesUsed is available for onCreate', () async { + int pictureSize = -1; + + Picture.onCreate = (Picture picture) => + pictureSize = picture.approximateBytesUsed; + + _createPicture(); + + expect(pictureSize >= 0, true); + Picture.onCreate = null; + }); + test('dispose() invokes onDispose once', () async { int onDisposeInvokedCount = 0; Picture? disposedPicture; From 7fec23deb8d967e7cbdff9028a156e4032e1681c Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 25 Aug 2022 16:40:38 -0700 Subject: [PATCH 29/43] - --- lib/ui/painting.dart | 15 +++++++++++---- lib/web_ui/lib/canvas.dart | 6 ++++-- lib/web_ui/lib/painting.dart | 6 ++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 7f229c566199b..b824cdcafc3df 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1618,6 +1618,10 @@ enum PixelFormat { bgra8888, } + +/// Signature for [Image] lifecycle events. +typedef ImageEventCallback = void Function(Image); + /// Opaque handle to raw decoded image data (pixels). /// /// To obtain an [Image] object, use the [ImageDescriptor] API. @@ -1661,14 +1665,14 @@ class Image { /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onCreate] directly because [MemoryAllocations] /// allows multiple callbacks. - static void Function(Image)? onCreate; + static ImageEventCallback? onCreate; /// A callback that is invoked to report the object disposal. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onDispose] directly because [MemoryAllocations] /// allows multiple callbacks. - static void Function(Image)? onDispose; + static ImageEventCallback? onDispose; StackTrace? _debugStack; @@ -5593,6 +5597,9 @@ class Canvas extends NativeFieldWrapperClass1 { external void _drawShadow(Path path, int color, double elevation, bool transparentOccluder); } +/// Signature for [Picture] lifecycle events. +typedef PictureEventCallback = void Function(Picture); + /// An object representing a sequence of recorded graphical operations. /// /// To create a [Picture], use a [PictureRecorder]. @@ -5614,14 +5621,14 @@ class Picture extends NativeFieldWrapperClass1 { /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onCreate] directly because [MemoryAllocations] /// allows multiple callbacks. - static void Function(Picture)? onCreate; + static PictureEventCallback? onCreate; /// A callback that is invoked to report the object disposal. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onDispose] directly because [MemoryAllocations] /// allows multiple callbacks. - static void Function(Picture)? onDispose; + static PictureEventCallback? onDispose; /// Creates an image from this picture. /// diff --git a/lib/web_ui/lib/canvas.dart b/lib/web_ui/lib/canvas.dart index 5c989e557d26f..d7df80f466325 100644 --- a/lib/web_ui/lib/canvas.dart +++ b/lib/web_ui/lib/canvas.dart @@ -153,9 +153,11 @@ abstract class Canvas { ); } +typedef PictureEventCallback = void Function(Picture); + abstract class Picture { - static void Function(Picture)? onCreate; - static void Function(Picture)? onDispose; + static PictureEventCallback? onCreate; + static PictureEventCallback? onDispose; Future toImage(int width, int height); Image toImageSync(int width, int height); void dispose(); diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index ba242d8169405..3502d208ac82d 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -331,9 +331,11 @@ abstract class Gradient extends Shader { endAngle, matrix4 != null ? engine.toMatrix32(matrix4) : null); } +typedef ImageEventCallback = void Function(Image); + abstract class Image { - static void Function(Image)? onCreate; - static void Function(Image)? onDispose; + static ImageEventCallback? onCreate; + static ImageEventCallback? onDispose; int get width; int get height; From 9a8de067990fe68176c297bccf1ed0dd1b44b505 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 29 Aug 2022 15:47:15 -0700 Subject: [PATCH 30/43] - --- .../engine/canvaskit/picture_recorder.dart | 1 + .../lib/src/engine/html_image_codec.dart | 2 + lib/web_ui/lib/src/engine/picture.dart | 3 ++ lib/web_ui/test/engine/image/image_test.dart | 50 +++++++++++-------- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart b/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart index 7a0d11e433548..d3bb345432f27 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart @@ -29,6 +29,7 @@ class CkPictureRecorder implements ui.PictureRecorder { @override CkPicture endRecording() { + print('CkPicture'); final SkPictureRecorder? recorder = _skRecorder; if (recorder == null) { diff --git a/lib/web_ui/lib/src/engine/html_image_codec.dart b/lib/web_ui/lib/src/engine/html_image_codec.dart index dfb3c3657d46c..e62a389a72726 100644 --- a/lib/web_ui/lib/src/engine/html_image_codec.dart +++ b/lib/web_ui/lib/src/engine/html_image_codec.dart @@ -141,7 +141,9 @@ class SingleFrameInfo implements ui.FrameInfo { class HtmlImage implements ui.Image { HtmlImage(this.imgElement, this.width, this.height) { + print('before oncreate'); ui.Image.onCreate?.call(this); + print('after oncreate'); } final DomHTMLImageElement imgElement; diff --git a/lib/web_ui/lib/src/engine/picture.dart b/lib/web_ui/lib/src/engine/picture.dart index 074dc9f27856d..61d5899c954dc 100644 --- a/lib/web_ui/lib/src/engine/picture.dart +++ b/lib/web_ui/lib/src/engine/picture.dart @@ -33,6 +33,7 @@ class EnginePictureRecorder implements ui.PictureRecorder { @override EnginePicture endRecording() { + print('EnginePicture'); if (!_isRecording) { // The mobile version returns an empty picture in this case. To match the // behavior we produce a blank picture too. @@ -81,6 +82,7 @@ class EnginePicture implements ui.Picture { imageElement.addEventListener('error', errorListener); late final DomEventListener loadListener; loadListener = allowInterop((DomEvent event) { + print('before complete'); onImageLoaded.complete(HtmlImage( imageElement, width, @@ -89,6 +91,7 @@ class EnginePicture implements ui.Picture { imageElement.removeEventListener('load', loadListener); }); imageElement.addEventListener('load', loadListener); + print('toImage returning...'); return onImageLoaded.future; } diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index 7f3815913fe25..135b6d71c04f0 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -19,39 +19,43 @@ Future testMain() async { createdImage = image; }; - final ui.Image image1 = await _createImage(); +print(10); + final Future future = _createImage(); +print(20); + final image = await future; +print(30); - expect(onCreateInvokedCount, 1); - expect(createdImage, image1); + // expect(onCreateInvokedCount, 1); + // expect(createdImage, image1); - final ui.Image image2 = await _createImage(); + // final ui.Image image2 = await _createImage(); - expect(onCreateInvokedCount, 2); - expect(createdImage, image2); + // expect(onCreateInvokedCount, 2); + // expect(createdImage, image2); ui.Image.onCreate = null; }); - test('dispose() invokes onDispose once', () async { - int onDisposeInvokedCount = 0; - ui.Image? disposedImage; - ui.Image.onDispose = (ui.Image image) { - onDisposeInvokedCount++; - disposedImage = image; - }; + // test('dispose() invokes onDispose once', () async { + // int onDisposeInvokedCount = 0; + // ui.Image? disposedImage; + // ui.Image.onDispose = (ui.Image image) { + // onDisposeInvokedCount++; + // disposedImage = image; + // }; - final ui.Image image1 = await _createImage()..dispose(); + // final ui.Image image1 = await _createImage()..dispose(); - expect(onDisposeInvokedCount, 1); - expect(disposedImage, image1); + // expect(onDisposeInvokedCount, 1); + // expect(disposedImage, image1); - final ui.Image image2 = await _createImage()..dispose(); + // final ui.Image image2 = await _createImage()..dispose(); - expect(onDisposeInvokedCount, 2); - expect(disposedImage, image2); + // expect(onDisposeInvokedCount, 2); + // expect(disposedImage, image2); - ui.Image.onDispose = null; - }); + // ui.Image.onDispose = null; + // }); } Future _createImage() => _createPicture().toImage(10, 10); @@ -61,5 +65,7 @@ ui.Picture _createPicture() { final ui.Canvas canvas = ui.Canvas(recorder); const ui.Rect rect = ui.Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); canvas.clipRect(rect); - return recorder.endRecording(); + final result = recorder.endRecording(); + print('created'); + return result; } From 22babb6522c7e741a4d6e037054d38b45bfdbb5e Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 29 Aug 2022 15:50:58 -0700 Subject: [PATCH 31/43] Create image_test.dart --- lib/web_ui/test/canvaskit/image_test.dart | 71 +++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 lib/web_ui/test/canvaskit/image_test.dart diff --git a/lib/web_ui/test/canvaskit/image_test.dart b/lib/web_ui/test/canvaskit/image_test.dart new file mode 100644 index 0000000000000..135b6d71c04f0 --- /dev/null +++ b/lib/web_ui/test/canvaskit/image_test.dart @@ -0,0 +1,71 @@ +// 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. + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/ui.dart' as ui; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +Future testMain() async { + test('Image constructor invokes onCreate once', () async { + int onCreateInvokedCount = 0; + ui.Image? createdImage; + ui.Image.onCreate = (ui.Image image) { + onCreateInvokedCount++; + createdImage = image; + }; + +print(10); + final Future future = _createImage(); +print(20); + final image = await future; +print(30); + + // expect(onCreateInvokedCount, 1); + // expect(createdImage, image1); + + // final ui.Image image2 = await _createImage(); + + // expect(onCreateInvokedCount, 2); + // expect(createdImage, image2); + + ui.Image.onCreate = null; + }); + + // test('dispose() invokes onDispose once', () async { + // int onDisposeInvokedCount = 0; + // ui.Image? disposedImage; + // ui.Image.onDispose = (ui.Image image) { + // onDisposeInvokedCount++; + // disposedImage = image; + // }; + + // final ui.Image image1 = await _createImage()..dispose(); + + // expect(onDisposeInvokedCount, 1); + // expect(disposedImage, image1); + + // final ui.Image image2 = await _createImage()..dispose(); + + // expect(onDisposeInvokedCount, 2); + // expect(disposedImage, image2); + + // ui.Image.onDispose = null; + // }); +} + +Future _createImage() => _createPicture().toImage(10, 10); + +ui.Picture _createPicture() { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + const ui.Rect rect = ui.Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); + canvas.clipRect(rect); + final result = recorder.endRecording(); + print('created'); + return result; +} From 41754eda6ed24eddd739187f440e29688e5af16a Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 30 Aug 2022 16:44:40 -0700 Subject: [PATCH 32/43] - --- lib/web_ui/test/canvaskit/image_test.dart | 44 +++++++++++++++++++ lib/web_ui/test/engine/image/image_test.dart | 46 ++++++++++++++++++++ testing/dart/image_test.dart | 41 +++++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/lib/web_ui/test/canvaskit/image_test.dart b/lib/web_ui/test/canvaskit/image_test.dart index f6ba8031cf1a4..9f4d620c9fa58 100644 --- a/lib/web_ui/test/canvaskit/image_test.dart +++ b/lib/web_ui/test/canvaskit/image_test.dart @@ -24,6 +24,50 @@ void testMain() { image.dispose(); // TODO(hterkelsen): https://github.com/flutter/flutter/issues/109265 }, skip: isFirefox); + + test('Image constructor invokes onCreate once', () async { + int onCreateInvokedCount = 0; + ui.Image? createdImage; + ui.Image.onCreate = (ui.Image image) { + onCreateInvokedCount++; + createdImage = image; + }; + + final ui.Image image1 = await _createImage(); + + expect(onCreateInvokedCount, 1); + expect(createdImage, image1); + + final ui.Image image2 = await _createImage(); + + expect(onCreateInvokedCount, 2); + expect(createdImage, image2); + + ui.Image.onCreate = null; + // TODO(hterkelsen): https://github.com/flutter/flutter/issues/109265 + }, skip: isFirefox); + + test('dispose() invokes onDispose once', () async { + int onDisposeInvokedCount = 0; + ui.Image? disposedImage; + ui.Image.onDispose = (ui.Image image) { + onDisposeInvokedCount++; + disposedImage = image; + }; + + final ui.Image image1 = await _createImage()..dispose(); + + expect(onDisposeInvokedCount, 1); + expect(disposedImage, image1); + + final ui.Image image2 = await _createImage()..dispose(); + + expect(onDisposeInvokedCount, 2); + expect(disposedImage, image2); + + ui.Image.onDispose = null; + // TODO(hterkelsen): https://github.com/flutter/flutter/issues/109265 + }, skip: isFirefox); } Future _createImage() => _createPicture().toImage(10, 10); diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index 8d690483a7ea6..0b5fef4b8daae 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -19,6 +19,52 @@ Future testMain() async { // TODO(polina-c): unskip the test when bug is fixed: // https://github.com/flutter/engine/pull/35791 }, skip: true); + + test('Image constructor invokes onCreate once', () async { + int onCreateInvokedCount = 0; + ui.Image? createdImage; + ui.Image.onCreate = (ui.Image image) { + onCreateInvokedCount++; + createdImage = image; + }; + + final ui.Image image1 = await _createImage(); + + expect(onCreateInvokedCount, 1); + expect(createdImage, image1); + + final ui.Image image2 = await _createImage(); + + expect(onCreateInvokedCount, 2); + expect(createdImage, image2); + + ui.Image.onCreate = null; + // TODO(polina-c): unskip the test when bug is fixed: + // https://github.com/flutter/engine/pull/35791 + }, skip: true); + + test('dispose() invokes onDispose once', () async { + int onDisposeInvokedCount = 0; + ui.Image? disposedImage; + ui.Image.onDispose = (ui.Image image) { + onDisposeInvokedCount++; + disposedImage = image; + }; + + final ui.Image image1 = await _createImage()..dispose(); + + expect(onDisposeInvokedCount, 1); + expect(disposedImage, image1); + + final ui.Image image2 = await _createImage()..dispose(); + + expect(onDisposeInvokedCount, 2); + expect(disposedImage, image2); + + ui.Image.onDispose = null; + // TODO(polina-c): unskip the test when bug is fixed: + // https://github.com/flutter/engine/pull/35791 + }, skip: true); } Future _createImage() => _createPicture().toImage(10, 10); diff --git a/testing/dart/image_test.dart b/testing/dart/image_test.dart index 4cb44267b6f25..18bca7df5f8ce 100644 --- a/testing/dart/image_test.dart +++ b/testing/dart/image_test.dart @@ -13,6 +13,47 @@ void main() { expect(image.runtimeType.toString(), equals('Image')); image.dispose(); }); + + test('Image constructor invokes onCreate once', () async { + int onCreateInvokedCount = 0; + Image? createdImage; + Image.onCreate = (Image image) { + onCreateInvokedCount++; + createdImage = image; + }; + + final Image image1 = await _createImage(); + + expect(onCreateInvokedCount, 1); + expect(createdImage, image1); + + final Image image2 = await _createImage(); + + expect(onCreateInvokedCount, 2); + expect(createdImage, image2); + Image.onCreate = null; + }); + + test('dispose() invokes onDispose once', () async { + int onDisposeInvokedCount = 0; + Image? disposedImage; + Image.onDispose = (Image image) { + onDisposeInvokedCount++; + disposedImage = image; + }; + + final Image image1 = await _createImage()..dispose(); + + expect(onDisposeInvokedCount, 1); + expect(disposedImage, image1); + + final Image image2 = await _createImage()..dispose(); + + expect(onDisposeInvokedCount, 2); + expect(disposedImage, image2); + + Image.onDispose = null; + }); } Future _createImage() => _createPicture().toImage(10, 10); From 4b2462853ee7efeb0d9358d1db13e538e2571761 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 30 Aug 2022 16:54:22 -0700 Subject: [PATCH 33/43] - --- lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart | 1 - lib/web_ui/lib/src/engine/html_image_codec.dart | 2 -- lib/web_ui/lib/src/engine/picture.dart | 3 --- 3 files changed, 6 deletions(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart b/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart index d3bb345432f27..7a0d11e433548 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart @@ -29,7 +29,6 @@ class CkPictureRecorder implements ui.PictureRecorder { @override CkPicture endRecording() { - print('CkPicture'); final SkPictureRecorder? recorder = _skRecorder; if (recorder == null) { diff --git a/lib/web_ui/lib/src/engine/html_image_codec.dart b/lib/web_ui/lib/src/engine/html_image_codec.dart index e62a389a72726..dfb3c3657d46c 100644 --- a/lib/web_ui/lib/src/engine/html_image_codec.dart +++ b/lib/web_ui/lib/src/engine/html_image_codec.dart @@ -141,9 +141,7 @@ class SingleFrameInfo implements ui.FrameInfo { class HtmlImage implements ui.Image { HtmlImage(this.imgElement, this.width, this.height) { - print('before oncreate'); ui.Image.onCreate?.call(this); - print('after oncreate'); } final DomHTMLImageElement imgElement; diff --git a/lib/web_ui/lib/src/engine/picture.dart b/lib/web_ui/lib/src/engine/picture.dart index 61d5899c954dc..074dc9f27856d 100644 --- a/lib/web_ui/lib/src/engine/picture.dart +++ b/lib/web_ui/lib/src/engine/picture.dart @@ -33,7 +33,6 @@ class EnginePictureRecorder implements ui.PictureRecorder { @override EnginePicture endRecording() { - print('EnginePicture'); if (!_isRecording) { // The mobile version returns an empty picture in this case. To match the // behavior we produce a blank picture too. @@ -82,7 +81,6 @@ class EnginePicture implements ui.Picture { imageElement.addEventListener('error', errorListener); late final DomEventListener loadListener; loadListener = allowInterop((DomEvent event) { - print('before complete'); onImageLoaded.complete(HtmlImage( imageElement, width, @@ -91,7 +89,6 @@ class EnginePicture implements ui.Picture { imageElement.removeEventListener('load', loadListener); }); imageElement.addEventListener('load', loadListener); - print('toImage returning...'); return onImageLoaded.future; } From 59cb25098b0693ce4d75ee39825dbf2fcbc50a04 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 30 Aug 2022 17:03:21 -0700 Subject: [PATCH 34/43] Update image_test.dart --- testing/dart/image_test.dart | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/testing/dart/image_test.dart b/testing/dart/image_test.dart index 18bca7df5f8ce..7fd46483e5ef4 100644 --- a/testing/dart/image_test.dart +++ b/testing/dart/image_test.dart @@ -33,27 +33,6 @@ void main() { expect(createdImage, image2); Image.onCreate = null; }); - - test('dispose() invokes onDispose once', () async { - int onDisposeInvokedCount = 0; - Image? disposedImage; - Image.onDispose = (Image image) { - onDisposeInvokedCount++; - disposedImage = image; - }; - - final Image image1 = await _createImage()..dispose(); - - expect(onDisposeInvokedCount, 1); - expect(disposedImage, image1); - - final Image image2 = await _createImage()..dispose(); - - expect(onDisposeInvokedCount, 2); - expect(disposedImage, image2); - - Image.onDispose = null; - }); } Future _createImage() => _createPicture().toImage(10, 10); From 0efa9c80fb204b8e949aaec68808ea2d158afb75 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 30 Aug 2022 17:13:52 -0700 Subject: [PATCH 35/43] Update BUILD.gn --- testing/dart/BUILD.gn | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/dart/BUILD.gn b/testing/dart/BUILD.gn index 5880a15c3f979..662884b3562ba 100644 --- a/testing/dart/BUILD.gn +++ b/testing/dart/BUILD.gn @@ -20,7 +20,6 @@ tests = [ "gradient_test.dart", "http_allow_http_connections_test.dart", "http_disallow_http_connections_test.dart", - "image_test.dart", "image_descriptor_test.dart", "image_dispose_test.dart", "image_filter_test.dart", From 62431c1d44e03f049f133912ebfe7bc543640e6b Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 30 Aug 2022 17:48:46 -0700 Subject: [PATCH 36/43] - --- testing/dart/BUILD.gn | 1 + testing/dart/image_dispose_test.dart | 31 --------------- testing/dart/image_events_test.dart | 56 ++++++++++++++++++++++++++++ testing/dart/image_test.dart | 20 ---------- 4 files changed, 57 insertions(+), 51 deletions(-) create mode 100644 testing/dart/image_events_test.dart diff --git a/testing/dart/BUILD.gn b/testing/dart/BUILD.gn index 662884b3562ba..04035d13d8f2e 100644 --- a/testing/dart/BUILD.gn +++ b/testing/dart/BUILD.gn @@ -22,6 +22,7 @@ tests = [ "http_disallow_http_connections_test.dart", "image_descriptor_test.dart", "image_dispose_test.dart", + "image_events_test.dart", "image_filter_test.dart", "image_resize_test.dart", "image_shader_test.dart", diff --git a/testing/dart/image_dispose_test.dart b/testing/dart/image_dispose_test.dart index 3f5087930993d..e96ca0dcb44a8 100644 --- a/testing/dart/image_dispose_test.dart +++ b/testing/dart/image_dispose_test.dart @@ -132,37 +132,6 @@ void main() { expect(() => frame.image.debugDisposed, throwsStateError); } }); - - test('dispose() invokes onDispose once', () async { - int onDisposeInvokedCount = 0; - Image? disposedImage; - Image.onDispose = (Image image) { - onDisposeInvokedCount++; - disposedImage = image; - }; - - final Image image1 = await _createImage()..dispose(); - - expect(onDisposeInvokedCount, 1); - expect(disposedImage, image1); - - final Image image2 = await _createImage()..dispose(); - - expect(onDisposeInvokedCount, 2); - expect(disposedImage, image2); - - Image.onDispose = null; - }); -} - -Future _createImage() async => _createPicture().toImage(10, 10); - -Picture _createPicture() { - final PictureRecorder recorder = PictureRecorder(); - final Canvas canvas = Canvas(recorder); - const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); - canvas.clipRect(rect); - return recorder.endRecording(); } Future _readFile(String fileName) async { diff --git a/testing/dart/image_events_test.dart b/testing/dart/image_events_test.dart new file mode 100644 index 0000000000000..92b856c0014e4 --- /dev/null +++ b/testing/dart/image_events_test.dart @@ -0,0 +1,56 @@ +// 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. + +import 'dart:async'; +import 'dart:ui'; + +import 'package:litetest/litetest.dart'; + +void main() { + test('Image constructor and dispose invokes onCreate once', () async { + // We test constructor and dispose in one test because + // litetest runs the tests in parallel and static handlers + // are shared between tests. + + int onCreateInvokedCount = 0; + Image? createdImage; + int onDisposeInvokedCount = 0; + Image? disposedImage; + Image.onCreate = (Image image) { + onCreateInvokedCount++; + createdImage = image; + }; + Image.onDispose = (Image image) { + onDisposeInvokedCount++; + disposedImage = image; + }; + + final Image image1 = await _createImage()..dispose(); + + expect(onCreateInvokedCount, 1); + expect(createdImage, image1); + expect(onDisposeInvokedCount, 1); + expect(disposedImage, image1); + + final Image image2 = await _createImage()..dispose(); + + expect(onCreateInvokedCount, 2); + expect(createdImage, image2); + expect(onDisposeInvokedCount, 2); + expect(disposedImage, image2); + + Image.onCreate = null; + Image.onDispose = null; + }); +} + +Future _createImage() => _createPicture().toImage(10, 10); + +Picture _createPicture() { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + const Rect rect = Rect.fromLTWH(0.0, 0.0, 100.0, 100.0); + canvas.clipRect(rect); + return recorder.endRecording(); +} diff --git a/testing/dart/image_test.dart b/testing/dart/image_test.dart index 7fd46483e5ef4..4cb44267b6f25 100644 --- a/testing/dart/image_test.dart +++ b/testing/dart/image_test.dart @@ -13,26 +13,6 @@ void main() { expect(image.runtimeType.toString(), equals('Image')); image.dispose(); }); - - test('Image constructor invokes onCreate once', () async { - int onCreateInvokedCount = 0; - Image? createdImage; - Image.onCreate = (Image image) { - onCreateInvokedCount++; - createdImage = image; - }; - - final Image image1 = await _createImage(); - - expect(onCreateInvokedCount, 1); - expect(createdImage, image1); - - final Image image2 = await _createImage(); - - expect(onCreateInvokedCount, 2); - expect(createdImage, image2); - Image.onCreate = null; - }); } Future _createImage() => _createPicture().toImage(10, 10); From a958c1d07e5ffd8896e27bbff193997f860c8631 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 31 Aug 2022 10:29:40 -0700 Subject: [PATCH 37/43] Update painting.dart --- lib/web_ui/lib/painting.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 05926a584f3f2..10ca511800c8c 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -333,7 +333,7 @@ abstract class Gradient extends Shader { matrix4 != null ? engine.toMatrix32(matrix4) : null); } -typedef ImageEventCallback = void Function(Image); +typedef ImageEventCallback = void Function(Image image); abstract class Image { static ImageEventCallback? onCreate; From 20cd6d9169d664b715fb7d36dacec8bab31fe863 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 31 Aug 2022 11:17:14 -0700 Subject: [PATCH 38/43] Update api_conform_test.dart --- web_sdk/test/api_conform_test.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/web_sdk/test/api_conform_test.dart b/web_sdk/test/api_conform_test.dart index 755b6f9a3345c..db5ffb8587ed7 100644 --- a/web_sdk/test/api_conform_test.dart +++ b/web_sdk/test/api_conform_test.dart @@ -247,8 +247,15 @@ void main() { final SimpleFormalParameter webParam = (webTypeDef.type as GenericFunctionType).parameters.parameters[i] as SimpleFormalParameter; - - if (webParam.identifier!.name != uiParam.identifier!.name) { + if (webParam.identifier == null) { + failed = true; + print('Warning: lib/web_ui/ui.dart $typeDefName parameter $i should have name.'); + } + if (uiParam.identifier == null) { + failed = true; + print('Warning: lib/ui/ui.dart $typeDefName parameter $i should have name.'); + } + if (webParam.identifier?.name != uiParam.identifier?.name) { failed = true; print('Warning: lib/ui/ui.dart $typeDefName parameter $i ' '${uiParam.identifier!.name} has a different name in lib/web_ui/ui.dart.'); From 76f096e3d4a211d232f21e003753383e66d9a6af Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 31 Aug 2022 11:18:16 -0700 Subject: [PATCH 39/43] Update painting.dart --- lib/ui/painting.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 8f17c6e832f84..5b0a58caef616 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1626,7 +1626,7 @@ enum PixelFormat { /// Signature for [Image] lifecycle events. -typedef ImageEventCallback = void Function(Image); +typedef ImageEventCallback = void Function(Image image); /// Opaque handle to raw decoded image data (pixels). /// From 6f949a25e5055ef89e746df5410a8c90291fc797 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 31 Aug 2022 11:18:53 -0700 Subject: [PATCH 40/43] Update painting.dart --- lib/ui/painting.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 5b0a58caef616..a7ae9c893c8b9 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5682,7 +5682,7 @@ class Canvas extends NativeFieldWrapperClass1 { } /// Signature for [Picture] lifecycle events. -typedef PictureEventCallback = void Function(Picture); +typedef PictureEventCallback = void Function(Picture picture); /// An object representing a sequence of recorded graphical operations. /// From f87653e145b7accb1c30e10d94bfa354d7b92fbc Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 31 Aug 2022 11:19:09 -0700 Subject: [PATCH 41/43] Update canvas.dart --- lib/web_ui/lib/canvas.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/lib/canvas.dart b/lib/web_ui/lib/canvas.dart index 079cc721fe523..5311baddc9e47 100644 --- a/lib/web_ui/lib/canvas.dart +++ b/lib/web_ui/lib/canvas.dart @@ -124,7 +124,7 @@ abstract class Canvas { ); } -typedef PictureEventCallback = void Function(Picture); +typedef PictureEventCallback = void Function(Picture picture); abstract class Picture { static PictureEventCallback? onCreate; From 99ae37d11b4963817a89692a21b0949e94b92d7b Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 7 Sep 2022 16:51:27 -0700 Subject: [PATCH 42/43] addressed comments --- lib/ui/painting.dart | 8 ++++---- lib/web_ui/lib/src/engine/canvaskit/image.dart | 2 +- lib/web_ui/test/engine/image/image_test.dart | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index a7ae9c893c8b9..6e05046ac6583 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1666,14 +1666,14 @@ class Image { @pragma('vm:entry-point') final _Image _image; - /// A callback that is invoked to report an object creation. + /// A callback that is invoked to report an image creation. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onCreate] directly because [MemoryAllocations] /// allows multiple callbacks. static ImageEventCallback? onCreate; - /// A callback that is invoked to report the object disposal. + /// A callback that is invoked to report the image disposal. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onDispose] directly because [MemoryAllocations] @@ -5700,14 +5700,14 @@ class Picture extends NativeFieldWrapperClass1 { @pragma('vm:entry-point') Picture._(); - /// A callback that is invoked to report an object creation. + /// A callback that is invoked to report a picture creation. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onCreate] directly because [MemoryAllocations] /// allows multiple callbacks. static PictureEventCallback? onCreate; - /// A callback that is invoked to report the object disposal. + /// A callback that is invoked to report the picture disposal. /// /// It's preferred to use [MemoryAllocations] in flutter/foundation.dart /// than to use [onDispose] directly because [MemoryAllocations] diff --git a/lib/web_ui/lib/src/engine/canvaskit/image.dart b/lib/web_ui/lib/src/engine/canvaskit/image.dart index e7bf0b68dbf2d..8a6a8222bd054 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -240,11 +240,11 @@ class CkImage implements ui.Image, StackTraceDebugger { @override void dispose() { - ui.Image.onDispose?.call(this); assert( !_disposed, 'Cannot dispose an image that has already been disposed.', ); + ui.Image.onDispose?.call(this); _disposed = true; box.unref(this); } diff --git a/lib/web_ui/test/engine/image/image_test.dart b/lib/web_ui/test/engine/image/image_test.dart index 0b5fef4b8daae..c0b6235368b3f 100644 --- a/lib/web_ui/test/engine/image/image_test.dart +++ b/lib/web_ui/test/engine/image/image_test.dart @@ -17,7 +17,7 @@ Future testMain() async { expect(image.runtimeType.toString(), equals('HtmlImage')); image.dispose(); // TODO(polina-c): unskip the test when bug is fixed: - // https://github.com/flutter/engine/pull/35791 + // https://github.com/flutter/flutter/issues/110599 }, skip: true); test('Image constructor invokes onCreate once', () async { @@ -40,7 +40,7 @@ Future testMain() async { ui.Image.onCreate = null; // TODO(polina-c): unskip the test when bug is fixed: - // https://github.com/flutter/engine/pull/35791 + // https://github.com/flutter/flutter/issues/110599 }, skip: true); test('dispose() invokes onDispose once', () async { @@ -63,7 +63,7 @@ Future testMain() async { ui.Image.onDispose = null; // TODO(polina-c): unskip the test when bug is fixed: - // https://github.com/flutter/engine/pull/35791 + // https://github.com/flutter/flutter/issues/110599 }, skip: true); } From 360ff2a57d20cd98ec841e2ef1f9dc3cd134e4ff Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 8 Sep 2022 08:36:49 -0700 Subject: [PATCH 43/43] Update painting.dart --- lib/ui/painting.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 6e05046ac6583..58e2996ca05b9 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1624,7 +1624,6 @@ enum PixelFormat { bgra8888, } - /// Signature for [Image] lifecycle events. typedef ImageEventCallback = void Function(Image image);