diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e1361dda517bd..6407cb3be713c 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1944,6 +1944,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.d ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface_factory.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/text.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/texture.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/util.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/vertices.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/clipboard.dart + ../../../flutter/LICENSE @@ -2066,6 +2067,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_action.dar ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_type.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/texture.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/util.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/validators.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/vector_math.dart + ../../../flutter/LICENSE @@ -4426,6 +4428,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dar FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface_factory.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/text.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/texture.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/util.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/vertices.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/clipboard.dart @@ -4548,6 +4551,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_action.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/input_type.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/texture.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/util.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/validators.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/vector_math.dart diff --git a/lib/web_ui/lib/initialization.dart b/lib/web_ui/lib/initialization.dart index 3cb2a8835242a..c161d249a6fc5 100644 --- a/lib/web_ui/lib/initialization.dart +++ b/lib/web_ui/lib/initialization.dart @@ -141,3 +141,32 @@ class PlatformViewRegistry { /// The platform view registry for this app. final PlatformViewRegistry platformViewRegistry = PlatformViewRegistry(); + +/// A registry for textures. +class TextureRegistry { + /// Registers a texture. + /// + /// Valid [texture] can be any object that that webGL's texImage2D supports. + /// For example, HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, + /// ImageData, ImageBitmap and VideoFrame. + /// + /// The returned id can be used to refer to the texture in Texture widgets. + int registerTexture(Object texture) { + return engine.renderer.textureRegistry?.registerTexture(texture) ?? -1; + } + + /// Unregisters the texture with the given id. + void unregisterTexture(int id) { + engine.renderer.textureRegistry?.unregisterTexture(id); + } + + /// Notifies Flutter that the content of the previously registered texture + /// has been updated. + void textureFrameAvailable(int id) { + engine.renderer.textureRegistry?.textureFrameAvailable(id); + engine.EnginePlatformDispatcher.instance.scheduleFrame(); + } +} + +/// The texture registry for this app. +final TextureRegistry textureRegistry = TextureRegistry(); diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index e86ffb97942ff..d32c826c63c70 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -53,6 +53,7 @@ export 'engine/canvaskit/skia_object_cache.dart'; export 'engine/canvaskit/surface.dart'; export 'engine/canvaskit/surface_factory.dart'; export 'engine/canvaskit/text.dart'; +export 'engine/canvaskit/texture.dart'; export 'engine/canvaskit/util.dart'; export 'engine/canvaskit/vertices.dart'; export 'engine/clipboard.dart'; @@ -168,6 +169,7 @@ export 'engine/text_editing/input_action.dart'; export 'engine/text_editing/input_type.dart'; export 'engine/text_editing/text_capitalization.dart'; export 'engine/text_editing/text_editing.dart'; +export 'engine/texture.dart'; export 'engine/util.dart'; export 'engine/validators.dart'; export 'engine/vector_math.dart'; diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart index e32ca5786dbd3..2082aa2da02da 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -140,7 +140,7 @@ extension CanvasKitExtension on CanvasKit { ); external SkImage? MakeLazyImageFromTextureSource( Object src, - SkPartialImageInfo info, + SkPartialImageInfo? info, ); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer.dart b/lib/web_ui/lib/src/engine/canvaskit/layer.dart index d8c98694ad1c4..118901ac7cab4 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer.dart @@ -13,6 +13,7 @@ import 'painting.dart'; import 'path.dart'; import 'picture.dart'; import 'raster_cache.dart'; +import 'texture.dart'; import 'util.dart'; /// A layer to be composed into a scene. @@ -87,6 +88,7 @@ class PaintContext { this.leafNodesCanvas, this.rasterCache, this.viewEmbedder, + this.textureRegistry, ); /// A multi-canvas that applies clips, transforms, and opacity @@ -102,6 +104,8 @@ class PaintContext { /// A compositor for embedded HTML views. final HtmlViewEmbedder? viewEmbedder; + + final CkTextureRegistry? textureRegistry; } /// A layer that contains child layers. @@ -616,3 +620,29 @@ class PlatformViewLayer extends Layer { } } } + +/// A layer which renders a texture backed by [textureId]. +class TextureLayer extends Layer { + TextureLayer(this.textureId, this.offset, this.width, this.height, + this.freeze, this.filterQuality); + + final int textureId; + final ui.Offset offset; + final double width; + final double height; + final bool freeze; + final ui.FilterQuality filterQuality; + + @override + void preroll(PrerollContext prerollContext, Matrix4 matrix) { + paintBounds = ui.Rect.fromLTWH(offset.dx, offset.dy, width, height); + } + + @override + void paint(PaintContext paintContext) { + final CkTexture? texture = + paintContext.textureRegistry?.getTexture(textureId); + + texture?.paint(paintContext, offset, width, height, freeze, filterQuality); + } +} 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 e1f71752e63c1..0949e09d3a2fa 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 @@ -72,7 +72,9 @@ class LayerSceneBuilder implements ui.SceneBuilder { bool freeze = false, ui.FilterQuality filterQuality = ui.FilterQuality.low, }) { - // TODO(hterkelsen): implement addTexture, b/128315641 + currentLayer.add( + TextureLayer(textureId, offset, width, height, freeze, filterQuality), + ); } @override diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart index 576e1b2533221..f22e673c302f0 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart @@ -13,6 +13,7 @@ import 'layer.dart'; import 'n_way_canvas.dart'; import 'picture_recorder.dart'; import 'raster_cache.dart'; +import 'texture.dart'; /// A tree of [Layer]s that, together with a [Size] compose a frame. class LayerTree { @@ -58,6 +59,7 @@ class LayerTree { frame.canvas, ignoreRasterCache ? null : frame.rasterCache, frame.viewEmbedder, + frame.textureRegistry, ); if (rootLayer.needsPainting) { rootLayer.paint(context); @@ -75,8 +77,13 @@ class LayerTree { final CkNWayCanvas internalNodesCanvas = CkNWayCanvas(); internalNodesCanvas.addCanvas(canvas); - final PaintContext paintContext = - PaintContext(internalNodesCanvas, canvas, null, null); + final PaintContext paintContext = PaintContext( + internalNodesCanvas, + canvas, + null, + null, + CkTextureRegistry.instance, + ); if (rootLayer.needsPainting) { rootLayer.paint(paintContext); } @@ -86,7 +93,7 @@ class LayerTree { /// A single frame to be rendered. class Frame { - Frame(this.canvas, this.rasterCache, this.viewEmbedder); + Frame(this.canvas, this.rasterCache, this.viewEmbedder, this.textureRegistry); /// The canvas to render this frame to. final CkCanvas canvas; @@ -97,6 +104,8 @@ class Frame { /// The platform view embedder. final HtmlViewEmbedder? viewEmbedder; + final CkTextureRegistry? textureRegistry; + /// Rasterize the given layer tree into this frame. bool raster(LayerTree layerTree, {bool ignoreRasterCache = false}) { timeAction(kProfilePrerollFrame, () { @@ -115,7 +124,11 @@ class CompositorContext { RasterCache? rasterCache; /// Acquire a frame using this compositor's settings. - Frame acquireFrame(CkCanvas canvas, HtmlViewEmbedder? viewEmbedder) { - return Frame(canvas, rasterCache, viewEmbedder); + Frame acquireFrame( + CkCanvas canvas, + HtmlViewEmbedder? viewEmbedder, + CkTextureRegistry? textureRegistry, + ) { + return Frame(canvas, rasterCache, viewEmbedder, textureRegistry); } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart index b8b420bb829a6..c728b7819c3ec 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart @@ -11,6 +11,7 @@ import 'embedded_views.dart'; import 'layer_tree.dart'; import 'surface.dart'; import 'surface_factory.dart'; +import 'texture.dart'; /// A class that can rasterize [LayerTree]s into a given [Surface]. class Rasterizer { @@ -33,8 +34,11 @@ class Rasterizer { SurfaceFactory.instance.baseSurface.acquireFrame(layerTree.frameSize); HtmlViewEmbedder.instance.frameSize = layerTree.frameSize; final CkCanvas canvas = frame.skiaCanvas; - final Frame compositorFrame = - context.acquireFrame(canvas, HtmlViewEmbedder.instance); + final Frame compositorFrame = context.acquireFrame( + canvas, + HtmlViewEmbedder.instance, + CkTextureRegistry.instance, + ); compositorFrame.raster(layerTree, ignoreRasterCache: true); SurfaceFactory.instance.baseSurface.addToScene(); diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index 800a7f4926814..1045d93b66f24 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -26,6 +26,7 @@ import 'picture_recorder.dart'; import 'rasterizer.dart'; import 'shader.dart'; import 'text.dart'; +import 'texture.dart'; import 'vertices.dart'; class CanvasKitRenderer implements Renderer { @@ -40,6 +41,9 @@ class CanvasKitRenderer implements Renderer { @override SkiaFontCollection get fontCollection => _fontCollection; + @override + final CkTextureRegistry textureRegistry = CkTextureRegistry.instance; + /// The scene host, where the root canvas and overlay canvases are added to. DomElement? _sceneHost; DomElement? get sceneHost => _sceneHost; diff --git a/lib/web_ui/lib/src/engine/canvaskit/texture.dart b/lib/web_ui/lib/src/engine/canvaskit/texture.dart new file mode 100644 index 0000000000000..acbf2435954d4 --- /dev/null +++ b/lib/web_ui/lib/src/engine/canvaskit/texture.dart @@ -0,0 +1,99 @@ +// 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:ui/ui.dart' as ui; + +import '../texture.dart'; +import 'canvaskit_api.dart'; +import 'image.dart'; +import 'layer.dart'; +import 'painting.dart'; + +class CkTexture { + CkTexture(this.source); + + final Object source; + + CkImage? _ckImage; + + bool _newFrameReady = false; + + final CkPaint _paint = CkPaint(); + + void markNewFrameAvailable() { + _newFrameReady = true; + } + + void paint( + PaintContext context, + ui.Offset offset, + double width, + double height, + bool freeze, + ui.FilterQuality filterQuality, + ) { + if (_ckImage == null || _newFrameReady && !freeze) { + final SkImage? skImage = + canvasKit.MakeLazyImageFromTextureSource(source, null); + + if (skImage == null) { + return; + } + + _ckImage?.dispose(); + _ckImage = CkImage(skImage); + } + + context.leafNodesCanvas?.drawImageRect( + _ckImage!, + ui.Rect.fromLTWH( + 0, + 0, + _ckImage!.width.toDouble(), + _ckImage!.height.toDouble(), + ), + ui.Rect.fromLTWH(offset.dx, offset.dy, width, height), + _paint..filterQuality = filterQuality, + ); + } + + void dispose() { + _ckImage?.dispose(); + } +} + +class CkTextureRegistry implements TextureRegistry { + CkTextureRegistry._(); + + static final CkTextureRegistry instance = CkTextureRegistry._(); + + final Map _textures = {}; + + int _nextTextureId = 0; + + @override + int registerTexture(Object source) { + final int id = _nextTextureId++; + _textures[id] = CkTexture(source); + return id; + } + + @override + void unregisterTexture(int id) { + final CkTexture? texture = _textures.remove(id); + texture?.dispose(); + } + + CkTexture? getTexture(int id) { + return _textures[id]; + } + + @override + void textureFrameAvailable(int id) { + final CkTexture? texture = _textures[id]; + if (texture != null) { + texture.markNewFrameAvailable(); + } + } +} diff --git a/lib/web_ui/lib/src/engine/html/renderer.dart b/lib/web_ui/lib/src/engine/html/renderer.dart index dd155f2fc0efb..74a48a9320193 100644 --- a/lib/web_ui/lib/src/engine/html/renderer.dart +++ b/lib/web_ui/lib/src/engine/html/renderer.dart @@ -23,6 +23,9 @@ class HtmlRenderer implements Renderer { @override HtmlFontCollection get fontCollection => _fontCollection; + @override + TextureRegistry? get textureRegistry => null; + @override void initialize() { scheduleMicrotask(() { diff --git a/lib/web_ui/lib/src/engine/renderer.dart b/lib/web_ui/lib/src/engine/renderer.dart index cc715bb510386..2db3a84da8a13 100644 --- a/lib/web_ui/lib/src/engine/renderer.dart +++ b/lib/web_ui/lib/src/engine/renderer.dart @@ -16,6 +16,7 @@ import 'fonts.dart'; import 'html/renderer.dart'; import 'html_image_codec.dart'; import 'skwasm/skwasm_stub/renderer.dart' if (dart.library.ffi) 'skwasm/skwasm_impl/renderer.dart'; +import 'texture.dart'; final Renderer _renderer = Renderer._internal(); Renderer get renderer => _renderer; @@ -49,6 +50,8 @@ abstract class Renderer { String get rendererTag; FontCollection get fontCollection; + TextureRegistry? get textureRegistry; + FutureOr initialize(); void reset(FlutterViewEmbedder embedder); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart index 00f3108af1b24..05c69f75892e2 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart @@ -12,6 +12,7 @@ import '../../embedder.dart'; import '../../fonts.dart'; import '../../html_image_codec.dart'; import '../../renderer.dart'; +import '../../texture.dart'; // TODO(jacksongardner): Actually implement skwasm renderer. class SkwasmRenderer implements Renderer { @@ -138,6 +139,9 @@ class SkwasmRenderer implements Renderer { @override FontCollection get fontCollection => throw UnimplementedError('Not yet implemented'); + @override + TextureRegistry? get textureRegistry => throw UnimplementedError('Not yet implemented'); + @override FutureOr initialize() { throw UnimplementedError('Not yet implemented'); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart index 4a3f5621c7e5c..3de52bcfc4a6d 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart @@ -12,6 +12,7 @@ import '../../embedder.dart'; import '../../fonts.dart'; import '../../html_image_codec.dart'; import '../../renderer.dart'; +import '../../texture.dart'; class SkwasmRenderer implements Renderer { @override @@ -137,6 +138,9 @@ class SkwasmRenderer implements Renderer { @override FontCollection get fontCollection => throw UnimplementedError('Skwasm not implemented on this platform.'); + @override + TextureRegistry? get textureRegistry => throw UnimplementedError('Skwasm not implemented on this platform.'); + @override FutureOr initialize() { throw UnimplementedError('Skwasm not implemented on this platform.'); diff --git a/lib/web_ui/lib/src/engine/texture.dart b/lib/web_ui/lib/src/engine/texture.dart new file mode 100644 index 0000000000000..0b8218eecd2c7 --- /dev/null +++ b/lib/web_ui/lib/src/engine/texture.dart @@ -0,0 +1,19 @@ +// 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. + +/// A collection of textures available to the engine. +abstract class TextureRegistry { + /// Registers a texture, returns an id that can be used to reference that + /// texture in subsequent calls. + int registerTexture(Object source); + + /// Unregisters a texture that was previously registered with + /// [registerTexture]. + void unregisterTexture(int id); + + /// Notifies Flutter that the content of the previously registered texture + /// has been updated. [id] is the id of the texture that was previously + /// returned by [registerTexture]. + void textureFrameAvailable(int id); +} diff --git a/lib/web_ui/test/canvaskit/texture_golden_test.dart b/lib/web_ui/test/canvaskit/texture_golden_test.dart new file mode 100644 index 0000000000000..145fd2a953586 --- /dev/null +++ b/lib/web_ui/test/canvaskit/texture_golden_test.dart @@ -0,0 +1,87 @@ +// 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 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; +import 'package:web_engine_tester/golden_tester.dart'; + +import 'common.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + group('CanvasKit Texture', () { + setUpCanvasKitTest(); + + setUp(() { + window.debugOverrideDevicePixelRatio(1); + }); + + test('can take an image as a texture', () async { + final DomHTMLImageElement image = createDomHTMLImageElement() + ..src = '/test_images/mandrill_128.png'; + + await _waitImageLoaded(image); + + final int textureId = ui.textureRegistry.registerTexture(image); + + final LayerSceneBuilder sb = LayerSceneBuilder(); + sb.pushOffset(0, 0); + sb.addTexture(textureId, width: 50, height: 50); + + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); + await matchGoldenFile( + 'canvaskit_texture_image.png', + region: const ui.Rect.fromLTRB(0, 0, 128, 128), + ); + }); + + test('can mark a texture as updated', () async { + final DomHTMLImageElement image = createDomHTMLImageElement() + ..src = '/test_images/mandrill_128.png'; + + await _waitImageLoaded(image); + + final DomCanvasElement canvas = createDomCanvasElement( + width: 128, + height: 128, + ); + + final int textureId = ui.textureRegistry.registerTexture(canvas); + + final LayerSceneBuilder sb = LayerSceneBuilder(); + sb.pushOffset(0, 0); + sb.addTexture(textureId, width: 128, height: 128); + + canvas.context2D.drawImage(image, 0, 0); + ui.textureRegistry.textureFrameAvailable(textureId); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); + + canvas.context2D.drawImage(image, 50, 50); + ui.textureRegistry.textureFrameAvailable(textureId); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); + + await matchGoldenFile( + 'canvaskit_texture_canvas.png', + region: const ui.Rect.fromLTRB(0, 0, 128, 128), + ); + }); + }); +} + +Future _waitImageLoaded(DomHTMLImageElement image) { + final Completer imageLoaded = Completer(); + + image.addEventListener('load', allowInterop((_) { + imageLoaded.complete(); + })); + + return imageLoaded.future; +} diff --git a/lib/web_ui/test/canvaskit/texture_test.dart b/lib/web_ui/test/canvaskit/texture_test.dart new file mode 100644 index 0000000000000..0e364929d21b4 --- /dev/null +++ b/lib/web_ui/test/canvaskit/texture_test.dart @@ -0,0 +1,60 @@ +// 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/src/engine.dart'; + +import 'common.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + group('$CkTextureRegistry', () { + setUpCanvasKitTest(); + + setUp(() { + window.debugOverrideDevicePixelRatio(1); + }); + + test('can register and unregister a texture', () async { + final CkTextureRegistry registry = CanvasKitRenderer.instance.textureRegistry; + + final DomHTMLImageElement image = createDomHTMLImageElement(); + final int id = registry.registerTexture(image); + + expect(id, isNotNull); + expect(registry.getTexture(id), isNotNull); + + registry.unregisterTexture(id); + expect(registry.getTexture(id), isNull); + }); + + test('can register multiple textures with different ids', () async { + final CkTextureRegistry registry = CanvasKitRenderer.instance.textureRegistry; + + final DomHTMLImageElement image1 = createDomHTMLImageElement(); + final int id1 = registry.registerTexture(image1); + + final DomHTMLImageElement image2 = createDomHTMLImageElement(); + final int id2 = registry.registerTexture(image2); + + expect(id1, isNotNull); + expect(id2, isNotNull); + expect(id2, isNot(id1)); + + registry.unregisterTexture(id1); + expect(registry.getTexture(id1), isNull); + + final DomHTMLImageElement image3 = createDomHTMLImageElement(); + final int id3 = registry.registerTexture(image3); + + expect(id3, isNotNull); + expect(id3, isNot(id1)); + expect(id3, isNot(id2)); + }); + }); +}