diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index d98275d34f9c7..b3b51035edcb8 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -21,23 +21,6 @@ class Scene extends NativeFieldWrapperClass1 { @pragma('vm:entry-point') Scene._(); - /// Synchronously creates a handle to an image from this scene. - /// - /// {@macro dart.ui.painting.Picture.toImageSync} - Image toImageSync(int width, int height) { - if (width <= 0 || height <= 0) { - throw Exception('Invalid image dimensions.'); - } - - final _Image image = _Image._(); - final String? result = _toImageSync(width, height, image); - if (result != null) { - throw PictureRasterizationException._(result); - } - return Image._(image, image.width, image.height); - } - String? _toImageSync(int width, int height, _Image outImage) native 'Scene_toImageSync'; - /// Creates a raster image representation of the current state of the scene. /// This is a slow operation that is performed on a background thread. /// diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 48def9ddc2941..a6448970f662d 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -22,7 +22,6 @@ namespace flutter { IMPLEMENT_WRAPPERTYPEINFO(ui, Scene); #define FOR_EACH_BINDING(V) \ - V(Scene, toImageSync) \ V(Scene, toImage) \ V(Scene, dispose) @@ -67,24 +66,6 @@ void Scene::dispose() { ClearDartWrapper(); } -Dart_Handle Scene::toImageSync(uint32_t width, - uint32_t height, - Dart_Handle raw_image_handle) { - TRACE_EVENT0("flutter", "Scene::toImageSync"); - - if (!layer_tree_) { - return tonic::ToDart("Scene did not contain a layer tree."); - } - - auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height)); - if (!picture) { - return tonic::ToDart("Could not flatten scene into a layer tree."); - } - - Picture::RasterizeToImageSync(picture, width, height, raw_image_handle); - return Dart_Null(); -} - Dart_Handle Scene::toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { diff --git a/lib/ui/compositing/scene.h b/lib/ui/compositing/scene.h index d550eac484ab6..f7a8d93711814 100644 --- a/lib/ui/compositing/scene.h +++ b/lib/ui/compositing/scene.h @@ -32,10 +32,6 @@ class Scene : public RefCountedDartWrappable { std::unique_ptr takeLayerTree(); - Dart_Handle toImageSync(uint32_t width, - uint32_t height, - Dart_Handle raw_image_handle); - Dart_Handle toImage(uint32_t width, uint32_t height, Dart_Handle image_callback); diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 92fa4967a15b5..c0baaec260b79 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -5375,35 +5375,6 @@ class Picture extends NativeFieldWrapperClass1 { } String? _toImage(int width, int height, _Callback<_Image?> callback) native 'Picture_toImage'; - /// Synchronously creates a handle to an image of this picture. - /// - /// {@template dart.ui.painting.Picture.toImageSync} - /// The returned image will be `width` pixels wide and `height` pixels high. - /// The picture is rasterized within the 0 (left), 0 (top), `width` (right), - /// `height` (bottom) bounds. Content outside these bounds is clipped. - /// - /// The image object is created and returned synchronously, but is rasterized - /// asynchronously. If the rasterization fails, an exception will be thrown - /// when the image is drawn to a [Canvas]. - /// - /// If a GPU context is available, this image will be created as GPU resident - /// and not copied back to the host. This means the image will be more - /// efficient to draw. - /// - /// If no GPU context is availalbe, the image will be rasterized on the CPU. - /// {@endtemplate} - Image toImageSync(int width, int height) { - assert(!_disposed); - if (width <= 0 || height <= 0) { - throw Exception('Invalid image dimensions.'); - } - - final _Image image = _Image._(); - _toImageSync(width, height, image); - return Image._(image, image.width, image.height); - } - void _toImageSync(int width, int height, _Image outImage) native 'Picture_toImageSync'; - /// Release the resources used by this object. The object is no longer usable /// after this method is called. void dispose() { @@ -5912,7 +5883,7 @@ Future _futurize(_Callbacker callbacker) { } /// An exception thrown by [Canvas.drawImage] and related methods when drawing -/// an [Image] created via [Picture.toImageSync] that is in an invalid state. +/// an [Image] that is in an invalid state. /// /// This exception may be thrown if the requested image dimensions exceeded the /// maximum 2D texture size allowed by the GPU, or if no GPU surface or context diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 4ec907e093cdd..95564670a381d 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -23,7 +23,6 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Picture); #define FOR_EACH_BINDING(V) \ V(Picture, toImage) \ - V(Picture, toImageSync) \ V(Picture, dispose) \ V(Picture, GetAllocationSize) @@ -53,46 +52,6 @@ Dart_Handle Picture::toImage(uint32_t width, raw_image_callback); } -void Picture::toImageSync(uint32_t width, - uint32_t height, - Dart_Handle raw_image_handle) { - FML_DCHECK(display_list_.skia_object()); - RasterizeToImageSync(display_list_.skia_object(), width, height, - raw_image_handle); -} - -// static -void Picture::RasterizeToImageSync(sk_sp display_list, - uint32_t width, - uint32_t height, - Dart_Handle raw_image_handle) { - auto* dart_state = UIDartState::Current(); - auto unref_queue = dart_state->GetSkiaUnrefQueue(); - auto snapshot_delegate = dart_state->GetSnapshotDelegate(); - auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); - - auto image = CanvasImage::Create(); - auto dl_image = DlDeferredImageGPU::Make(SkISize::Make(width, height)); - image->set_image(dl_image); - - fml::TaskRunner::RunNowOrPostTask( - raster_task_runner, - [snapshot_delegate, unref_queue, dl_image = std::move(dl_image), - display_list = std::move(display_list)]() { - sk_sp sk_image; - std::string error; - std::tie(sk_image, error) = snapshot_delegate->MakeGpuImage( - display_list, dl_image->dimensions()); - if (sk_image) { - dl_image->set_image(std::move(sk_image)); - } else { - dl_image->set_error(std::move(error)); - } - }); - - image->AssociateWithDartWrapper(raw_image_handle); -} - void Picture::dispose() { display_list_.reset(); ClearDartWrapper(); diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index 92653e9123cd6..33e5cb5772cf4 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -37,21 +37,12 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); - void toImageSync(uint32_t width, - uint32_t height, - Dart_Handle raw_image_handle); - void dispose(); size_t GetAllocationSize() const override; static void RegisterNatives(tonic::DartLibraryNatives* natives); - static void RasterizeToImageSync(sk_sp display_list, - uint32_t width, - uint32_t height, - Dart_Handle raw_image_handle); - static Dart_Handle RasterizeToImage(sk_sp display_list, uint32_t width, uint32_t height, diff --git a/lib/web_ui/lib/canvas.dart b/lib/web_ui/lib/canvas.dart index c9359b6930781..995bc66299617 100644 --- a/lib/web_ui/lib/canvas.dart +++ b/lib/web_ui/lib/canvas.dart @@ -155,7 +155,6 @@ abstract class Canvas { abstract class Picture { Future toImage(int width, int height); - Image toImageSync(int width, int height); void dispose(); bool get debugDisposed; int get approximateBytesUsed; diff --git a/lib/web_ui/lib/compositing.dart b/lib/web_ui/lib/compositing.dart index 96c51cbeeecf4..de1e6cdbee255 100644 --- a/lib/web_ui/lib/compositing.dart +++ b/lib/web_ui/lib/compositing.dart @@ -6,7 +6,6 @@ part of ui; abstract class Scene { Future toImage(int width, int height); - Image toImageSync(int width, int height); void dispose(); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart index eb6d860a0e072..f0cbd4a12a545 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart @@ -25,12 +25,6 @@ class LayerScene implements ui.Scene { final ui.Picture picture = layerTree.flatten(); return picture.toImage(width, height); } - - @override - ui.Image toImageSync(int width, int height) { - final ui.Picture picture = layerTree.flatten(); - return picture.toImageSync(width, height); - } } class LayerSceneBuilder implements ui.SceneBuilder { diff --git a/lib/web_ui/lib/src/engine/canvaskit/picture.dart b/lib/web_ui/lib/src/engine/canvaskit/picture.dart index c2af7eb844e09..0227246be5157 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/picture.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/picture.dart @@ -92,11 +92,6 @@ class CkPicture extends ManagedSkiaObject implements ui.Picture { @override Future toImage(int width, int height) async { - return toImageSync(width, height); - } - - @override - ui.Image toImageSync(int width, int height) { assert(debugCheckNotDisposed('Cannot convert picture to image.')); final SkSurface skSurface = canvasKit.MakeSurface(width, height); final SkCanvas skCanvas = skSurface.getCanvas(); diff --git a/lib/web_ui/lib/src/engine/html/scene.dart b/lib/web_ui/lib/src/engine/html/scene.dart index 645390e28eaa0..7ae9a36d69096 100644 --- a/lib/web_ui/lib/src/engine/html/scene.dart +++ b/lib/web_ui/lib/src/engine/html/scene.dart @@ -24,11 +24,6 @@ class SurfaceScene implements ui.Scene { throw UnsupportedError('toImage is not supported on the Web'); } - @override - ui.Image toImageSync(int width, int height) { - throw UnsupportedError('toImageSync is not supported on the Web'); - } - /// Releases the resources used by this scene. /// /// After calling this function, the scene is cannot be used further. diff --git a/lib/web_ui/lib/src/engine/picture.dart b/lib/web_ui/lib/src/engine/picture.dart index dc432b2b9f34c..6cc68063c91bf 100644 --- a/lib/web_ui/lib/src/engine/picture.dart +++ b/lib/web_ui/lib/src/engine/picture.dart @@ -88,11 +88,6 @@ class EnginePicture implements ui.Picture { return onImageLoaded.future; } - @override - ui.Image toImageSync(int width, int height) { - throw UnsupportedError('toImageSync is not supported on the HTML backend. Use drawPicture instead, or toImage.'); - } - bool _disposed = false; @override diff --git a/lib/web_ui/test/canvaskit/picture_test.dart b/lib/web_ui/test/canvaskit/picture_test.dart index b082d13d6e260..59851bfc7c3bc 100644 --- a/lib/web_ui/test/canvaskit/picture_test.dart +++ b/lib/web_ui/test/canvaskit/picture_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:typed_data'; - import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; @@ -85,23 +83,6 @@ void testMain() { expect(picture.resurrect(), isNotNull); }); }); - - test('toImageSync', () async { - const ui.Color color = ui.Color(0xFFAAAAAA); - final ui.PictureRecorder recorder = ui.PictureRecorder(); - final ui.Canvas canvas = ui.Canvas(recorder); - canvas.drawPaint(ui.Paint()..color = color); - final ui.Picture picture = recorder.endRecording(); - final ui.Image image = picture.toImageSync(10, 15); - - expect(image.width, 10); - expect(image.height, 15); - - final ByteData? data = await image.toByteData(); - expect(data, isNotNull); - expect(data!.lengthInBytes, 10 * 15 * 4); - expect(data.buffer.asUint32List().first, color.value); - }); // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 }, skip: isIosSafari); } diff --git a/shell/common/fixtures/shell_test.dart b/shell/common/fixtures/shell_test.dart index b8908bdd24563..f9d526ae6db45 100644 --- a/shell/common/fixtures/shell_test.dart +++ b/shell/common/fixtures/shell_test.dart @@ -321,26 +321,3 @@ void scene_with_red_box() { }; PlatformDispatcher.instance.scheduleFrame(); } - - -@pragma('vm:entry-point') -Future toImageSync() async { - final PictureRecorder recorder = PictureRecorder(); - final Canvas canvas = Canvas(recorder); - canvas.drawPaint(Paint()..color = const Color(0xFFAAAAAA)); - final Picture picture = recorder.endRecording(); - - final Image image = picture.toImageSync(20, 25); - void expect(Object? a, Object? b) { - if (a != b) { - throw 'Expected $a to == $b'; - } - } - expect(image.width, 20); - expect(image.height, 25); - - final ByteData data = (await image.toByteData())!; - expect(data.lengthInBytes, 20 * 25 * 4); - expect(data.buffer.asUint32List().every((int byte) => byte == 0xFFAAAAAA), true); - notifyNative(); -} diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 23f91cdbda900..5b97ac0c27b46 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -3754,40 +3754,6 @@ TEST_F(ShellTest, SpawnWorksWithOnError) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } -TEST_F(ShellTest, PictureToImageSync) { -#if !SHELL_ENABLE_GL - // GL emulation does not exist on Fuchsia. - GTEST_SKIP(); -#endif // !SHELL_ENABLE_GL - auto settings = CreateSettingsForFixture(); - std::unique_ptr shell = - CreateShell(settings, // - GetTaskRunnersForFixture(), // - false, // - nullptr, // - false, // - ShellTestPlatformView::BackendType::kGLBackend // - ); - - fml::AutoResetWaitableEvent latch; - AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&latch](auto args) { - latch.Signal(); - })); - - ASSERT_NE(shell, nullptr); - ASSERT_TRUE(shell->IsSetup()); - auto configuration = RunConfiguration::InferFromSettings(settings); - PlatformViewNotifyCreated(shell.get()); - configuration.SetEntrypoint("toImageSync"); - RunEngine(shell.get(), std::move(configuration)); - PumpOneFrame(shell.get()); - - latch.Wait(); - - PlatformViewNotifyDestroyed(shell.get()); - DestroyShell(std::move(shell)); -} - } // namespace testing } // namespace flutter diff --git a/testing/dart/canvas_test.dart b/testing/dart/canvas_test.dart index 4de620f9750cd..c0bae43fb5f0a 100644 --- a/testing/dart/canvas_test.dart +++ b/testing/dart/canvas_test.dart @@ -410,103 +410,6 @@ void main() { expect(areEqual, true); }, skip: !Platform.isLinux); // https://github.com/flutter/flutter/issues/53784 - test('toImageSync - too big', () async { - PictureRecorder recorder = PictureRecorder(); - Canvas canvas = Canvas(recorder); - canvas.drawPaint(Paint()..color = const Color(0xFF123456)); - final Picture picture = recorder.endRecording(); - final Image image = picture.toImageSync(300000, 4000000); - picture.dispose(); - - expect(image.width, 300000); - expect(image.height, 4000000); - - recorder = PictureRecorder(); - canvas = Canvas(recorder); - - // On a slower CI machine, the raster thread may get behind the UI thread - // here. However, once the image is in an error state it will immediately - // throw on subsequent attempts. - bool caughtException = false; - for (int iterations = 0; iterations < 1000; iterations += 1) { - try { - canvas.drawImage(image, Offset.zero, Paint()); - } on PictureRasterizationException catch (e) { - caughtException = true; - expect(e.message, contains('unable to create render target at specified size')); - break; - } - // Let the event loop turn. - await Future.delayed(const Duration(milliseconds: 1)); - } - expect(caughtException, true); - expect( - () => canvas.drawImageRect(image, Rect.zero, Rect.zero, Paint()), - throwsException, - ); - expect( - () => canvas.drawImageNine(image, Rect.zero, Rect.zero, Paint()), - throwsException, - ); - expect( - () => canvas.drawAtlas(image, [], [], null, null, null, Paint()), - throwsException, - ); - }); - - test('toImageSync - succeeds', () async { - PictureRecorder recorder = PictureRecorder(); - Canvas canvas = Canvas(recorder); - canvas.drawPaint(Paint()..color = const Color(0xFF123456)); - final Picture picture = recorder.endRecording(); - final Image image = picture.toImageSync(30, 40); - picture.dispose(); - - expect(image.width, 30); - expect(image.height, 40); - - recorder = PictureRecorder(); - canvas = Canvas(recorder); - expect( - () => canvas.drawImage(image, Offset.zero, Paint()), - returnsNormally, - ); - expect( - () => canvas.drawImageRect(image, Rect.zero, Rect.zero, Paint()), - returnsNormally, - ); - expect( - () => canvas.drawImageNine(image, Rect.zero, Rect.zero, Paint()), - returnsNormally, - ); - expect( - () => canvas.drawAtlas(image, [], [], null, null, null, Paint()), - returnsNormally, - ); - }); - - test('toImageSync - toByteData', () async { - const Color color = Color(0xFF123456); - final PictureRecorder recorder = PictureRecorder(); - final Canvas canvas = Canvas(recorder); - canvas.drawPaint(Paint()..color = color); - final Picture picture = recorder.endRecording(); - final Image image = picture.toImageSync(6, 8); - picture.dispose(); - - expect(image.width, 6); - expect(image.height, 8); - - final ByteData? data = await image.toByteData(format: ImageByteFormat.rawRgba); - - expect(data, isNotNull); - expect(data!.lengthInBytes, 6 * 8 * 4); - expect(data.buffer.asUint8List()[0], 0x12); - expect(data.buffer.asUint8List()[1], 0x34); - expect(data.buffer.asUint8List()[2], 0x56); - expect(data.buffer.asUint8List()[3], 0xFF); - }); - test('Canvas.drawParagraph throws when Paragraph.layout was not called', () async { // Regression test for https://github.com/flutter/flutter/issues/97172 bool assertsEnabled = false; diff --git a/testing/dart/compositing_test.dart b/testing/dart/compositing_test.dart index 7815fa2aaaf57..69b147c2514ac 100644 --- a/testing/dart/compositing_test.dart +++ b/testing/dart/compositing_test.dart @@ -8,34 +8,6 @@ import 'dart:ui'; import 'package:litetest/litetest.dart'; void main() { - test('Scene.toImageSync succeeds', () async { - final PictureRecorder recorder = PictureRecorder(); - final Canvas canvas = Canvas(recorder); - const Color color = Color(0xFF123456); - canvas.drawPaint(Paint()..color = color); - final Picture picture = recorder.endRecording(); - final SceneBuilder builder = SceneBuilder(); - builder.pushOffset(10, 10); - builder.addPicture(const Offset(5, 5), picture); - final Scene scene = builder.build(); - - final Image image = scene.toImageSync(6, 8); - picture.dispose(); - scene.dispose(); - - expect(image.width, 6); - expect(image.height, 8); - - final ByteData? data = await image.toByteData(); - - expect(data, isNotNull); - expect(data!.lengthInBytes, 6 * 8 * 4); - expect(data.buffer.asUint8List()[0], 0x12); - expect(data.buffer.asUint8List()[1], 0x34); - expect(data.buffer.asUint8List()[2], 0x56); - expect(data.buffer.asUint8List()[3], 0xFF); - }); - test('addPicture with disposed picture does not crash', () { bool assertsEnabled = false; assert(() { diff --git a/testing/dart/image_shader_test.dart b/testing/dart/image_shader_test.dart index 56c502b132596..f34b91ae85315 100644 --- a/testing/dart/image_shader_test.dart +++ b/testing/dart/image_shader_test.dart @@ -16,20 +16,4 @@ void main() { const Rect rect = Rect.fromLTRB(0, 0, 100, 100); testCanvas((Canvas canvas) => canvas.drawRect(rect, paint)); }); - - test('Construct an ImageShader - GPU image', () async { - final PictureRecorder recorder = PictureRecorder(); - final Canvas canvas = Canvas(recorder); - canvas.drawPaint(Paint()..color = const Color(0xFFABCDEF)); - final Picture picture = recorder.endRecording(); - final Image image = picture.toImageSync(50, 50); - picture.dispose(); - - // TODO(dnfield): this should not throw once - // https://github.com/flutter/flutter/issues/105085 is fixed. - expect( - () => ImageShader(image, TileMode.clamp, TileMode.clamp, Float64List(16)), - throwsException, - ); - }); }