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

Commit be56e05

Browse files
authored
[canvaskit] read pixels back in Picture.toImage (#40004)
[canvaskit] read pixels back in Picture.toImage
1 parent 0f62c23 commit be56e05

File tree

2 files changed

+59
-22
lines changed

2 files changed

+59
-22
lines changed

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

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -100,28 +100,7 @@ class CkPicture extends ManagedSkiaObject<SkPicture> implements ui.Picture {
100100
}
101101

102102
@override
103-
ui.Image toImageSync(int width, int height) {
104-
SurfaceFactory.instance.baseSurface.ensureSurface();
105-
if (SurfaceFactory.instance.baseSurface.usingSoftwareBackend) {
106-
return toImageSyncSoftware(width, height);
107-
}
108-
return toImageSyncGPU(width, height);
109-
}
110-
111-
ui.Image toImageSyncGPU(int width, int height) {
112-
assert(debugCheckNotDisposed('Cannot convert picture to image.'));
113-
114-
final CkSurface ckSurface = SurfaceFactory.instance.baseSurface
115-
.createRenderTargetSurface(ui.Size(width.toDouble(), height.toDouble()));
116-
final CkCanvas ckCanvas = ckSurface.getCanvas();
117-
ckCanvas.clear(const ui.Color(0x00000000));
118-
ckCanvas.drawPicture(this);
119-
final SkImage skImage = ckSurface.surface.makeImageSnapshot();
120-
ckSurface.dispose();
121-
return CkImage(skImage);
122-
}
123-
124-
ui.Image toImageSyncSoftware(int width, int height) {
103+
CkImage toImageSync(int width, int height) {
125104
assert(debugCheckNotDisposed('Cannot convert picture to image.'));
126105

127106
final Surface surface = SurfaceFactory.instance.pictureToImageSurface;

lib/web_ui/test/canvaskit/canvas_golden_test.dart

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,64 @@ void testMain() {
828828
await matchGoldenFile('canvaskit_empty_scene.png',
829829
region: const ui.Rect.fromLTRB(0, 0, 100, 100));
830830
});
831+
832+
// Regression test for https://github.com/flutter/flutter/issues/121758
833+
test('resources used in temporary surfaces for Image.toByteData can cross to rendering overlays', () async {
834+
final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer;
835+
SurfaceFactory.instance.debugClear();
836+
837+
ui.platformViewRegistry.registerViewFactory(
838+
'test-platform-view',
839+
(int viewId) => createDomHTMLDivElement()..id = 'view-0',
840+
);
841+
await createPlatformView(0, 'test-platform-view');
842+
843+
CkPicture makeTextPicture(String text, ui.Offset offset) {
844+
final CkPictureRecorder recorder = CkPictureRecorder();
845+
final CkCanvas canvas = recorder.beginRecording(ui.Rect.largest);
846+
final CkParagraphBuilder builder = CkParagraphBuilder(CkParagraphStyle());
847+
builder.addText(text);
848+
final CkParagraph paragraph = builder.build();
849+
paragraph.layout(const ui.ParagraphConstraints(width: 100));
850+
canvas.drawRect(
851+
ui.Rect.fromLTWH(offset.dx, offset.dy, paragraph.width, paragraph.height).inflate(10),
852+
CkPaint()..color = const ui.Color(0xFF00FF00)
853+
);
854+
canvas.drawParagraph(paragraph, offset);
855+
return recorder.endRecording();
856+
}
857+
858+
CkPicture imageToPicture(CkImage image, ui.Offset offset) {
859+
final CkPictureRecorder recorder = CkPictureRecorder();
860+
final CkCanvas canvas = recorder.beginRecording(ui.Rect.largest);
861+
canvas.drawImage(image, offset, CkPaint());
862+
return recorder.endRecording();
863+
}
864+
865+
final CkPicture helloPicture = makeTextPicture('Hello', ui.Offset.zero);
866+
867+
final CkImage helloImage = helloPicture.toImageSync(100, 100);
868+
869+
// Calling toByteData is essential to hit the bug.
870+
await helloImage.toByteData(format: ui.ImageByteFormat.png);
871+
872+
final LayerSceneBuilder sb = LayerSceneBuilder();
873+
sb.pushOffset(0, 0);
874+
sb.addPicture(ui.Offset.zero, helloPicture);
875+
sb.addPlatformView(0, width: 10, height: 10);
876+
877+
// The image is rendered after the platform view so that it's rendered into
878+
// a separate surface, which is what triggers the bug. If the bug is present
879+
// the image will not appear on the UI.
880+
sb.addPicture(const ui.Offset(0, 50), imageToPicture(helloImage, ui.Offset.zero));
881+
sb.pop();
882+
883+
// The below line should not throw an error.
884+
rasterizer.draw(sb.build().layerTree);
885+
886+
await matchGoldenFile('cross_overlay_resources.png', region: const ui.Rect.fromLTRB(0, 0, 100, 100));
887+
});
888+
831889
// TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520
832890
}, skip: isSafari || isFirefox);
833891
}

0 commit comments

Comments
 (0)