Skip to content

Commit

Permalink
[web] feature-detect and use ImageDecoder for all image decoding (flu…
Browse files Browse the repository at this point in the history
  • Loading branch information
yjbanov authored Nov 18, 2021
1 parent 29c5631 commit 9258e0c
Show file tree
Hide file tree
Showing 22 changed files with 1,154 additions and 250 deletions.
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,8 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/fonts.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image_filter.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image_wasm_codecs.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/initialization.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer.dart
Expand Down
9 changes: 8 additions & 1 deletion lib/web_ui/dev/chrome.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,14 @@ class Chrome extends Browser {
'--headless',
if (isChromeNoSandbox)
'--no-sandbox',
'--window-size=$kMaxScreenshotWidth,$kMaxScreenshotHeight', // When headless, this is the actual size of the viewport
// When headless, this is the actual size of the viewport.
if (!debug)
'--window-size=$kMaxScreenshotWidth,$kMaxScreenshotHeight',
// When debugging, run in maximized mode so there's enough room for DevTools.
if (debug)
'--start-maximized',
if (debug)
'--auto-open-devtools-for-tabs',
'--disable-extensions',
'--disable-popup-blocking',
// Indicates that the browser is in "browse without sign-in" (Guest session) mode.
Expand Down
2 changes: 1 addition & 1 deletion lib/web_ui/dev/goldens_lock.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
repository: https://github.com/flutter/goldens.git
revision: 8e169f3ca5cf4af283a2ff4cfd98a564fb173adf
revision: 0dd2e82050422c05e9daf652fa4267fb7c01f260
1 change: 1 addition & 0 deletions lib/web_ui/dev/run.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class RunCommand extends Command<bool> with ArgUtils<bool> {
browserName: browserName,
isDebug: false,
doUpdateScreenshotGoldens: false,
overridePathToCanvasKit: null,
),
};

Expand Down
7 changes: 7 additions & 0 deletions lib/web_ui/dev/steps/run_tests_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ class RunTestsStep implements PipelineStep {
required this.isDebug,
required this.doUpdateScreenshotGoldens,
this.testFiles,
required this.overridePathToCanvasKit,
}) : _browserEnvironment = getBrowserEnvironment(browserName);

final String browserName;
final List<FilePath>? testFiles;
final bool isDebug;
final bool doUpdateScreenshotGoldens;
final String? overridePathToCanvasKit;

final BrowserEnvironment _browserEnvironment;

Expand Down Expand Up @@ -120,6 +122,7 @@ class RunTestsStep implements PipelineStep {
isDebug: isDebug,
doUpdateScreenshotGoldens: doUpdateScreenshotGoldens,
skiaClient: skiaClient,
overridePathToCanvasKit: overridePathToCanvasKit,
);
}

