From b3a37d0273d9deb03840c7091c090f797abb763c Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 13 Mar 2020 07:02:34 -0700 Subject: [PATCH] [flutter_tools] support toggling CanvasKit rendering on with 'k' (#52511) --- .../lib/src/base/command_help.dart | 6 ++++ .../lib/src/build_runner/devfs_web.dart | 35 +++++++++++++++---- .../src/build_runner/resident_web_runner.dart | 10 ++++++ .../lib/src/resident_runner.dart | 17 +++++++++ .../general.shard/base/command_help_test.dart | 1 + .../general.shard/resident_runner_test.dart | 7 ++++ .../resident_web_runner_test.dart | 12 +++++++ .../general.shard/web/devfs_web_test.dart | 15 ++++++++ 8 files changed, 97 insertions(+), 6 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/command_help.dart b/packages/flutter_tools/lib/src/base/command_help.dart index d716eb9d1d..11c5fbd3f3 100644 --- a/packages/flutter_tools/lib/src/base/command_help.dart +++ b/packages/flutter_tools/lib/src/base/command_help.dart @@ -153,6 +153,12 @@ class CommandHelp { 'Toggle elevation checker.', ); + CommandHelpOption _k; + CommandHelpOption get k => _k ??= _makeOption( + 'k', + 'Toggle CanvasKit rendering.', + ); + CommandHelpOption _makeOption(String key, String description, [ String inParenthesis = '', ]) { diff --git a/packages/flutter_tools/lib/src/build_runner/devfs_web.dart b/packages/flutter_tools/lib/src/build_runner/devfs_web.dart index ecb8f7db36..9037714308 100644 --- a/packages/flutter_tools/lib/src/build_runner/devfs_web.dart +++ b/packages/flutter_tools/lib/src/build_runner/devfs_web.dart @@ -205,8 +205,9 @@ class WebAssetServer implements AssetReader { return shelf.Response.notFound(''); } - // For real files, use a serialized file stat as a revision - final String etag = file.lastModifiedSync().toIso8601String(); + // For real files, use a serialized file stat plus path as a revision. + // This allows us to update between canvaskit and non-canvaskit SDKs. + final String etag = file.lastModifiedSync().toIso8601String() + file.path; if (ifNoneMatch == etag) { return shelf.Response.notModified(); } @@ -291,6 +292,9 @@ class WebAssetServer implements AssetReader { return modules; } + /// Whether to use the cavaskit SDK for rendering. + bool canvasKitRendering = false; + @visibleForTesting final File dartSdk = globals.fs.file(globals.fs.path.join( globals.artifacts.getArtifactPath(Artifact.flutterWebSdk), @@ -299,6 +303,14 @@ class WebAssetServer implements AssetReader { 'dart_sdk.js', )); + @visibleForTesting + final File canvasKitDartSdk = globals.fs.file(globals.fs.path.join( + globals.artifacts.getArtifactPath(Artifact.flutterWebSdk), + 'kernel', + 'amd-canvaskit', + 'dart_sdk.js', + )); + @visibleForTesting final File dartSdkSourcemap = globals.fs.file(globals.fs.path.join( globals.artifacts.getArtifactPath(Artifact.flutterWebSdk), @@ -307,14 +319,26 @@ class WebAssetServer implements AssetReader { 'dart_sdk.js.map', )); + @visibleForTesting + final File canvasKitDartSdkSourcemap = globals.fs.file(globals.fs.path.join( + globals.artifacts.getArtifactPath(Artifact.flutterWebSdk), + 'kernel', + 'amd-canvaskit', + 'dart_sdk.js.map', + )); + // Attempt to resolve `path` to a dart file. File _resolveDartFile(String path) { // Return the actual file objects so that local engine changes are automatically picked up. switch (path) { case '/dart_sdk.js': - return dartSdk; - case '.dart_sdk.js.map': - return dartSdkSourcemap; + return canvasKitRendering + ? canvasKitDartSdk + : dartSdk; + case '/dart_sdk.js.map': + return canvasKitRendering + ? canvasKitDartSdkSourcemap + : dartSdkSourcemap; } // If this is a dart file, it must be on the local file system and is // likely coming from a source map request. The tool doesn't currently @@ -405,7 +429,6 @@ class WebDevFS implements DevFS { final bool enableDwds; final bool testMode; - @visibleForTesting WebAssetServer webAssetServer; Dwds get dwds => webAssetServer.dwds; diff --git a/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart b/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart index c6230ba4cc..1c99120e56 100644 --- a/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart @@ -710,6 +710,16 @@ class _ResidentWebRunner extends ResidentWebRunner { return 0; } + @override + bool get supportsCanvasKit => supportsServiceProtocol; + + @override + Future toggleCanvaskit() async { + final WebDevFS webDevFS = device.devFS as WebDevFS; + webDevFS.webAssetServer.canvasKitRendering = !webDevFS.webAssetServer.canvasKitRendering; + await _wipConnection?.sendCommand('Page.reload'); + } + @override Future exitApp() async { await device.exitApps(); diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 6aa3530c7f..29edd8dd56 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -665,6 +665,7 @@ abstract class ResidentRunner { bool get isRunningProfile => debuggingOptions.buildInfo.isProfile; bool get isRunningRelease => debuggingOptions.buildInfo.isRelease; bool get supportsServiceProtocol => isRunningDebug || isRunningProfile; + bool get supportsCanvasKit => false; // Returns the Uri of the first connected device for mobile, // and only connected device for web. @@ -724,6 +725,13 @@ abstract class ResidentRunner { throw '${fullRestart ? 'Restart' : 'Reload'} is not supported in $mode mode'; } + /// Toggle whether canvaskit is being used for rendering. + /// + /// Only supported on the web. + Future toggleCanvaskit() { + throw Exception('Canvaskit not supported by this runner.'); + } + /// The resident runner API for interaction with the reloadMethod vmservice /// request. /// @@ -1043,6 +1051,9 @@ abstract class ResidentRunner { commandHelp.S.print(); commandHelp.U.print(); } + if (supportsCanvasKit){ + commandHelp.k.print(); + } // `P` should precede `a` commandHelp.P.print(); commandHelp.a.print(); @@ -1182,6 +1193,12 @@ class TerminalHandler { return true; } return false; + case 'k': + if (residentRunner.supportsCanvasKit) { + await residentRunner.toggleCanvaskit(); + return true; + } + return false; case 'l': final List views = residentRunner.flutterDevices .expand((FlutterDevice d) => d.views).toList(); diff --git a/packages/flutter_tools/test/general.shard/base/command_help_test.dart b/packages/flutter_tools/test/general.shard/base/command_help_test.dart index 400019f8b7..daa9b64a04 100644 --- a/packages/flutter_tools/test/general.shard/base/command_help_test.dart +++ b/packages/flutter_tools/test/general.shard/base/command_help_test.dart @@ -59,6 +59,7 @@ void _testMessageLength({ expect(commandHelp.d.toString().length, lessThanOrEqualTo(expectedWidth)); expect(commandHelp.h.toString().length, lessThanOrEqualTo(expectedWidth)); expect(commandHelp.i.toString().length, lessThanOrEqualTo(expectedWidth)); + expect(commandHelp.k.toString().length, lessThanOrEqualTo(expectedWidth)); expect(commandHelp.o.toString().length, lessThanOrEqualTo(expectedWidth)); expect(commandHelp.p.toString().length, lessThanOrEqualTo(expectedWidth)); expect(commandHelp.q.toString().length, lessThanOrEqualTo(expectedWidth)); diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 8d35618f56..39ab340b2d 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -368,6 +368,8 @@ void main() { expect(residentRunner.supportsServiceProtocol, true); // isRunningDebug expect(residentRunner.isRunningDebug, true); + // does not support CanvasKit + expect(residentRunner.supportsCanvasKit, false); // commands expect(testLogger.statusText, equals( [ @@ -395,6 +397,11 @@ void main() { )); })); + test('ResidentRunner does not support CanvasKit', () => testbed.run(() async { + expect(() => residentRunner.toggleCanvaskit(), + throwsA(isA())); + })); + test('ResidentRunner can take screenshot on debug device', () => testbed.run(() async { when(mockDevice.supportsScreenshot).thenReturn(true); when(mockDevice.takeScreenshot(any)) diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 7e7c9df27b..a2aa47f5b0 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -425,6 +425,18 @@ void main() { expect(residentWebRunner.debuggingEnabled, true); })); + test('web resident runner can toggle CanvasKit', () => testbed.run(() async { + final WebAssetServer webAssetServer = WebAssetServer(null, null, null); + when(mockWebDevFS.webAssetServer).thenReturn(webAssetServer); + + expect(residentWebRunner.supportsCanvasKit, true); + expect(webAssetServer.canvasKitRendering, false); + + await residentWebRunner.toggleCanvaskit(); + + expect(webAssetServer.canvasKitRendering, true); + })); + test('Exits when initial compile fails', () => testbed.run(() async { _setupMocks(); when(mockWebDevFS.update( diff --git a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart index 8e5e06ca55..3b6f597446 100644 --- a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart +++ b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart @@ -357,6 +357,15 @@ void main() { webDevFS.webAssetServer.dartSdk ..createSync(recursive: true) ..writeAsStringSync('HELLO'); + webDevFS.webAssetServer.dartSdkSourcemap + ..createSync(recursive: true) + ..writeAsStringSync('THERE'); + webDevFS.webAssetServer.canvasKitDartSdk + ..createSync(recursive: true) + ..writeAsStringSync('OL'); + webDevFS.webAssetServer.canvasKitDartSdkSourcemap + ..createSync(recursive: true) + ..writeAsStringSync('CHUM'); webDevFS.webAssetServer.dartSdkSourcemap.createSync(recursive: true); await webDevFS.update( @@ -373,6 +382,7 @@ void main() { expect(webDevFS.webAssetServer.getFile('/manifest.json'), isNotNull); expect(webDevFS.webAssetServer.getFile('/flutter_service_worker.js'), isNotNull); expect(await webDevFS.webAssetServer.dartSourceContents('/dart_sdk.js'), 'HELLO'); + expect(await webDevFS.webAssetServer.dartSourceContents('/dart_sdk.js.map'), 'THERE'); // Update to the SDK. webDevFS.webAssetServer.dartSdk.writeAsStringSync('BELLOW'); @@ -380,6 +390,11 @@ void main() { // New SDK should be visible.. expect(await webDevFS.webAssetServer.dartSourceContents('/dart_sdk.js'), 'BELLOW'); + // Toggle CanvasKit + webDevFS.webAssetServer.canvasKitRendering = true; + expect(await webDevFS.webAssetServer.dartSourceContents('/dart_sdk.js'), 'OL'); + expect(await webDevFS.webAssetServer.dartSourceContents('/dart_sdk.js.map'), 'CHUM'); + await webDevFS.destroy(); })); }