From 66ddb4273f0c64789325181ba9671280c610bdc4 Mon Sep 17 00:00:00 2001 From: Benson Luk <97480502+b-luk@users.noreply.github.com> Date: Mon, 31 Jan 2022 21:50:31 +0000 Subject: [PATCH 1/8] Use H5vcc CanvasKit implementation if it is detected. --- .../src/engine/canvaskit/canvaskit_api.dart | 26 +++++++++++++++++++ .../src/engine/canvaskit/initialization.dart | 7 +++++ .../lib/src/engine/canvaskit/surface.dart | 7 +++++ 3 files changed, 40 insertions(+) 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 d5fcf7c2b660a..afdd2f73ffe1c 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -25,6 +25,14 @@ import '../profiler.dart'; /// Entrypoint into the CanvasKit API. late CanvasKit canvasKit; +/// Whether to use a CanvasKit implementation provided by a JavaScript +/// `window.h5vcc.canvasKit` object. +/// +/// Cobalt may use this object to expose a native implementation of the +/// CanvasKit bindings. If this exists, use it instead of using the normal +/// downloaded CanvasKit library. +final bool useH5vccCanvasKit = h5vcc != null; + /// Sets the [CanvasKit] object on `window` so we can use `@JS()` to bind to /// static APIs. /// @@ -39,6 +47,15 @@ external set windowFlutterCanvasKit(CanvasKit? value); @JS('window.flutterCanvasKit') external CanvasKit? get windowFlutterCanvasKit; +@JS('window.h5vcc') +external H5vcc? get h5vcc; + +@JS() +@anonymous +abstract class H5vcc { + external CanvasKit? get canvasKit; +} + @JS() @anonymous class CanvasKit { @@ -132,6 +149,15 @@ class CanvasKit { Object src, SkPartialImageInfo info, ); + + /// Gets a Skia surface from Cobalt's h5vcc object. + /// + /// This is only applicable when running on Cobalt and when using Cobalt's + /// h5vcc CanvasKit bindings. + /// + /// On Cobalt, this is the only way to get a Skia surface. Other CanvasKit + /// Make...Surface methods are not supported. + external SkSurface getH5vccSkSurface(); } @JS('window.CanvasKitInit') diff --git a/lib/web_ui/lib/src/engine/canvaskit/initialization.dart b/lib/web_ui/lib/src/engine/canvaskit/initialization.dart index 1185bf7968d81..f1157291fcde5 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/initialization.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/initialization.dart @@ -13,6 +13,7 @@ import '../embedder.dart'; import '../safe_browser_api.dart'; import 'canvaskit_api.dart'; import 'fonts.dart'; +import 'util.dart'; /// Whether to use CanvasKit as the rendering backend. final bool useCanvasKit = FlutterConfiguration.flutterWebAutoDetect @@ -47,6 +48,12 @@ String canvasKitWasmModuleUrl(String canvasKitBase, String file) => Future initializeCanvasKit({String? canvasKitBase}) async { if (windowFlutterCanvasKit != null) { canvasKit = windowFlutterCanvasKit!; + } else if (useH5vccCanvasKit) { + if (h5vcc?.canvasKit == null) { + throw CanvasKitError('H5vcc CanvasKit implementation not found.'); + } + canvasKit = h5vcc!.canvasKit!; + windowFlutterCanvasKit = canvasKit; } else { canvasKit = await downloadCanvasKit(canvasKitBase: canvasKitBase); windowFlutterCanvasKit = canvasKit; diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index 20e41adbdb9de..91ba89d53fd15 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -137,6 +137,13 @@ class Surface { /// Creates a and SkSurface for the given [size]. CkSurface createOrUpdateSurface(ui.Size size) { + if (useH5vccCanvasKit) { + if (_surface == null) { + _surface = CkSurface(canvasKit.getH5vccSkSurface(), null); + } + return _surface!; + } + if (size.isEmpty) { throw CanvasKitError('Cannot create surfaces of empty size.'); } From fc0ab527ec6193f100e288a98885fec7a71a5e2b Mon Sep 17 00:00:00 2001 From: Benson Luk <97480502+b-luk@users.noreply.github.com> Date: Tue, 1 Feb 2022 19:34:05 +0000 Subject: [PATCH 2/8] Use `??=` over testing for null. --- lib/web_ui/lib/src/engine/canvaskit/surface.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index 91ba89d53fd15..f0e8a149574e0 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -138,9 +138,7 @@ class Surface { /// Creates a and SkSurface for the given [size]. CkSurface createOrUpdateSurface(ui.Size size) { if (useH5vccCanvasKit) { - if (_surface == null) { - _surface = CkSurface(canvasKit.getH5vccSkSurface(), null); - } + _surface ??= CkSurface(canvasKit.getH5vccSkSurface(), null); return _surface!; } From 4b3fdd8bf7e91fe73e0265007716a8f2bb67bea5 Mon Sep 17 00:00:00 2001 From: Benson Luk <97480502+b-luk@users.noreply.github.com> Date: Wed, 2 Feb 2022 10:43:36 +0000 Subject: [PATCH 3/8] Add tests exercising a monkey-patched h5vcc implementation. --- .../src/engine/canvaskit/canvaskit_api.dart | 5 +- .../src/engine/canvaskit/initialization.dart | 4 ++ .../lib/src/engine/canvaskit/surface.dart | 1 + lib/web_ui/test/canvaskit/common.dart | 60 +++++++++++++++++++ .../test/canvaskit/initialization_test.dart | 13 ++++ lib/web_ui/test/canvaskit/surface_test.dart | 16 +++++ 6 files changed, 98 insertions(+), 1 deletion(-) 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 afdd2f73ffe1c..90709aa9f407e 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -31,7 +31,7 @@ late CanvasKit canvasKit; /// Cobalt may use this object to expose a native implementation of the /// CanvasKit bindings. If this exists, use it instead of using the normal /// downloaded CanvasKit library. -final bool useH5vccCanvasKit = h5vcc != null; +bool get useH5vccCanvasKit => h5vcc != null; /// Sets the [CanvasKit] object on `window` so we can use `@JS()` to bind to /// static APIs. @@ -50,6 +50,9 @@ external CanvasKit? get windowFlutterCanvasKit; @JS('window.h5vcc') external H5vcc? get h5vcc; +@JS('window.h5vcc') +external set debugH5vccSetter(H5vcc? value); + @JS() @anonymous abstract class H5vcc { diff --git a/lib/web_ui/lib/src/engine/canvaskit/initialization.dart b/lib/web_ui/lib/src/engine/canvaskit/initialization.dart index f1157291fcde5..3d275b66f065d 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/initialization.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/initialization.dart @@ -107,6 +107,10 @@ Future _downloadCanvasKitJs({String? canvasKitBase}) { SkiaFontCollection get skiaFontCollection => _skiaFontCollection!; SkiaFontCollection? _skiaFontCollection; +void debugSetSkiaFontCollection(SkiaFontCollection? value) { + _skiaFontCollection = value; +} + /// Initializes [skiaFontCollection]. void ensureSkiaFontCollectionInitialized() { _skiaFontCollection ??= SkiaFontCollection(); diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index f0e8a149574e0..38a128f9a6f47 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -137,6 +137,7 @@ class Surface { /// Creates a and SkSurface for the given [size]. CkSurface createOrUpdateSurface(ui.Size size) { + print('createOrUpdateSurface useH5vccCanvasKit is $useH5vccCanvasKit'); if (useH5vccCanvasKit) { _surface ??= CkSurface(canvasKit.getH5vccSkSurface(), null); return _surface!; diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index f062719bce2da..a33d14ba4e26c 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:js' as js; import 'package:test/test.dart'; @@ -245,3 +246,62 @@ CkParagraph makeSimpleText(String text, { paragraph.layout(const ui.ParagraphConstraints(width: 10000)); return paragraph; } + +class _PatchedH5vcc implements H5vcc { + @override + final CanvasKit canvasKit; + + _PatchedH5vcc(this.canvasKit); +} + +/// Test setup to initialize `window.h5vcc` with a patched H5vcc implementation. +/// +/// The patched H5vcc implementation uses a downloaded CanvasKit implementation +/// monkey-patched with a fake getH5vccSkSurface function. +/// +/// This function should be called before initialization, i.e. before +/// [setUpCanvasKitTest]. +void patchH5vccCanvasKit({Function? onGetH5vccSkSurfaceCalled}) { + CanvasKit? existingCanvasKit; + SkiaFontCollection? existingSkiaFontCollection; + + setUpAll(() async { + // Clear out any existing windowFlutterCanvasKit. This ensures that in the + // call to [initializeCanvasKit], no cached value is used. + existingCanvasKit = windowFlutterCanvasKit; + windowFlutterCanvasKit = null; + + // Clear out any existing skiaFontCollection. If a SkiaFontCollection was + // previously initialized with a non-h5vcc-patched CanvasKit, it is + // incompatible with the h5vcc-patched CanvasKit we create in this function. + // The next call to [ensureSkiaFontCollectionInitialized] will create a new + // SkiaFontCollection. + existingSkiaFontCollection = skiaFontCollection; + debugSetSkiaFontCollection(null); + + // Set `window.h5vcc` to _PatchedH5vcc which uses a downloaded CanvasKit. + final CanvasKit downloadedCanvasKit = await downloadCanvasKit(); + debugH5vccSetter = _PatchedH5vcc(downloadedCanvasKit); + + // Monkey-patch the getH5vccSkSurface function of `window.h5vcc.canvasKit`. + js.context['h5vcc']['canvasKit']['getH5vccSkSurface'] = () { + if (onGetH5vccSkSurfaceCalled != null) { + onGetH5vccSkSurfaceCalled(); + } + + // Returns a fake [SkSurface] object with a minimal implementation. + return js.JsObject.jsify({ + 'dispose': () {} + }); + }; + }); + + tearDownAll(() { + // Unset `window.h5vcc`. + debugH5vccSetter = null; + + // Reset original windowFlutterCanvasKit and skiaFontCollection values. + windowFlutterCanvasKit = existingCanvasKit; + debugSetSkiaFontCollection(existingSkiaFontCollection); + }); +} diff --git a/lib/web_ui/test/canvaskit/initialization_test.dart b/lib/web_ui/test/canvaskit/initialization_test.dart index 0a1a9c89a0d31..abd0a4242abf3 100644 --- a/lib/web_ui/test/canvaskit/initialization_test.dart +++ b/lib/web_ui/test/canvaskit/initialization_test.dart @@ -25,5 +25,18 @@ void testMain() { expect(html.document.body!.attributes['flt-build-mode'], 'debug'); }); // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 + + test('does not include getH5vccSkSurface', () { + expect(canvasKit.getH5vccSkSurface, isNull); + }, testOn: 'chrome'); }, skip: isIosSafari); + + group('Patched h5vcc CanvasKit', () { + patchH5vccCanvasKit(); + setUpCanvasKitTest(); + + test('includes patched getH5vccSkSurface', () { + expect(canvasKit.getH5vccSkSurface, isNotNull); + }); + }, testOn: 'chrome'); } diff --git a/lib/web_ui/test/canvaskit/surface_test.dart b/lib/web_ui/test/canvaskit/surface_test.dart index 8c0fccb473190..089b9a84cf389 100644 --- a/lib/web_ui/test/canvaskit/surface_test.dart +++ b/lib/web_ui/test/canvaskit/surface_test.dart @@ -180,4 +180,20 @@ void testMain() { expect(surface.htmlCanvas!.style.height, '32px'); }); }, skip: isIosSafari); + + group('with H5vcc', () { + int getH5vccSkSurfaceCalledCount = 0; + + patchH5vccCanvasKit(onGetH5vccSkSurfaceCalled: () { + getH5vccSkSurfaceCalledCount++; + }); + setUpCanvasKitTest(); + + test('Surface acquireFrame uses getH5vccSkSurface', () { + final Surface surface = SurfaceFactory.instance.getSurface(); + surface.acquireFrame(ui.Size.zero); + expect(getH5vccSkSurfaceCalledCount, 1); + }); + }, testOn: 'chrome'); + } From 503f21cc5a743ddd0f53f774b9f05168c4c226ea Mon Sep 17 00:00:00 2001 From: Benson Luk <97480502+b-luk@users.noreply.github.com> Date: Wed, 2 Feb 2022 10:49:47 +0000 Subject: [PATCH 4/8] Remove debugging print statement. --- lib/web_ui/lib/src/engine/canvaskit/surface.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index 38a128f9a6f47..f0e8a149574e0 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -137,7 +137,6 @@ class Surface { /// Creates a and SkSurface for the given [size]. CkSurface createOrUpdateSurface(ui.Size size) { - print('createOrUpdateSurface useH5vccCanvasKit is $useH5vccCanvasKit'); if (useH5vccCanvasKit) { _surface ??= CkSurface(canvasKit.getH5vccSkSurface(), null); return _surface!; From 0343783e5b4f2cc597d66c2aeb1a63ac22034c61 Mon Sep 17 00:00:00 2001 From: Benson Luk <97480502+b-luk@users.noreply.github.com> Date: Thu, 3 Feb 2022 19:47:21 +0000 Subject: [PATCH 5/8] Move h5vcc tests to new file. --- .../src/engine/canvaskit/canvaskit_api.dart | 2 +- .../src/engine/canvaskit/initialization.dart | 4 -- lib/web_ui/test/canvaskit/common.dart | 22 ---------- lib/web_ui/test/canvaskit/h5vcc_test.dart | 43 +++++++++++++++++++ .../test/canvaskit/initialization_test.dart | 9 ---- lib/web_ui/test/canvaskit/surface_test.dart | 16 ------- 6 files changed, 44 insertions(+), 52 deletions(-) create mode 100644 lib/web_ui/test/canvaskit/h5vcc_test.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 90709aa9f407e..05c55d2c15561 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -31,7 +31,7 @@ late CanvasKit canvasKit; /// Cobalt may use this object to expose a native implementation of the /// CanvasKit bindings. If this exists, use it instead of using the normal /// downloaded CanvasKit library. -bool get useH5vccCanvasKit => h5vcc != null; +final bool useH5vccCanvasKit = h5vcc != null; /// Sets the [CanvasKit] object on `window` so we can use `@JS()` to bind to /// static APIs. diff --git a/lib/web_ui/lib/src/engine/canvaskit/initialization.dart b/lib/web_ui/lib/src/engine/canvaskit/initialization.dart index 3d275b66f065d..f1157291fcde5 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/initialization.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/initialization.dart @@ -107,10 +107,6 @@ Future _downloadCanvasKitJs({String? canvasKitBase}) { SkiaFontCollection get skiaFontCollection => _skiaFontCollection!; SkiaFontCollection? _skiaFontCollection; -void debugSetSkiaFontCollection(SkiaFontCollection? value) { - _skiaFontCollection = value; -} - /// Initializes [skiaFontCollection]. void ensureSkiaFontCollectionInitialized() { _skiaFontCollection ??= SkiaFontCollection(); diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index a33d14ba4e26c..c05b9e158d448 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -266,19 +266,6 @@ void patchH5vccCanvasKit({Function? onGetH5vccSkSurfaceCalled}) { SkiaFontCollection? existingSkiaFontCollection; setUpAll(() async { - // Clear out any existing windowFlutterCanvasKit. This ensures that in the - // call to [initializeCanvasKit], no cached value is used. - existingCanvasKit = windowFlutterCanvasKit; - windowFlutterCanvasKit = null; - - // Clear out any existing skiaFontCollection. If a SkiaFontCollection was - // previously initialized with a non-h5vcc-patched CanvasKit, it is - // incompatible with the h5vcc-patched CanvasKit we create in this function. - // The next call to [ensureSkiaFontCollectionInitialized] will create a new - // SkiaFontCollection. - existingSkiaFontCollection = skiaFontCollection; - debugSetSkiaFontCollection(null); - // Set `window.h5vcc` to _PatchedH5vcc which uses a downloaded CanvasKit. final CanvasKit downloadedCanvasKit = await downloadCanvasKit(); debugH5vccSetter = _PatchedH5vcc(downloadedCanvasKit); @@ -295,13 +282,4 @@ void patchH5vccCanvasKit({Function? onGetH5vccSkSurfaceCalled}) { }); }; }); - - tearDownAll(() { - // Unset `window.h5vcc`. - debugH5vccSetter = null; - - // Reset original windowFlutterCanvasKit and skiaFontCollection values. - windowFlutterCanvasKit = existingCanvasKit; - debugSetSkiaFontCollection(existingSkiaFontCollection); - }); } diff --git a/lib/web_ui/test/canvaskit/h5vcc_test.dart b/lib/web_ui/test/canvaskit/h5vcc_test.dart new file mode 100644 index 0000000000000..846e2ff57ee39 --- /dev/null +++ b/lib/web_ui/test/canvaskit/h5vcc_test.dart @@ -0,0 +1,43 @@ +// 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 'package:ui/ui.dart' as ui; + +import 'common.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + group('H5vcc patched CanvasKit', () { + int getH5vccSkSurfaceCalledCount = 0; + + patchH5vccCanvasKit(onGetH5vccSkSurfaceCalled: () { + getH5vccSkSurfaceCalledCount++; + }); + setUpCanvasKitTest(); + + setUp(() { + getH5vccSkSurfaceCalledCount = 0; + }); + + test('sets useH5vccCanvasKit', () { + expect(useH5vccCanvasKit, true); + }); + + test('API includes patched getH5vccSkSurface', () { + expect(canvasKit.getH5vccSkSurface, isNotNull); + }); + + test('Surface scquireFrame uses getH5vccSkSurface', () { + final Surface surface = SurfaceFactory.instance.getSurface(); + surface.acquireFrame(ui.Size.zero); + expect(getH5vccSkSurfaceCalledCount, 1); + }); + }, testOn: 'chrome'); +} diff --git a/lib/web_ui/test/canvaskit/initialization_test.dart b/lib/web_ui/test/canvaskit/initialization_test.dart index abd0a4242abf3..1ebb5537a13b4 100644 --- a/lib/web_ui/test/canvaskit/initialization_test.dart +++ b/lib/web_ui/test/canvaskit/initialization_test.dart @@ -30,13 +30,4 @@ void testMain() { expect(canvasKit.getH5vccSkSurface, isNull); }, testOn: 'chrome'); }, skip: isIosSafari); - - group('Patched h5vcc CanvasKit', () { - patchH5vccCanvasKit(); - setUpCanvasKitTest(); - - test('includes patched getH5vccSkSurface', () { - expect(canvasKit.getH5vccSkSurface, isNotNull); - }); - }, testOn: 'chrome'); } diff --git a/lib/web_ui/test/canvaskit/surface_test.dart b/lib/web_ui/test/canvaskit/surface_test.dart index 089b9a84cf389..8c0fccb473190 100644 --- a/lib/web_ui/test/canvaskit/surface_test.dart +++ b/lib/web_ui/test/canvaskit/surface_test.dart @@ -180,20 +180,4 @@ void testMain() { expect(surface.htmlCanvas!.style.height, '32px'); }); }, skip: isIosSafari); - - group('with H5vcc', () { - int getH5vccSkSurfaceCalledCount = 0; - - patchH5vccCanvasKit(onGetH5vccSkSurfaceCalled: () { - getH5vccSkSurfaceCalledCount++; - }); - setUpCanvasKitTest(); - - test('Surface acquireFrame uses getH5vccSkSurface', () { - final Surface surface = SurfaceFactory.instance.getSurface(); - surface.acquireFrame(ui.Size.zero); - expect(getH5vccSkSurfaceCalledCount, 1); - }); - }, testOn: 'chrome'); - } From b0ec882f4fe02c59c1338839f5ebc2473dd3af02 Mon Sep 17 00:00:00 2001 From: Benson Luk <97480502+b-luk@users.noreply.github.com> Date: Thu, 3 Feb 2022 23:35:22 +0000 Subject: [PATCH 6/8] Move patchH5vccCanvasKit from common.dart to h5vcc_test.dart since it's only used there. Remove test in initialization_test.dart. --- lib/web_ui/test/canvaskit/common.dart | 38 ------------------- lib/web_ui/test/canvaskit/h5vcc_test.dart | 36 ++++++++++++++++++ .../test/canvaskit/initialization_test.dart | 4 -- 3 files changed, 36 insertions(+), 42 deletions(-) diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index c05b9e158d448..f062719bce2da 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:js' as js; import 'package:test/test.dart'; @@ -246,40 +245,3 @@ CkParagraph makeSimpleText(String text, { paragraph.layout(const ui.ParagraphConstraints(width: 10000)); return paragraph; } - -class _PatchedH5vcc implements H5vcc { - @override - final CanvasKit canvasKit; - - _PatchedH5vcc(this.canvasKit); -} - -/// Test setup to initialize `window.h5vcc` with a patched H5vcc implementation. -/// -/// The patched H5vcc implementation uses a downloaded CanvasKit implementation -/// monkey-patched with a fake getH5vccSkSurface function. -/// -/// This function should be called before initialization, i.e. before -/// [setUpCanvasKitTest]. -void patchH5vccCanvasKit({Function? onGetH5vccSkSurfaceCalled}) { - CanvasKit? existingCanvasKit; - SkiaFontCollection? existingSkiaFontCollection; - - setUpAll(() async { - // Set `window.h5vcc` to _PatchedH5vcc which uses a downloaded CanvasKit. - final CanvasKit downloadedCanvasKit = await downloadCanvasKit(); - debugH5vccSetter = _PatchedH5vcc(downloadedCanvasKit); - - // Monkey-patch the getH5vccSkSurface function of `window.h5vcc.canvasKit`. - js.context['h5vcc']['canvasKit']['getH5vccSkSurface'] = () { - if (onGetH5vccSkSurfaceCalled != null) { - onGetH5vccSkSurfaceCalled(); - } - - // Returns a fake [SkSurface] object with a minimal implementation. - return js.JsObject.jsify({ - 'dispose': () {} - }); - }; - }); -} diff --git a/lib/web_ui/test/canvaskit/h5vcc_test.dart b/lib/web_ui/test/canvaskit/h5vcc_test.dart index 846e2ff57ee39..d969ee236947a 100644 --- a/lib/web_ui/test/canvaskit/h5vcc_test.dart +++ b/lib/web_ui/test/canvaskit/h5vcc_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:js' as js; + import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; @@ -41,3 +43,37 @@ void testMain() { }); }, testOn: 'chrome'); } + +class PatchedH5vcc implements H5vcc { + @override + final CanvasKit canvasKit; + + PatchedH5vcc(this.canvasKit); +} + +/// Test setup to initialize `window.h5vcc` with a patched H5vcc implementation. +/// +/// The patched H5vcc implementation uses a downloaded CanvasKit implementation +/// monkey-patched with a fake getH5vccSkSurface function. +void patchH5vccCanvasKit({Function? onGetH5vccSkSurfaceCalled}) { + CanvasKit? existingCanvasKit; + SkiaFontCollection? existingSkiaFontCollection; + + setUpAll(() async { + // Set `window.h5vcc` to PatchedH5vcc which uses a downloaded CanvasKit. + final CanvasKit downloadedCanvasKit = await downloadCanvasKit(); + debugH5vccSetter = PatchedH5vcc(downloadedCanvasKit); + + // Monkey-patch the getH5vccSkSurface function of `window.h5vcc.canvasKit`. + js.context['h5vcc']['canvasKit']['getH5vccSkSurface'] = () { + if (onGetH5vccSkSurfaceCalled != null) { + onGetH5vccSkSurfaceCalled(); + } + + // Returns a fake [SkSurface] object with a minimal implementation. + return js.JsObject.jsify({ + 'dispose': () {} + }); + }; + }); +} diff --git a/lib/web_ui/test/canvaskit/initialization_test.dart b/lib/web_ui/test/canvaskit/initialization_test.dart index 1ebb5537a13b4..0a1a9c89a0d31 100644 --- a/lib/web_ui/test/canvaskit/initialization_test.dart +++ b/lib/web_ui/test/canvaskit/initialization_test.dart @@ -25,9 +25,5 @@ void testMain() { expect(html.document.body!.attributes['flt-build-mode'], 'debug'); }); // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - - test('does not include getH5vccSkSurface', () { - expect(canvasKit.getH5vccSkSurface, isNull); - }, testOn: 'chrome'); }, skip: isIosSafari); } From 41416c1b49f7c3b405dabd4b6166b16d9b7bef8c Mon Sep 17 00:00:00 2001 From: Benson Luk <97480502+b-luk@users.noreply.github.com> Date: Fri, 4 Feb 2022 00:00:33 +0000 Subject: [PATCH 7/8] Move h5vcc monkey patching out of its separate function. --- lib/web_ui/test/canvaskit/h5vcc_test.dart | 45 ++++++++--------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/lib/web_ui/test/canvaskit/h5vcc_test.dart b/lib/web_ui/test/canvaskit/h5vcc_test.dart index d969ee236947a..174213fdc3735 100644 --- a/lib/web_ui/test/canvaskit/h5vcc_test.dart +++ b/lib/web_ui/test/canvaskit/h5vcc_test.dart @@ -19,9 +19,23 @@ void testMain() { group('H5vcc patched CanvasKit', () { int getH5vccSkSurfaceCalledCount = 0; - patchH5vccCanvasKit(onGetH5vccSkSurfaceCalled: () { - getH5vccSkSurfaceCalledCount++; + setUpAll(() async { + // Set `window.h5vcc` to PatchedH5vcc which uses a downloaded CanvasKit. + final CanvasKit downloadedCanvasKit = await downloadCanvasKit(); + debugH5vccSetter = PatchedH5vcc(downloadedCanvasKit); + + // Monkey-patch the getH5vccSkSurface function of + // `window.h5vcc.canvasKit`. + js.context['h5vcc']['canvasKit']['getH5vccSkSurface'] = () { + getH5vccSkSurfaceCalledCount++; + + // Returns a fake [SkSurface] object with a minimal implementation. + return js.JsObject.jsify({ + 'dispose': () {} + }); + }; }); + setUpCanvasKitTest(); setUp(() { @@ -50,30 +64,3 @@ class PatchedH5vcc implements H5vcc { PatchedH5vcc(this.canvasKit); } - -/// Test setup to initialize `window.h5vcc` with a patched H5vcc implementation. -/// -/// The patched H5vcc implementation uses a downloaded CanvasKit implementation -/// monkey-patched with a fake getH5vccSkSurface function. -void patchH5vccCanvasKit({Function? onGetH5vccSkSurfaceCalled}) { - CanvasKit? existingCanvasKit; - SkiaFontCollection? existingSkiaFontCollection; - - setUpAll(() async { - // Set `window.h5vcc` to PatchedH5vcc which uses a downloaded CanvasKit. - final CanvasKit downloadedCanvasKit = await downloadCanvasKit(); - debugH5vccSetter = PatchedH5vcc(downloadedCanvasKit); - - // Monkey-patch the getH5vccSkSurface function of `window.h5vcc.canvasKit`. - js.context['h5vcc']['canvasKit']['getH5vccSkSurface'] = () { - if (onGetH5vccSkSurfaceCalled != null) { - onGetH5vccSkSurfaceCalled(); - } - - // Returns a fake [SkSurface] object with a minimal implementation. - return js.JsObject.jsify({ - 'dispose': () {} - }); - }; - }); -} From ec9c4243e83833a1258ffe715f022c6d557ca7dc Mon Sep 17 00:00:00 2001 From: Benson Luk <97480502+b-luk@users.noreply.github.com> Date: Fri, 4 Feb 2022 22:24:24 +0000 Subject: [PATCH 8/8] Update test to add a check for element, and fix a typo. --- lib/web_ui/test/canvaskit/h5vcc_test.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/test/canvaskit/h5vcc_test.dart b/lib/web_ui/test/canvaskit/h5vcc_test.dart index 174213fdc3735..a5a710e435e92 100644 --- a/lib/web_ui/test/canvaskit/h5vcc_test.dart +++ b/lib/web_ui/test/canvaskit/h5vcc_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 'dart:html' as html; import 'dart:js' as js; import 'package:test/bootstrap/browser.dart'; @@ -50,10 +51,16 @@ void testMain() { expect(canvasKit.getH5vccSkSurface, isNotNull); }); - test('Surface scquireFrame uses getH5vccSkSurface', () { + test('Surface acquireFrame uses getH5vccSkSurface', () { final Surface surface = SurfaceFactory.instance.getSurface(); surface.acquireFrame(ui.Size.zero); expect(getH5vccSkSurfaceCalledCount, 1); + + // No element should be created. + expect( + flutterViewEmbedder.glassPaneElement!.querySelectorAll('canvas'), + isEmpty, + ); }); }, testOn: 'chrome'); }