Expand All @@ -133,6 +136,7 @@ class RunTestsStep implements PipelineStep {
isDebug: isDebug,
doUpdateScreenshotGoldens: doUpdateScreenshotGoldens,
skiaClient: skiaClient,
overridePathToCanvasKit: overridePathToCanvasKit,
);
_checkExitCode('Unit tests');
}
Expand All @@ -148,6 +152,7 @@ class RunTestsStep implements PipelineStep {
isDebug: isDebug,
doUpdateScreenshotGoldens: doUpdateScreenshotGoldens,
skiaClient: skiaClient,
overridePathToCanvasKit: overridePathToCanvasKit,
);
_checkExitCode('Golden tests');
}
Expand Down Expand Up @@ -234,6 +239,7 @@ Future<void> _runTestBatch({
required int concurrency,
required bool expectFailure,
required SkiaGoldClient? skiaClient,
required String? overridePathToCanvasKit,
}) async {
final String configurationFilePath = pathlib.join(
environment.webUiRootDir.path,
Expand Down Expand Up @@ -271,6 +277,7 @@ Future<void> _runTestBatch({
// expected to fail.
doUpdateScreenshotGoldens: !expectFailure && doUpdateScreenshotGoldens,
skiaClient: skiaClient,
overridePathToCanvasKit: overridePathToCanvasKit,
);
});

Expand Down
79 changes: 79 additions & 0 deletions lib/web_ui/dev/test_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class BrowserPlatform extends PlatformPlugin {
required BrowserEnvironment browserEnvironment,
required bool doUpdateScreenshotGoldens,
required SkiaGoldClient? skiaClient,
required String? overridePathToCanvasKit,
}) async {
final shelf_io.IOServer server = shelf_io.IOServer(await HttpMultiServer.loopback(0));
return BrowserPlatform._(
Expand All @@ -62,6 +63,7 @@ class BrowserPlatform extends PlatformPlugin {
doUpdateScreenshotGoldens: doUpdateScreenshotGoldens,
packageConfig: await loadPackageConfigUri((await Isolate.packageConfig)!),
skiaClient: skiaClient,
overridePathToCanvasKit: overridePathToCanvasKit,
);
}

Expand Down Expand Up @@ -105,13 +107,16 @@ class BrowserPlatform extends PlatformPlugin {
/// and update images.
final SkiaGoldClient? skiaClient;

final String? overridePathToCanvasKit;

BrowserPlatform._({
required this.browserEnvironment,
required this.server,
required this.isDebug,
required this.doUpdateScreenshotGoldens,
required this.packageConfig,
required this.skiaClient,
required this.overridePathToCanvasKit,
}) : _screenshotManager = browserEnvironment.getScreenshotManager() {
// The cascade of request handlers.
final shelf.Cascade cascade = shelf.Cascade()
Expand All @@ -128,9 +133,13 @@ class BrowserPlatform extends PlatformPlugin {
// * Assets that are part of the engine sources, such as Ahem.ttf
.add(_packageUrlHandler)

.add(_canvasKitOverrideHandler)

// Serves files from the web_ui/build/ directory at the root (/) URL path.
.add(buildDirectoryHandler)

.add(_testImageListingHandler)

// Serves the initial HTML for the test.
.add(_testBootstrapHandler)

Expand All @@ -153,6 +162,76 @@ class BrowserPlatform extends PlatformPlugin {
server.mount(cascade.handler);
}

/// If a path to a custom local build of CanvasKit was specified, serve from
/// there instead of serving the default CanvasKit in the build/ directory.
Future<shelf.Response> _canvasKitOverrideHandler(shelf.Request request) async {
final String? pathOverride = overridePathToCanvasKit;

if (pathOverride == null || !request.url.path.startsWith('canvaskit/')) {
return shelf.Response.notFound('Not a request for CanvasKit.');
}

final File file = File(p.joinAll(<String>[
pathOverride,
...p.split(request.url.path).skip(1),
]));

if (!file.existsSync()) {
return shelf.Response.notFound('File not found: ${request.url.path}');
}

final String extension = p.extension(file.path);
final String? contentType = contentTypes[extension];

if (contentType == null) {
final String error = 'Failed to determine Content-Type for "${request.url.path}".';
stderr.writeln(error);
return shelf.Response.internalServerError(body: error);
}

return shelf.Response.ok(
file.readAsBytesSync(),
headers: <String, Object>{
HttpHeaders.contentTypeHeader: contentType,
},
);
}

/// Lists available test images under `web_ui/build/test_images`.
Future<shelf.Response> _testImageListingHandler(shelf.Request request) async {
const Map<String, String> supportedImageTypes = <String, String>{
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.webp': 'image/webp',
'.bmp': 'image/bmp',
};

if (request.url.path != 'test_images/') {
return shelf.Response.notFound('Not found.');
}

final Directory testImageDirectory = Directory(p.join(
env.environment.webUiBuildDir.path,
'test_images',
));

final List<String> testImageFiles = testImageDirectory
.listSync(recursive: true)
.whereType<File>()
.map<String>((File file) => p.relative(file.path, from: testImageDirectory.path))
.where((String path) => supportedImageTypes.containsKey(p.extension(path)))
.toList();

return shelf.Response.ok(
json.encode(testImageFiles),
headers: <String, Object>{
HttpHeaders.contentTypeHeader: 'application/json',
},
);
}

Future<shelf.Response> _fileNotFoundCatcher(shelf.Request request) async {
print('HTTP 404: ${request.url}');
return shelf.Response.notFound('File not found');
Expand Down
14 changes: 12 additions & 2 deletions lib/web_ui/dev/test_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ class TestCommand extends Command<bool> with ArgUtils<bool> {
..addOption(
'browser',
defaultsTo: 'chrome',
help: 'An option to choose a browser to run the tests. Tests only work '
' on Chrome for now.',
help: 'An option to choose a browser to run the tests. By default '
'tests run in Chrome.',
)
..addFlag(
'fail-early',
Expand All @@ -80,6 +80,12 @@ class TestCommand extends Command<bool> with ArgUtils<bool> {
'failure. If not set, the test runner will continue running '
'test despite failures and will report them after all tests '
'finish.',
)
..addOption(
'canvaskit-path',
help: 'Optional. The path to a local build of CanvasKit to use in '
'tests. If omitted, the test runner uses the default CanvasKit '
'build.',
);
}

Expand Down Expand Up @@ -118,6 +124,9 @@ class TestCommand extends Command<bool> with ArgUtils<bool> {
/// Whether to fetch the goldens repo prior to running tests.
bool get skipGoldensRepoFetch => boolArg('skip-goldens-repo-fetch');

/// Path to a CanvasKit build. Overrides the default CanvasKit.
String? get overridePathToCanvasKit => argResults!['canvaskit-path'] as String?;

@override
Future<bool> run() async {
final List<FilePath> testFiles = runAllTests
Expand All @@ -135,6 +144,7 @@ class TestCommand extends Command<bool> with ArgUtils<bool> {
testFiles: testFiles,
isDebug: isDebug,
doUpdateScreenshotGoldens: doUpdateScreenshotGoldens,
overridePathToCanvasKit: overridePathToCanvasKit,
),
]);
await testPipeline.run();
Expand Down
4 changes: 4 additions & 0 deletions lib/web_ui/lib/src/engine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ export 'engine/canvaskit/image.dart';

export 'engine/canvaskit/image_filter.dart';

export 'engine/canvaskit/image_wasm_codecs.dart';

export 'engine/canvaskit/image_web_codecs.dart';

export 'engine/canvaskit/initialization.dart';

export 'engine/canvaskit/interval_tree.dart';
Expand Down
23 changes: 22 additions & 1 deletion lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,15 @@ class CanvasKit {
/// Typically pixel data is obtained using [SkImage.readPixels]. The
/// parameters specified in [SkImageInfo] passed [SkImage.readPixels] must
/// match [info].
external SkImage MakeImage(
external SkImage? MakeImage(
SkImageInfo info,
Uint8List pixels,
int bytesPerRow,
);
external SkImage? MakeLazyImageFromTextureSource(
Object src,
SkPartialImageInfo info,
);
}

@JS('window.CanvasKitInit')
Expand Down Expand Up @@ -2141,3 +2145,20 @@ class SkImageInfo {
external SkImageInfo makeColorType(SkColorType colorType);
external SkImageInfo makeWH(int width, int height);
}

@JS()
@anonymous
class SkPartialImageInfo {
external factory SkPartialImageInfo({
required int width,
required int height,
required SkColorType colorType,
required SkAlphaType alphaType,
required ColorSpace colorSpace,
});
external SkAlphaType get alphaType;
external ColorSpace get colorSpace;
external SkColorType get colorType;
external int get height;
external int get width;
}
2 changes: 1 addition & 1 deletion lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ class HtmlViewEmbedder {

// Try reusing a cached overlay created for another platform view.
final Surface overlay = SurfaceFactory.instance.getOverlay()!;
overlay.createOrUpdateSurfaces(_frameSize);
overlay.createOrUpdateSurface(_frameSize);
_overlays[viewId] = overlay;
}

Expand Down
Loading

0 comments on commit 9258e0c

Please sign in to comment.