未验证 提交 cba6c1ea 编写于 作者: H Harry Terkelsen 提交者: GitHub

Use cached CanvasKit instance if available (#26059)

* If CanvasKit has already been initialized, don't load it again.

This could be useful for hot restart or for DartPad.

* Don't redownload script if it is already loaded.

* trailing whitespace

* Touch up comments
上级 01ce6a1b
......@@ -16,8 +16,15 @@ late CanvasKit canvasKit;
/// static APIs.
///
/// See, e.g. [SkPaint].
///
/// This also acts as a cache of an initialized CanvasKit instance. We can use
/// this, for example, to perform a hot restart without needing to redownload
/// and reinitialize CanvasKit.
@JS('window.flutterCanvasKit')
external set windowFlutterCanvasKit(CanvasKit? value);
@JS('window.flutterCanvasKit')
external set windowFlutterCanvasKit(CanvasKit value);
external CanvasKit? get windowFlutterCanvasKit;
@JS()
@anonymous
......@@ -141,7 +148,7 @@ class ColorSpace {}
@anonymous
class SkWebGLContextOptions {
external factory SkWebGLContextOptions({
required int anitalias,
required int antialias,
// WebGL version: 1 or 2.
required int majorVersion,
});
......
......@@ -87,20 +87,23 @@ String canvasKitWasmModuleUrl(String file) => canvasKitBuildUrl + file;
/// This calls `CanvasKitInit` and assigns the global [canvasKit] object.
Future<void> initializeCanvasKit() {
final Completer<void> canvasKitCompleter = Completer<void>();
late StreamSubscription<html.Event> loadSubscription;
loadSubscription = domRenderer.canvasKitScript!.onLoad.listen((_) {
loadSubscription.cancel();
final CanvasKitInitPromise canvasKitInitPromise =
CanvasKitInit(CanvasKitInitOptions(
locateFile: js.allowInterop(
(String file, String unusedBase) => canvasKitWasmModuleUrl(file)),
));
canvasKitInitPromise.then(js.allowInterop((CanvasKit ck) {
canvasKit = ck;
windowFlutterCanvasKit = canvasKit;
canvasKitCompleter.complete();
}));
});
if (windowFlutterCanvasKit != null) {
canvasKit = windowFlutterCanvasKit!;
canvasKitCompleter.complete();
} else {
domRenderer.canvasKitLoaded!.then((_) {
final CanvasKitInitPromise canvasKitInitPromise =
CanvasKitInit(CanvasKitInitOptions(
locateFile: js.allowInterop(
(String file, String unusedBase) => canvasKitWasmModuleUrl(file)),
));
canvasKitInitPromise.then(js.allowInterop((CanvasKit ck) {
canvasKit = ck;
windowFlutterCanvasKit = canvasKit;
canvasKitCompleter.complete();
}));
});
}
/// Add a Skia scene host.
skiaSceneHost = html.Element.tag('flt-scene');
......
......@@ -210,7 +210,7 @@ class Surface {
SkWebGLContextOptions(
// Default to no anti-aliasing. Paint commands can be explicitly
// anti-aliased by setting their `Paint` object's `antialias` property.
anitalias: 0,
antialias: 0,
majorVersion: webGLVersion,
),
);
......
......@@ -48,6 +48,9 @@ class DomRenderer {
html.ScriptElement? get canvasKitScript => _canvasKitScript;
html.ScriptElement? _canvasKitScript;
Future<void>? get canvasKitLoaded => _canvasKitLoaded;
Future<void>? _canvasKitLoaded;
/// The element that contains the [sceneElement].
///
/// This element is created and inserted in the HTML DOM once. It is never
......@@ -441,7 +444,8 @@ flt-glass-pane * {
_sceneHostElement = createElement('flt-scene-host');
final html.Element semanticsHostElement = createElement('flt-semantics-host');
final html.Element semanticsHostElement =
createElement('flt-semantics-host');
semanticsHostElement.style
..position = 'absolute'
..transformOrigin = '0 0 0';
......@@ -509,11 +513,21 @@ flt-glass-pane * {
});
}
if (useCanvasKit) {
// Only reset CanvasKit if it's not already available.
if (useCanvasKit && windowFlutterCanvasKit == null) {
_canvasKitScript?.remove();
_canvasKitScript = html.ScriptElement();
_canvasKitScript!.src = canvasKitJavaScriptBindingsUrl;
Completer<void> canvasKitLoadCompleter = Completer<void>();
_canvasKitLoaded = canvasKitLoadCompleter.future;
late StreamSubscription<html.Event> loadSubscription;
loadSubscription = _canvasKitScript!.onLoad.listen((_) {
loadSubscription.cancel();
canvasKitLoadCompleter.complete(true);
});
// TODO(hterkelsen): Rather than this monkey-patch hack, we should
// build CanvasKit ourselves. See:
// https://github.com/flutter/flutter/issues/52588
......@@ -591,7 +605,8 @@ flt-glass-pane * {
/// logical pixels. To compensate, we inject an inverse scale at the root
/// level.
void updateSemanticsScreenProperties() {
_semanticsHostElement!.style.transform = 'scale(${1 / html.window.devicePixelRatio})';
_semanticsHostElement!.style.transform =
'scale(${1 / html.window.devicePixelRatio})';
}
/// Called immediately after browser window metrics change.
......
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart' as ui;
import 'common.dart';
void main() {
internalBootstrapBrowserTest(() => testMain);
}
void testMain() {
group('initialize', () {
test(
're-uses the same initialized instance if it is already set on the window',
() async {
expect(windowFlutterCanvasKit, isNull);
DomRenderer();
await ui.webOnlyInitializePlatform(
assetManager: WebOnlyMockAssetManager());
expect(windowFlutterCanvasKit, isNotNull);
var firstCanvasKitInstance = windowFlutterCanvasKit;
// Triggers a reset of the CanvasKit script element.
DomRenderer();
await ui.webOnlyInitializePlatform(
assetManager: WebOnlyMockAssetManager());
// The instance is the same.
expect(firstCanvasKitInstance, windowFlutterCanvasKit);
});
// TODO: https://github.com/flutter/flutter/issues/60040
}, skip: isIosSafari);
}
......@@ -20,7 +20,8 @@ void testMain() {
test('populates flt-renderer and flt-build-mode', () {
DomRenderer();
expect(html.document.body!.attributes['flt-renderer'], 'canvaskit (requested explicitly)');
expect(html.document.body!.attributes['flt-renderer'],
'canvaskit (requested explicitly)');
expect(html.document.body!.attributes['flt-build-mode'], 'debug');
});
// TODO: https://github.com/flutter/flutter/issues/60040
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册