diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 260ae32ba8c..41a98a9b656 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -1283,6 +1283,10 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/message_codec.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/message_codecs.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/services/serialization.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/shadow.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/svg.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/test_embedding.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart diff --git a/engine/src/flutter/lib/web_ui/dev/steps/compile_tests_step.dart b/engine/src/flutter/lib/web_ui/dev/steps/compile_tests_step.dart index 40656b5f536..e9931b7b5ed 100644 --- a/engine/src/flutter/lib/web_ui/dev/steps/compile_tests_step.dart +++ b/engine/src/flutter/lib/web_ui/dev/steps/compile_tests_step.dart @@ -186,11 +186,16 @@ Future compileTests(List testFiles) async { // different dart2js options. final List htmlTargets = []; final List canvasKitTargets = []; + final List skwasmTargets = []; final String canvasKitTestDirectory = pathlib.join(environment.webUiTestDir.path, 'canvaskit'); + final String skwasmTestDirectory = + pathlib.join(environment.webUiTestDir.path, 'skwasm'); for (final FilePath testFile in testFiles) { if (pathlib.isWithin(canvasKitTestDirectory, testFile.absolute)) { canvasKitTargets.add(testFile); + } else if (pathlib.isWithin(skwasmTestDirectory, testFile.absolute)) { + skwasmTargets.add(testFile); } else { htmlTargets.add(testFile); } @@ -198,9 +203,11 @@ Future compileTests(List testFiles) async { await Future.wait(>[ if (htmlTargets.isNotEmpty) - _compileTestsInParallel(targets: htmlTargets, forCanvasKit: false), + _compileTestsInParallel(targets: htmlTargets), if (canvasKitTargets.isNotEmpty) _compileTestsInParallel(targets: canvasKitTargets, forCanvasKit: true), + if (skwasmTargets.isNotEmpty) + _compileTestsInParallel(targets: skwasmTargets, forSkwasm: true), ]); stopwatch.stop(); @@ -220,11 +227,12 @@ final Pool _dart2jsPool = Pool(_dart2jsConcurrency); /// Spawns multiple dart2js processes to compile [targets] in parallel. Future _compileTestsInParallel({ required List targets, - required bool forCanvasKit, + bool forCanvasKit = false, + bool forSkwasm = false, }) async { final Stream results = _dart2jsPool.forEach( targets, - (FilePath file) => compileUnitTest(file, forCanvasKit: forCanvasKit), + (FilePath file) => compileUnitTest(file, forCanvasKit: forCanvasKit, forSkwasm: forSkwasm), ); await for (final bool isSuccess in results) { if (!isSuccess) { @@ -250,7 +258,7 @@ Future _compileTestsInParallel({ /// directory before test are build. See [_copyFilesFromTestToBuild]. /// /// Later the extra files will be deleted in [_cleanupExtraFilesUnderTestDir]. -Future compileUnitTest(FilePath input, {required bool forCanvasKit}) async { +Future compileUnitTest(FilePath input, {required bool forCanvasKit, required bool forSkwasm}) async { final String targetFileName = pathlib.join( environment.webUiBuildDir.path, '${input.relativeToWebUi}.browser_test.dart.js', @@ -277,6 +285,7 @@ Future compileUnitTest(FilePath input, {required bool forCanvasKit}) async // renderer explicitly. '-DFLUTTER_WEB_AUTO_DETECT=false', '-DFLUTTER_WEB_USE_SKIA=$forCanvasKit', + '-DFLUTTER_WEB_USE_SKWASM=$forSkwasm', '-O2', '-o', diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/configuration.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/configuration.dart index 948404a6415..395e3f87c14 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/configuration.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/configuration.dart @@ -68,6 +68,9 @@ class FlutterConfiguration { static const bool flutterWebAutoDetect = bool.fromEnvironment('FLUTTER_WEB_AUTO_DETECT', defaultValue: true); + static const bool flutterWebUseSkwasm = + bool.fromEnvironment('FLUTTER_WEB_USE_SKWASM'); + /// Enable the Skia-based rendering backend. /// /// Using flutter tools option "--web-render=canvaskit" would set the value to diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/renderer.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/renderer.dart index e66d77f2d26..41523b3491b 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/renderer.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/renderer.dart @@ -15,6 +15,7 @@ import 'embedder.dart'; 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'; final Renderer _renderer = Renderer._internal(); Renderer get renderer => _renderer; @@ -26,6 +27,9 @@ Renderer get renderer => _renderer; /// of functionality needed by the rest of the generic web engine code. abstract class Renderer { factory Renderer._internal() { + if (FlutterConfiguration.flutterWebUseSkwasm) { + return SkwasmRenderer(); + } bool useCanvasKit; if (FlutterConfiguration.flutterWebAutoDetect) { if (requestedRendererType != null) { @@ -154,27 +158,27 @@ abstract class Renderer { ui.Path combinePaths(ui.PathOperation op, ui.Path path1, ui.Path path2); ui.TextStyle createTextStyle({ - ui.Color? color, - ui.TextDecoration? decoration, - ui.Color? decorationColor, - ui.TextDecorationStyle? decorationStyle, - double? decorationThickness, - ui.FontWeight? fontWeight, - ui.FontStyle? fontStyle, - ui.TextBaseline? textBaseline, - String? fontFamily, - List? fontFamilyFallback, - double? fontSize, - double? letterSpacing, - double? wordSpacing, - double? height, - ui.TextLeadingDistribution? leadingDistribution, - ui.Locale? locale, - ui.Paint? background, - ui.Paint? foreground, - List? shadows, - List? fontFeatures, - List? fontVariations, + required ui.Color? color, + required ui.TextDecoration? decoration, + required ui.Color? decorationColor, + required ui.TextDecorationStyle? decorationStyle, + required double? decorationThickness, + required ui.FontWeight? fontWeight, + required ui.FontStyle? fontStyle, + required ui.TextBaseline? textBaseline, + required String? fontFamily, + required List? fontFamilyFallback, + required double? fontSize, + required double? letterSpacing, + required double? wordSpacing, + required double? height, + required ui.TextLeadingDistribution? leadingDistribution, + required ui.Locale? locale, + required ui.Paint? background, + required ui.Paint? foreground, + required List? shadows, + required List? fontFeatures, + required List? fontVariations, }); ui.ParagraphStyle createParagraphStyle({ diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart new file mode 100644 index 00000000000..554302e24e8 --- /dev/null +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart @@ -0,0 +1,7 @@ +// 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. + +library skwasm_impl; + +export 'skwasm_impl/renderer.dart'; diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart new file mode 100644 index 00000000000..ff240beba20 --- /dev/null +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/renderer.dart @@ -0,0 +1,168 @@ +// 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 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:ui/ui.dart' as ui; + +import '../../embedder.dart'; +import '../../fonts.dart'; +import '../../html_image_codec.dart'; +import '../../renderer.dart'; + +// TODO(jacksongardner): Actually implement skwasm renderer. +class SkwasmRenderer implements Renderer { + @override + ui.Path combinePaths(ui.PathOperation op, ui.Path path1, ui.Path path2) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.ImageFilter composeImageFilters({required ui.ImageFilter outer, required ui.ImageFilter inner}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Path copyPath(ui.Path src) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.ImageFilter createBlurImageFilter({double sigmaX = 0.0, double sigmaY = 0.0, ui.TileMode tileMode = ui.TileMode.clamp}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Canvas createCanvas(ui.PictureRecorder recorder, [ui.Rect? cullRect]) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Gradient createConicalGradient(ui.Offset focal, double focalRadius, ui.Offset center, double radius, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix]) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.ImageFilter createDilateImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.ImageFilter createErodeImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.ImageShader createImageShader(ui.Image image, ui.TileMode tmx, ui.TileMode tmy, Float64List matrix4, ui.FilterQuality? filterQuality) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Gradient createLinearGradient(ui.Offset from, ui.Offset to, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4]) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.ImageFilter createMatrixImageFilter(Float64List matrix4, {ui.FilterQuality filterQuality = ui.FilterQuality.low}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Paint createPaint() { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.ParagraphBuilder createParagraphBuilder(ui.ParagraphStyle style) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.ParagraphStyle createParagraphStyle({ui.TextAlign? textAlign, ui.TextDirection? textDirection, int? maxLines, String? fontFamily, double? fontSize, double? height, ui.TextHeightBehavior? textHeightBehavior, ui.FontWeight? fontWeight, ui.FontStyle? fontStyle, ui.StrutStyle? strutStyle, String? ellipsis, ui.Locale? locale}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Path createPath() { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.PictureRecorder createPictureRecorder() { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Gradient createRadialGradient(ui.Offset center, double radius, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4]) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.SceneBuilder createSceneBuilder() { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.StrutStyle createStrutStyle({String? fontFamily, List? fontFamilyFallback, double? fontSize, double? height, ui.TextLeadingDistribution? leadingDistribution, double? leading, ui.FontWeight? fontWeight, ui.FontStyle? fontStyle, bool? forceStrutHeight}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Gradient createSweepGradient(ui.Offset center, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, double startAngle = 0.0, double endAngle = math.pi * 2, Float32List? matrix4]) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.TextStyle createTextStyle({ui.Color? color, ui.TextDecoration? decoration, ui.Color? decorationColor, ui.TextDecorationStyle? decorationStyle, double? decorationThickness, ui.FontWeight? fontWeight, ui.FontStyle? fontStyle, ui.TextBaseline? textBaseline, String? fontFamily, List? fontFamilyFallback, double? fontSize, double? letterSpacing, double? wordSpacing, double? height, ui.TextLeadingDistribution? leadingDistribution, ui.Locale? locale, ui.Paint? background, ui.Paint? foreground, List? shadows, List? fontFeatures, List? fontVariations}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Vertices createVertices(ui.VertexMode mode, List positions, {List? textureCoordinates, List? colors, List? indices}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + ui.Vertices createVerticesRaw(ui.VertexMode mode, Float32List positions, {Float32List? textureCoordinates, Int32List? colors, Uint16List? indices}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + void decodeImageFromPixels(Uint8List pixels, int width, int height, ui.PixelFormat format, ui.ImageDecoderCallback callback, {int? rowBytes, int? targetWidth, int? targetHeight, bool allowUpscaling = true}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + FontCollection get fontCollection => throw UnimplementedError('Not yet implemented'); + + @override + FutureOr initialize() { + throw UnimplementedError('Not yet implemented'); + } + + @override + Future instantiateImageCodec(Uint8List list, {int? targetWidth, int? targetHeight, bool allowUpscaling = true}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + Future instantiateImageCodecFromUrl(Uri uri, {WebOnlyImageCodecChunkCallback? chunkCallback}) { + throw UnimplementedError('Not yet implemented'); + } + + @override + void renderScene(ui.Scene scene) { + throw UnimplementedError('Not yet implemented'); + } + + @override + String get rendererTag => throw UnimplementedError('Not yet implemented'); + + @override + void reset(FlutterViewEmbedder embedder) { + throw UnimplementedError('Not yet implemented'); + } +} diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart new file mode 100644 index 00000000000..32f7960a81f --- /dev/null +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart @@ -0,0 +1,7 @@ +// 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. + +library skwasm_stub; + +export 'skwasm_stub/renderer.dart'; diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart new file mode 100644 index 00000000000..6858335cd4e --- /dev/null +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart @@ -0,0 +1,167 @@ +// 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 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:ui/ui.dart' as ui; + +import '../../embedder.dart'; +import '../../fonts.dart'; +import '../../html_image_codec.dart'; +import '../../renderer.dart'; + +class SkwasmRenderer implements Renderer { + @override + ui.Path combinePaths(ui.PathOperation op, ui.Path path1, ui.Path path2) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.ImageFilter composeImageFilters({required ui.ImageFilter outer, required ui.ImageFilter inner}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Path copyPath(ui.Path src) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.ImageFilter createBlurImageFilter({double sigmaX = 0.0, double sigmaY = 0.0, ui.TileMode tileMode = ui.TileMode.clamp}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Canvas createCanvas(ui.PictureRecorder recorder, [ui.Rect? cullRect]) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Gradient createConicalGradient(ui.Offset focal, double focalRadius, ui.Offset center, double radius, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix]) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.ImageFilter createDilateImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.ImageFilter createErodeImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.ImageShader createImageShader(ui.Image image, ui.TileMode tmx, ui.TileMode tmy, Float64List matrix4, ui.FilterQuality? filterQuality) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Gradient createLinearGradient(ui.Offset from, ui.Offset to, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4]) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.ImageFilter createMatrixImageFilter(Float64List matrix4, {ui.FilterQuality filterQuality = ui.FilterQuality.low}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Paint createPaint() { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.ParagraphBuilder createParagraphBuilder(ui.ParagraphStyle style) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.ParagraphStyle createParagraphStyle({ui.TextAlign? textAlign, ui.TextDirection? textDirection, int? maxLines, String? fontFamily, double? fontSize, double? height, ui.TextHeightBehavior? textHeightBehavior, ui.FontWeight? fontWeight, ui.FontStyle? fontStyle, ui.StrutStyle? strutStyle, String? ellipsis, ui.Locale? locale}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Path createPath() { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.PictureRecorder createPictureRecorder() { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Gradient createRadialGradient(ui.Offset center, double radius, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4]) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.SceneBuilder createSceneBuilder() { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.StrutStyle createStrutStyle({String? fontFamily, List? fontFamilyFallback, double? fontSize, double? height, ui.TextLeadingDistribution? leadingDistribution, double? leading, ui.FontWeight? fontWeight, ui.FontStyle? fontStyle, bool? forceStrutHeight}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Gradient createSweepGradient(ui.Offset center, List colors, [List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, double startAngle = 0.0, double endAngle = math.pi * 2, Float32List? matrix4]) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.TextStyle createTextStyle({ui.Color? color, ui.TextDecoration? decoration, ui.Color? decorationColor, ui.TextDecorationStyle? decorationStyle, double? decorationThickness, ui.FontWeight? fontWeight, ui.FontStyle? fontStyle, ui.TextBaseline? textBaseline, String? fontFamily, List? fontFamilyFallback, double? fontSize, double? letterSpacing, double? wordSpacing, double? height, ui.TextLeadingDistribution? leadingDistribution, ui.Locale? locale, ui.Paint? background, ui.Paint? foreground, List? shadows, List? fontFeatures, List? fontVariations}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Vertices createVertices(ui.VertexMode mode, List positions, {List? textureCoordinates, List? colors, List? indices}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + ui.Vertices createVerticesRaw(ui.VertexMode mode, Float32List positions, {Float32List? textureCoordinates, Int32List? colors, Uint16List? indices}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + void decodeImageFromPixels(Uint8List pixels, int width, int height, ui.PixelFormat format, ui.ImageDecoderCallback callback, {int? rowBytes, int? targetWidth, int? targetHeight, bool allowUpscaling = true}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + FontCollection get fontCollection => throw UnimplementedError('Skwasm not implemented on this platform.'); + + @override + FutureOr initialize() { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + Future instantiateImageCodec(Uint8List list, {int? targetWidth, int? targetHeight, bool allowUpscaling = true}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + Future instantiateImageCodecFromUrl(Uri uri, {WebOnlyImageCodecChunkCallback? chunkCallback}) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + void renderScene(ui.Scene scene) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } + + @override + String get rendererTag => throw UnimplementedError('Skwasm not implemented on this platform.'); + + @override + void reset(FlutterViewEmbedder embedder) { + throw UnimplementedError('Skwasm not implemented on this platform.'); + } +} diff --git a/engine/src/flutter/lib/web_ui/test/skwasm/smoke_test.dart b/engine/src/flutter/lib/web_ui/test/skwasm/smoke_test.dart new file mode 100644 index 00000000000..74c5a30ad7a --- /dev/null +++ b/engine/src/flutter/lib/web_ui/test/skwasm/smoke_test.dart @@ -0,0 +1,27 @@ +// 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. + +@TestOn('chrome || safari || firefox') + +import 'dart:async'; + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine/renderer.dart'; +import 'package:ui/src/engine/skwasm/skwasm_stub/renderer.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +Future testMain() async { + group('Skwasm stub tests', () { + test('Skwasm stub renderer throws', () { + expect(renderer, isA()); + expect(() { + renderer.initialize(); + }, throwsUnimplementedError); + }); + }); +} diff --git a/engine/src/flutter/web_sdk/BUILD.gn b/engine/src/flutter/web_sdk/BUILD.gn index ba7d190ed83..1c653d5b91d 100644 --- a/engine/src/flutter/web_sdk/BUILD.gn +++ b/engine/src/flutter/web_sdk/BUILD.gn @@ -19,17 +19,6 @@ web_ui_sources = exec_script("//third_party/dart/tools/list_dart_files.py", ], "list lines") -web_engine_sources = - exec_script("//third_party/dart/tools/list_dart_files.py", - [ - "absolute", - rebase_path("//flutter/lib/web_ui/lib/src/engine"), - ], - "list lines") - -web_engine_sources += - [ rebase_path("//flutter/lib/web_ui/lib/src/engine.dart") ] - group("web_sdk") { deps = [ ":flutter_dartdevc_canvaskit_html_kernel_sdk", @@ -43,60 +32,100 @@ group("web_sdk") { ] } -prebuilt_dart_action("web_ui_sources") { - inputs = web_ui_sources + [ "sdk_rewriter.dart" ] +template("sdk_rewriter") { + ui = defined(invoker.ui) && invoker.ui + if (!ui) { + assert(defined(invoker.library_name), "Must pass 'library_name'") + assert(defined(invoker.api_file), "Must pass 'api_file'") + } + assert(defined(invoker.input_dir), "Must pass 'input_dir'") + assert(defined(invoker.output_dir), "Must pass 'output_dir'") - packages = dart_sdk_package_config - script = "sdk_rewriter.dart" - output_dir = rebase_path("$root_out_dir/flutter_web_sdk/lib/ui/") - input_dir = rebase_path("//flutter/lib/web_ui/lib/") - pool = "//flutter/build/dart:dart_pool" + source_dart_files = exec_script("//third_party/dart/tools/list_dart_files.py", + [ + "absolute", + rebase_path(invoker.input_dir), + ], + "list lines") - outputs = [ - "$target_gen_dir/$target_name.stamp", - "$root_out_dir/flutter_web_sdk/lib/ui/", - ] + if (defined(invoker.exclude_patterns)) { + filtered_files = filter_exclude(source_dart_files, invoker.exclude_patterns) + source_dart_files = [] + source_dart_files = filtered_files + } - args = [ - "--output-dir=$output_dir", - "--input-dir=$input_dir", - "--ui", - "--stamp", - rebase_path(outputs[0], root_build_dir), - ] + prebuilt_dart_action(target_name) { + packages = dart_sdk_package_config + pool = "//flutter/build/dart:dart_pool" - foreach(source_file, web_ui_sources) { - path = rebase_path(source_file) - args += [ "--input=$path" ] + script = "sdk_rewriter.dart" + inputs = source_dart_files + [ "sdk_rewriter.dart" ] + + stamp_location = "$target_gen_dir/$target_name.stamp" + outputs = [ + stamp_location, + invoker.output_dir, + ] + + input_dir = rebase_path(invoker.input_dir) + output_dir = rebase_path(invoker.output_dir) + + args = [ + "--output-dir=$output_dir", + "--input-dir=$input_dir", + "--stamp", + rebase_path(stamp_location, root_build_dir), + ] + if (ui) { + args += [ "--ui" ] + } else { + library_name = invoker.library_name + api_file = rebase_path(invoker.api_file) + args += [ + "--library-name=$library_name", + "--api-file=$api_file", + ] + } + + foreach(source_file, source_dart_files) { + path = rebase_path(source_file) + args += [ "--source-file=$path" ] + } } } -prebuilt_dart_action("web_engine_sources") { - inputs = web_engine_sources + [ "sdk_rewriter.dart" ] +sdk_rewriter("web_ui_library_sources") { + ui = true + input_dir = "//flutter/lib/web_ui/lib/" + output_dir = "$root_out_dir/flutter_web_sdk/lib/ui/" - packages = dart_sdk_package_config - script = "sdk_rewriter.dart" - output_dir = rebase_path("$root_out_dir/flutter_web_sdk/lib/_engine/") - input_dir = rebase_path("//flutter/lib/web_ui/lib/src/") - pool = "//flutter/build/dart:dart_pool" + # exclude everything in the engine directory, it will be a separate internal library + exclude_patterns = [ rebase_path("//flutter/lib/web_ui/lib/src/*") ] +} - outputs = [ - "$target_gen_dir/$target_name.stamp", - "$root_out_dir/flutter_web_sdk/lib/_engine/", - ] +sdk_rewriter("web_engine_library") { + library_name = "engine" + api_file = "//flutter/lib/web_ui/lib/src/engine.dart" + input_dir = "//flutter/lib/web_ui/lib/src/engine/" + output_dir = "$root_out_dir/flutter_web_sdk/lib/_engine/" - args = [ - "--output-dir=$output_dir", - "--input-dir=$input_dir", - "--engine", - "--stamp", - rebase_path(outputs[0], root_build_dir), - ] + # exclude skwasm, it will be a separate internal library + exclude_patterns = + [ rebase_path("//flutter/lib/web_ui/lib/src/engine/skwasm/*") ] +} - foreach(source_file, web_engine_sources) { - path = rebase_path(source_file) - args += [ "--input=$path" ] - } +sdk_rewriter("skwasm_stub_library") { + library_name = "skwasm_stub" + api_file = "//flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart" + input_dir = "//flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/" + output_dir = "$root_out_dir/flutter_web_sdk/lib/_skwasm_stub/" +} + +sdk_rewriter("skwasm_impl_library") { + library_name = "skwasm_impl" + api_file = "//flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart" + input_dir = "//flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/" + output_dir = "$root_out_dir/flutter_web_sdk/lib/_skwasm_impl/" } copy("web_ui_library") { @@ -119,9 +148,11 @@ template("_dartdevc") { action(target_name) { not_needed(invoker, [ "packages" ]) deps = [ - ":web_engine_sources", + ":skwasm_impl_library", + ":skwasm_stub_library", + ":web_engine_library", ":web_ui_library", - ":web_ui_sources", + ":web_ui_library_sources", "//flutter:dart_sdk", ] script = "//build/gn_run_binary.py" @@ -148,9 +179,11 @@ template("_dartdevc") { forward_variables_from(invoker, "*") deps = [ - ":web_engine_sources", + ":skwasm_impl_library", + ":skwasm_stub_library", + ":web_engine_library", ":web_ui_library", - ":web_ui_sources", + ":web_ui_library_sources", "//flutter:dart_sdk", "//third_party/dart/pkg:pkg_files_stamp", "//third_party/dart/utils/dartdevc:dartdevc_files_stamp", @@ -177,9 +210,11 @@ template("_kernel_worker") { if (flutter_prebuilt_dart_sdk) { action(target_name) { deps = [ - ":web_engine_sources", + ":skwasm_impl_library", + ":skwasm_stub_library", + ":web_engine_library", ":web_ui_library", - ":web_ui_sources", + ":web_ui_library_sources", "//flutter:dart_sdk", ] script = "//build/gn_run_binary.py" @@ -207,9 +242,11 @@ template("_kernel_worker") { forward_variables_from(invoker, "*") deps = [ - ":web_engine_sources", + ":skwasm_impl_library", + ":skwasm_stub_library", + ":web_engine_library", ":web_ui_library", - ":web_ui_sources", + ":web_ui_library_sources", "//flutter:dart_sdk", "//third_party/dart/pkg:pkg_files_stamp", "//third_party/dart/utils/dartdevc:dartdevc_files_stamp", @@ -225,7 +262,7 @@ template("_kernel_worker") { # Compile the unsound DDC SDK's summary. _kernel_worker("flutter_dartdevc_kernel_sdk_outline") { - inputs = [ "sdk_rewriter.dart" ] + web_ui_sources + web_engine_sources + inputs = [ "sdk_rewriter.dart" ] + web_ui_sources outputs = [ sdk_dill ] @@ -257,7 +294,7 @@ _kernel_worker("flutter_dartdevc_kernel_sdk_outline") { # Compiles the unsound html only renderer. _dartdevc("flutter_dartdevc_kernel_sdk") { - inputs = [ "sdk_rewriter.dart" ] + web_ui_sources + web_engine_sources + inputs = [ "sdk_rewriter.dart" ] + web_ui_sources packages = dart_sdk_package_config @@ -303,7 +340,7 @@ _dartdevc("flutter_dartdevc_kernel_sdk") { # Compiles the unsound canvaskit only renderer. _dartdevc("flutter_dartdevc_canvaskit_kernel_sdk") { - inputs = [ "sdk_rewriter.dart" ] + web_ui_sources + web_engine_sources + inputs = [ "sdk_rewriter.dart" ] + web_ui_sources packages = dart_sdk_package_config @@ -351,7 +388,7 @@ _dartdevc("flutter_dartdevc_canvaskit_kernel_sdk") { # Compiles the unsound autodetect renderer. _dartdevc("flutter_dartdevc_canvaskit_html_kernel_sdk") { - inputs = [ "sdk_rewriter.dart" ] + web_ui_sources + web_engine_sources + inputs = [ "sdk_rewriter.dart" ] + web_ui_sources packages = dart_sdk_package_config @@ -399,7 +436,7 @@ _dartdevc("flutter_dartdevc_canvaskit_html_kernel_sdk") { # Compiles the sound html only renderer. _dartdevc("flutter_dartdevc_kernel_sdk_sound") { - inputs = [ "sdk_rewriter.dart" ] + web_ui_sources + web_engine_sources + inputs = [ "sdk_rewriter.dart" ] + web_ui_sources packages = dart_sdk_package_config @@ -446,7 +483,7 @@ _dartdevc("flutter_dartdevc_kernel_sdk_sound") { # Compiles the sound canvaskit only renderer. _dartdevc("flutter_dartdevc_canvaskit_kernel_sdk_sound") { - inputs = [ "sdk_rewriter.dart" ] + web_ui_sources + web_engine_sources + inputs = [ "sdk_rewriter.dart" ] + web_ui_sources packages = dart_sdk_package_config @@ -494,7 +531,7 @@ _dartdevc("flutter_dartdevc_canvaskit_kernel_sdk_sound") { # Compiles the sound autodetect renderer. _dartdevc("flutter_dartdevc_canvaskit_html_kernel_sdk_sound") { - inputs = [ "sdk_rewriter.dart" ] + web_ui_sources + web_engine_sources + inputs = [ "sdk_rewriter.dart" ] + web_ui_sources packages = dart_sdk_package_config @@ -542,7 +579,7 @@ _dartdevc("flutter_dartdevc_canvaskit_html_kernel_sdk_sound") { # Compile the sound DDC SDK's summary. _kernel_worker("flutter_dartdevc_kernel_sdk_outline_sound") { - inputs = [ "sdk_rewriter.dart" ] + web_ui_sources + web_engine_sources + inputs = [ "sdk_rewriter.dart" ] + web_ui_sources outputs = [ sdk_dill_sound ] @@ -585,9 +622,11 @@ if (!is_fuchsia) { ":flutter_dartdevc_kernel_sdk_outline", ":flutter_dartdevc_kernel_sdk_outline_sound", ":flutter_dartdevc_kernel_sdk_sound", - ":web_engine_sources", + ":skwasm_impl_library", + ":skwasm_stub_library", + ":web_engine_library", ":web_ui_library", - ":web_ui_sources", + ":web_ui_library_sources", ] sources = get_target_outputs(":flutter_dartdevc_canvaskit_html_kernel_sdk") sources += @@ -600,8 +639,10 @@ if (!is_fuchsia) { sources += get_target_outputs(":flutter_dartdevc_kernel_sdk_outline_sound") sources += get_target_outputs(":flutter_dartdevc_kernel_sdk_sound") sources += get_target_outputs(":web_ui_library") - sources += get_target_outputs(":web_ui_sources") - sources += get_target_outputs(":web_engine_sources") + sources += get_target_outputs(":web_ui_library_sources") + sources += get_target_outputs(":skwasm_stub_library") + sources += get_target_outputs(":skwasm_impl_library") + sources += get_target_outputs(":web_engine_library") tmp_files = [] foreach(source, sources) { tmp_files += [ diff --git a/engine/src/flutter/web_sdk/libraries.json b/engine/src/flutter/web_sdk/libraries.json index 01a9fece85a..7f9c8789b27 100644 --- a/engine/src/flutter/web_sdk/libraries.json +++ b/engine/src/flutter/web_sdk/libraries.json @@ -14,6 +14,9 @@ }, "_engine": { "uri": "lib/_engine/engine.dart" + }, + "_skwasm_stub": { + "uri": "lib/_skwasm_stub/skwasm_stub.dart" } } }, @@ -30,6 +33,9 @@ }, "_engine": { "uri": "lib/_engine/engine.dart" + }, + "_skwasm_stub": { + "uri": "lib/_skwasm_stub/skwasm_stub.dart" } } }, @@ -46,6 +52,9 @@ }, "_engine": { "uri": "lib/_engine/engine.dart" + }, + "_skwasm_impl": { + "uri": "lib/_skwasm_impl/skwasm_impl.dart" } } } diff --git a/engine/src/flutter/web_sdk/libraries.yaml b/engine/src/flutter/web_sdk/libraries.yaml index 46bb23f079d..5a95df9ca41 100644 --- a/engine/src/flutter/web_sdk/libraries.yaml +++ b/engine/src/flutter/web_sdk/libraries.yaml @@ -7,7 +7,7 @@ # Note: if you edit this file, you must also edit libraries.json in this # directory: # -#. python third_party/dart/tools/yaml2json.py flutter/web_sdk/libraries.yaml flutter/web_sdk/libraries.json +#. dart third_party/dart/tools/yaml2json.dart flutter/web_sdk/libraries.yaml flutter/web_sdk/libraries.json # # We currently have several different files that needs to be updated when # changing libraries, sources, and patch files. See @@ -24,6 +24,9 @@ dartdevc: _engine: uri: "lib/_engine/engine.dart" + _skwasm_stub: + uri: "lib/_skwasm_stub/skwasm_stub.dart" + dart2js: include: - {path: "../dart-sdk/lib/libraries.json", target: dart2js} @@ -35,6 +38,9 @@ dart2js: _engine: uri: "lib/_engine/engine.dart" + _skwasm_stub: + uri: "lib/_skwasm_stub/skwasm_stub.dart" + wasm: include: - {path: "../dart-sdk/lib/libraries.json", target: wasm} @@ -45,3 +51,6 @@ wasm: _engine: uri: "lib/_engine/engine.dart" + + _skwasm_impl: + uri: "lib/_skwasm_impl/skwasm_impl.dart" diff --git a/engine/src/flutter/web_sdk/sdk_rewriter.dart b/engine/src/flutter/web_sdk/sdk_rewriter.dart index bacc7683443..cb383b6a374 100644 --- a/engine/src/flutter/web_sdk/sdk_rewriter.dart +++ b/engine/src/flutter/web_sdk/sdk_rewriter.dart @@ -11,8 +11,9 @@ final ArgParser argParser = ArgParser() ..addOption('output-dir') ..addOption('input-dir') ..addFlag('ui') - ..addFlag('engine') - ..addMultiOption('input') + ..addOption('library-name') + ..addOption('api-file') + ..addMultiOption('source-file') ..addOption('stamp'); final List uiPatterns = [ @@ -33,10 +34,11 @@ export 'dart:_engine' ), ]; -final List engineLibraryPatterns = [ - AllReplacer(RegExp(r'library\s+engine;'), ''' +List generateApiFilePatterns(String libraryName, String extraImports) { + return [ + AllReplacer(RegExp('library\\s+$libraryName;'), ''' @JS() -library dart._engine; +library dart._$libraryName; import 'dart:async'; import 'dart:collection'; @@ -47,27 +49,33 @@ import 'dart:_js_annotations'; import 'dart:math' as math; import 'dart:typed_data'; import 'dart:ui' as ui; -'''), - // Replace exports of engine files with "part" directives. - MappedReplacer(RegExp(r''' -export\s*'engine/(.*)'; +$extraImports +''' + ), + // Replace exports of engine files with "part" directives. + MappedReplacer(RegExp(''' +export\\s*'$libraryName/(.*)'; '''), (Match match) => ''' -part 'engine/${match.group(1)}'; -'''), -]; +part '$libraryName/${match.group(1)}'; +''' + ), + ]; +} -final List enginePartsPatterns = [ - AllReplacer(RegExp(r'part\s+of\s+engine;'), 'part of dart._engine;'), - // Remove library-level JS annotations. - AllReplacer(RegExp(r'\n@JS(.*)\nlibrary .+;'), ''), - // Remove library directives. - AllReplacer(RegExp(r'\nlibrary .+;'), ''), - // Remove imports/exports from all engine parts. - AllReplacer(RegExp(r'\nimport\s*.*'), ''), - AllReplacer(RegExp(r'\nexport\s*.*'), ''), -]; +List generatePartsPatterns(String libraryName) { + return [ + AllReplacer(RegExp('part\\s+of\\s+$libraryName;'), 'part of dart._$libraryName;'), + // Remove library-level JS annotations. + AllReplacer(RegExp(r'\n@JS(.*)\nlibrary .+;'), ''), + // Remove library directives. + AllReplacer(RegExp(r'\nlibrary .+;'), ''), + // Remove imports/exports from all part files. + AllReplacer(RegExp(r'\nimport\s*.*'), ''), + AllReplacer(RegExp(r'\nexport\s*.*'), ''), + ]; +} -final List sharedPatterns = [ +final List stripMetaPatterns = [ AllReplacer(RegExp(r"import\s*'package:meta/meta.dart';"), ''), AllReplacer('@required', ''), AllReplacer('@protected', ''), @@ -82,38 +90,75 @@ void main(List arguments) { final ArgResults results = argParser.parse(arguments); final Directory directory = Directory(results['output-dir'] as String); final String inputDirectoryPath = results['input-dir'] as String; - for (final String inputFilePath in results['input'] as Iterable) { - final File inputFile = File(inputFilePath); - final File outputFile = File(path.join( - directory.path, inputFile.path.substring(inputDirectoryPath.length))) - ..createSync(recursive: true); - final String source = inputFile.readAsStringSync(); - final String rewrittenContent = rewriteFile( - source, - filePath: inputFilePath, - isUi: results['ui'] as bool, - isEngine: results['engine'] as bool, - ); - outputFile.writeAsStringSync(rewrittenContent); - if (results['stamp'] != null) { - File(results['stamp'] as String).writeAsStringSync('stamp'); + + String Function(String source)? preprocessor; + List replacementPatterns; + String? libraryName; + if (results['ui'] as bool) { + replacementPatterns = uiPatterns; + } else { + libraryName = results['library-name'] as String; + if (libraryName == null) { + throw Exception('library-name must be specified if not rewriting ui'); } + preprocessor = (String source) => preprocessPartFile(source, libraryName!); + replacementPatterns = generatePartsPatterns(libraryName); + } + for (final String inputFilePath in results['source-file'] as Iterable) { + String pathSuffix = inputFilePath.substring(inputDirectoryPath.length); + if (libraryName != null) { + pathSuffix = path.join(libraryName, pathSuffix); + } + final String outputFilePath = path.join(directory.path, pathSuffix); + processFile(inputFilePath, outputFilePath, preprocessor, replacementPatterns); + } + + if (results['api-file'] != null) { + if (libraryName == null) { + throw Exception('library-name must be specified if api-file is specified'); + } + + final String inputFilePath = results['api-file'] as String; + final String outputFilePath = path.join( + directory.path, path.basename(inputFilePath)); + String extraImports = ''; + if (libraryName == 'engine') { + extraImports = "import 'dart:_skwasm_stub' if (dart.library.ffi) 'dart:_skwasm_impl';\n"; + } else if (libraryName == 'skwasm_stub' || libraryName == 'skwasm_impl') { + extraImports = "import 'dart:_engine';\n"; + } + replacementPatterns = generateApiFilePatterns(libraryName, extraImports); + + processFile( + inputFilePath, + outputFilePath, + (String source) => validateApiFile(inputFilePath, source, libraryName!), + replacementPatterns + ); + } + + + if (results['stamp'] != null) { + File(results['stamp'] as String).writeAsStringSync('stamp'); } } -String rewriteFile(String source, {required String filePath, required bool isUi, required bool isEngine}) { - final List replacementPatterns = []; - replacementPatterns.addAll(sharedPatterns); - if (isUi) { - replacementPatterns.addAll(uiPatterns); - } else if (isEngine) { - if (filePath.endsWith('lib/src/engine.dart')) { - _validateEngineSource(filePath, source); - replacementPatterns.addAll(engineLibraryPatterns); - } else { - source = _preprocessEnginePartFile(source); - replacementPatterns.addAll(enginePartsPatterns); - } +void processFile(String inputFilePath, String outputFilePath, String Function(String source)? preprocessor, List replacementPatterns) { + final File inputFile = File(inputFilePath); + final File outputFile = File(outputFilePath) + ..createSync(recursive: true); + outputFile.writeAsStringSync(processSource( + inputFile.readAsStringSync(), + preprocessor, + replacementPatterns)); +} + +String processSource(String source, String Function(String source)? preprocessor, List replacementPatterns) { + if (preprocessor != null) { + source = preprocessor(source); + } + for (final Replacer replacer in stripMetaPatterns) { + source = replacer.perform(source); } for (final Replacer replacer in replacementPatterns) { source = replacer.perform(source); @@ -121,17 +166,17 @@ String rewriteFile(String source, {required String filePath, required bool isUi, return source; } -// Enforces a particular structure in engine.dart source code. +// Enforces a particular structure in top level api files for sublibraries. // -// Code in `engine.dart` must only be made of the library directive, exports, +// Code in api files must only be made of the library directive, exports, // and code comments. Imports are disallowed. Instead, the required imports are // added by this script during the rewrite. -void _validateEngineSource(String engineDartPath, String engineDartCode) { - const List expectedLines = [ - 'library engine;', +String validateApiFile(String apiFilePath, String apiFileCode, String libraryName) { + final List expectedLines = [ + 'library $libraryName;', ]; - final List lines = engineDartCode.split('\n'); + final List lines = apiFileCode.split('\n'); for (int i = 0; i < lines.length; i += 1) { final int lineNumber = i + 1; final String line = lines[i].trim(); @@ -157,20 +202,21 @@ void _validateEngineSource(String engineDartPath, String engineDartCode) { } throw Exception( - 'on line $lineNumber: unexpected code in $engineDartPath. This file ' + 'on line $lineNumber: unexpected code in $apiFilePath. This file ' 'may only contain comments and exports. Found:\n' '$line' ); } + return apiFileCode; } -String _preprocessEnginePartFile(String source) { - if (source.startsWith('part of engine;') || source.contains('\npart of engine;')) { +String preprocessPartFile(String source, String libraryName) { + if (source.startsWith('part of $libraryName;') || source.contains('\npart of $libraryName;')) { // The file hasn't been migrated yet. // Do nothing. } else { // Insert the part directive at the beginning of the file. - source = 'part of engine;\n$source'; + source = 'part of $libraryName;\n$source'; } return source; } diff --git a/engine/src/flutter/web_sdk/test/sdk_rewriter_test.dart b/engine/src/flutter/web_sdk/test/sdk_rewriter_test.dart index 4e17279f335..22a424a66c3 100644 --- a/engine/src/flutter/web_sdk/test/sdk_rewriter_test.dart +++ b/engine/src/flutter/web_sdk/test/sdk_rewriter_test.dart @@ -35,6 +35,8 @@ import 'dart:_js_annotations'; import 'dart:math' as math; import 'dart:typed_data'; import 'dart:ui' as ui; +import 'dart:extra'; + // Comment 2 @@ -44,11 +46,13 @@ part 'engine/file2.dart'; part 'engine/file3.dart'; '''; - final String result = rewriteFile( + final String result = processSource( source, - filePath: '/path/to/lib/web_ui/lib/src/engine.dart', - isUi: false, - isEngine: true, + (String source) => validateApiFile( + '/path/to/lib/web_ui/lib/src/engine.dart', + source, + 'engine'), + generateApiFilePatterns('engine', "import 'dart:extra';\n"), ); expect(result, expected); }); @@ -64,11 +68,13 @@ export 'engine/file3.dart'; Object? caught; try { - rewriteFile( + processSource( source, - filePath: '/path/to/lib/web_ui/lib/src/engine.dart', - isUi: false, - isEngine: true, + (String source) => validateApiFile( + '/path/to/lib/web_ui/lib/src/engine.dart', + source, + 'engine'), + generateApiFilePatterns('engine', ''), ); } catch(error) { caught = error; @@ -112,11 +118,10 @@ void printSomething() { } '''; - final String result = rewriteFile( + final String result = processSource( source, - filePath: '/path/to/lib/web_ui/lib/src/engine/my_file.dart', - isUi: false, - isEngine: true, + (String source) => preprocessPartFile(source, 'engine'), + generatePartsPatterns('engine'), ); expect(result, expected); }); @@ -138,11 +143,10 @@ void printSomething() { } '''; - final String result = rewriteFile( + final String result = processSource( source, - filePath: '/path/to/lib/web_ui/lib/src/engine/my_file.dart', - isUi: false, - isEngine: true, + (String source) => preprocessPartFile(source, 'engine'), + generatePartsPatterns('engine'), ); expect(result, expected); });