Skip to content

Instantly share code, notes, and snippets.

@jonahwilliams
Created July 27, 2022 19:50
Show Gist options
  • Save jonahwilliams/dfb5ccc1d44affc0a013d879009fb849 to your computer and use it in GitHub Desktop.
Save jonahwilliams/dfb5ccc1d44affc0a013d879009fb849 to your computer and use it in GitHub Desktop.
diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart
index c815293abd..b5a0cb6e81 100644
--- a/lib/ui/compositing.dart
+++ b/lib/ui/compositing.dart
@@ -18,25 +18,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);
- }
-
- @FfiNative<Handle Function(Pointer<Void>, Uint32, Uint32, Handle)>('Scene::toImageSync')
- external String? _toImageSync(int width, int height, _Image outImage);
-
/// 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 734a67ef24..236adc20d9 100644
--- a/lib/ui/compositing/scene.cc
+++ b/lib/ui/compositing/scene.cc
@@ -60,24 +60,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 1cf95aad4e..93add4c751 100644
--- a/lib/ui/compositing/scene.h
+++ b/lib/ui/compositing/scene.h
@@ -28,10 +28,6 @@ class Scene : public RefCountedDartWrappable<Scene> {
std::unique_ptr<flutter::LayerTree> 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/dart_ui.cc b/lib/ui/dart_ui.cc
index 61d35c5cd2..2a16b323aa 100644
--- a/lib/ui/dart_ui.cc
+++ b/lib/ui/dart_ui.cc
@@ -251,7 +251,6 @@ typedef CanvasPath Path;
V(Picture, GetAllocationSize, 1) \
V(Picture, dispose, 1) \
V(Picture, toImage, 4) \
- V(Picture, toImageSync, 4) \
V(SceneBuilder, addPerformanceOverlay, 6) \
V(SceneBuilder, addPicture, 5) \
V(SceneBuilder, addPlatformView, 6) \
@@ -275,7 +274,6 @@ typedef CanvasPath Path;
V(SceneBuilder, setRasterizerTracingThreshold, 2) \
V(Scene, dispose, 1) \
V(Scene, toImage, 4) \
- V(Scene, toImageSync, 4) \
V(SemanticsUpdateBuilder, build, 2) \
V(SemanticsUpdateBuilder, updateCustomAction, 5) \
V(SemanticsUpdateBuilder, updateNode, 36) \
diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart
index 3336554b17..894e1ab103 100644
--- a/lib/ui/painting.dart
+++ b/lib/ui/painting.dart
@@ -5554,37 +5554,6 @@ class Picture extends NativeFieldWrapperClass1 {
@FfiNative<Handle Function(Pointer<Void>, Uint32, Uint32, Handle)>('Picture::toImage')
external String? _toImage(int width, int height, void Function(_Image?) callback);
- /// 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 available, 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);
- }
-
- @FfiNative<Void Function(Pointer<Void>, Uint32, Uint32, Handle)>('Picture::toImageSync')
- external void _toImageSync(int width, int height, _Image outImage);
-
/// Release the resources used by this object. The object is no longer usable
/// after this method is called.
void dispose() {
@@ -6121,30 +6090,3 @@ Future<T> _futurize<T>(_Callbacker<T> callbacker) {
throw Exception(error);
return completer.future;
}
-
-/// An exception thrown by [Canvas.drawImage] and related methods when drawing
-/// an [Image] created via [Picture.toImageSync] 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
-/// was available for rasterization at request time.
-class PictureRasterizationException implements Exception {
- const PictureRasterizationException._(this.message, {this.stack});
-
- /// A string containing details about the failure.
- final String message;
-
- /// If available, the stack trace at the time [Picture.toImageSync] was called.
- final StackTrace? stack;
-
- @override
- String toString() {
- final StringBuffer buffer = StringBuffer('Failed to rasterize a picture: $message.');
- if (stack != null) {
- buffer.writeln();
- buffer.writeln('The callstack when the image was created was:');
- buffer.writeln(stack!.toString());
- }
- return buffer.toString();
- }
-}
diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc
index 2869c3fc77..ebcef9ca41 100644
--- a/lib/ui/painting/picture.cc
+++ b/lib/ui/painting/picture.cc
@@ -45,46 +45,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<DisplayList> 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<SkImage> 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 1cb390a182..4353aa0ebf 100644
--- a/lib/ui/painting/picture.h
+++ b/lib/ui/painting/picture.h
@@ -33,19 +33,10 @@ class Picture : public RefCountedDartWrappable<Picture> {
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 RasterizeToImageSync(sk_sp<DisplayList> display_list,
- uint32_t width,
- uint32_t height,
- Dart_Handle raw_image_handle);
-
static Dart_Handle RasterizeToImage(sk_sp<DisplayList> 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 c9359b6930..995bc66299 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<Image> 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 96c51cbeee..de1e6cdbee 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<Image> 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 eb6d860a0e..f0cbd4a12a 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 c2af7eb844..0227246be5 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<SkPicture> implements ui.Picture {
@override
Future<ui.Image> 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 645390e28e..7ae9a36d69 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 dc432b2b9f..6cc68063c9 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 b082d13d6e..419222f41d 100644
--- a/lib/web_ui/test/canvaskit/picture_test.dart
+++ b/lib/web_ui/test/canvaskit/picture_test.dart
@@ -85,23 +85,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 b8908bdd24..f9d526ae6d 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<void> 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 e4a86b5775..d676ba8270 100644
--- a/shell/common/shell_unittests.cc
+++ b/shell/common/shell_unittests.cc
@@ -3763,40 +3763,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> 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 4de620f975..c0bae43fb5 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<void>.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, <RSTransform>[], <Rect>[], 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, <RSTransform>[], <Rect>[], 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 7815fa2aaa..69b147c251 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 56c502b132..f34b91ae85 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,
- );
- });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment