Add stubs for Skwasm renderer (flutter/engine#35748)

This commit is contained in:
Jackson Gardner 2022-09-01 11:36:29 -07:00 committed by GitHub
parent 9d4e72eb7b
commit 3abd78d817
14 changed files with 682 additions and 177 deletions

View File

@ -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

View File

@ -186,11 +186,16 @@ Future<void> compileTests(List<FilePath> testFiles) async {
// different dart2js options.
final List<FilePath> htmlTargets = <FilePath>[];
final List<FilePath> canvasKitTargets = <FilePath>[];
final List<FilePath> skwasmTargets = <FilePath>[];
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<void> compileTests(List<FilePath> testFiles) async {
await Future.wait(<Future<void>>[
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<void> _compileTestsInParallel({
required List<FilePath> targets,
required bool forCanvasKit,
bool forCanvasKit = false,
bool forSkwasm = false,
}) async {
final Stream<bool> 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<void> _compileTestsInParallel({
/// directory before test are build. See [_copyFilesFromTestToBuild].
///
/// Later the extra files will be deleted in [_cleanupExtraFilesUnderTestDir].
Future<bool> compileUnitTest(FilePath input, {required bool forCanvasKit}) async {
Future<bool> 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<bool> 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',

View File

@ -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

View File

@ -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<String>? fontFamilyFallback,
double? fontSize,
double? letterSpacing,
double? wordSpacing,
double? height,
ui.TextLeadingDistribution? leadingDistribution,
ui.Locale? locale,
ui.Paint? background,
ui.Paint? foreground,
List<ui.Shadow>? shadows,
List<ui.FontFeature>? fontFeatures,
List<ui.FontVariation>? 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<String>? 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<ui.Shadow>? shadows,
required List<ui.FontFeature>? fontFeatures,
required List<ui.FontVariation>? fontVariations,
});
ui.ParagraphStyle createParagraphStyle({

View File

@ -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';

View File

@ -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<ui.Color> colors, [List<double>? 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<ui.Color> colors, [List<double>? 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<ui.Color> colors, [List<double>? 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<String>? 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<ui.Color> colors, [List<double>? 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<String>? fontFamilyFallback, double? fontSize, double? letterSpacing, double? wordSpacing, double? height, ui.TextLeadingDistribution? leadingDistribution, ui.Locale? locale, ui.Paint? background, ui.Paint? foreground, List<ui.Shadow>? shadows, List<ui.FontFeature>? fontFeatures, List<ui.FontVariation>? fontVariations}) {
throw UnimplementedError('Not yet implemented');
}
@override
ui.Vertices createVertices(ui.VertexMode mode, List<ui.Offset> positions, {List<ui.Offset>? textureCoordinates, List<ui.Color>? colors, List<int>? 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<void> initialize() {
throw UnimplementedError('Not yet implemented');
}
@override
Future<ui.Codec> instantiateImageCodec(Uint8List list, {int? targetWidth, int? targetHeight, bool allowUpscaling = true}) {
throw UnimplementedError('Not yet implemented');
}
@override
Future<ui.Codec> 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');
}
}

View File

@ -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';

View File

@ -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<ui.Color> colors, [List<double>? 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<ui.Color> colors, [List<double>? 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<ui.Color> colors, [List<double>? 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<String>? 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<ui.Color> colors, [List<double>? 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<String>? fontFamilyFallback, double? fontSize, double? letterSpacing, double? wordSpacing, double? height, ui.TextLeadingDistribution? leadingDistribution, ui.Locale? locale, ui.Paint? background, ui.Paint? foreground, List<ui.Shadow>? shadows, List<ui.FontFeature>? fontFeatures, List<ui.FontVariation>? fontVariations}) {
throw UnimplementedError('Skwasm not implemented on this platform.');
}
@override
ui.Vertices createVertices(ui.VertexMode mode, List<ui.Offset> positions, {List<ui.Offset>? textureCoordinates, List<ui.Color>? colors, List<int>? 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<void> initialize() {
throw UnimplementedError('Skwasm not implemented on this platform.');
}
@override
Future<ui.Codec> instantiateImageCodec(Uint8List list, {int? targetWidth, int? targetHeight, bool allowUpscaling = true}) {
throw UnimplementedError('Skwasm not implemented on this platform.');
}
@override
Future<ui.Codec> 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.');
}
}

View File

@ -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<void> testMain() async {
group('Skwasm stub tests', () {
test('Skwasm stub renderer throws', () {
expect(renderer, isA<SkwasmRenderer>());
expect(() {
renderer.initialize();
}, throwsUnimplementedError);
});
});
}

View File

@ -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 += [

View File

@ -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"
}
}
}

View File

@ -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"

View File

@ -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<Replacer> uiPatterns = <Replacer>[
@ -33,10 +34,11 @@ export 'dart:_engine'
),
];
final List<Replacer> engineLibraryPatterns = <Replacer>[
AllReplacer(RegExp(r'library\s+engine;'), '''
List<Replacer> generateApiFilePatterns(String libraryName, String extraImports) {
return <Replacer>[
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<Replacer> enginePartsPatterns = <Replacer>[
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<Replacer> generatePartsPatterns(String libraryName) {
return <Replacer>[
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<Replacer> sharedPatterns = <Replacer>[
final List<Replacer> stripMetaPatterns = <Replacer>[
AllReplacer(RegExp(r"import\s*'package:meta/meta.dart';"), ''),
AllReplacer('@required', ''),
AllReplacer('@protected', ''),
@ -82,38 +90,75 @@ void main(List<String> 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<String>) {
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<Replacer> 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>) {
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<Replacer> replacementPatterns = <Replacer>[];
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<Replacer> 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<Replacer> 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<String> expectedLines = <String>[
'library engine;',
String validateApiFile(String apiFilePath, String apiFileCode, String libraryName) {
final List<String> expectedLines = <String>[
'library $libraryName;',
];
final List<String> lines = engineDartCode.split('\n');
final List<String> 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;
}

View File

@ -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);
});