Skip to content

Commit eba6dba

Browse files
authored
[web] Migrate Flutter Web DOM usage to JS static interop - 4 (flutter#32938)
* [web] Migrate Flutter Web DOM usage to JS static interop - 3. * [web] Migrate Flutter Web DOM usage to JS static interop - 4.
1 parent 88afc65 commit eba6dba

File tree

6 files changed

+167
-61
lines changed

6 files changed

+167
-61
lines changed

lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
library canvaskit_api;
1414

1515
import 'dart:async';
16-
import 'dart:html' as html;
1716
import 'dart:js' as js;
1817
import 'dart:typed_data';
1918

2019
import 'package:js/js.dart';
2120
import 'package:ui/ui.dart' as ui;
2221

22+
import '../dom.dart';
2323
import '../profiler.dart';
2424

2525
/// Entrypoint into the CanvasKit API.
@@ -132,15 +132,15 @@ extension CanvasKitExtension on CanvasKit {
132132
external TypefaceFontProviderNamespace get TypefaceFontProvider;
133133
external SkTypefaceFactory get Typeface;
134134
external int GetWebGLContext(
135-
html.CanvasElement canvas, SkWebGLContextOptions options);
135+
DomCanvasElement canvas, SkWebGLContextOptions options);
136136
external SkGrContext MakeGrContext(int glContext);
137137
external SkSurface? MakeOnScreenGLSurface(
138138
SkGrContext grContext,
139139
int width,
140140
int height,
141141
ColorSpace colorSpace,
142142
);
143-
external SkSurface MakeSWCanvasSurface(html.CanvasElement canvas);
143+
external SkSurface MakeSWCanvasSurface(DomCanvasElement canvas);
144144

145145
/// Creates an image from decoded pixels represented as a list of bytes.
146146
///
@@ -2332,7 +2332,7 @@ class ProductionCollector implements Collector {
23322332
/// emptied out to prevent memory leaks. This may happen, for example, when the
23332333
/// same object is deleted more than once.
23342334
void collectSkiaObjectsNow() {
2335-
html.window.performance.mark('SkObject collection-start');
2335+
domWindow.performance.mark('SkObject collection-start');
23362336
final int length = _skiaObjectCollectionQueue.length;
23372337
dynamic firstError;
23382338
StackTrace? firstStackTrace;
@@ -2364,8 +2364,8 @@ class ProductionCollector implements Collector {
23642364
}
23652365
_skiaObjectCollectionQueue = <SkDeletable>[];
23662366

2367-
html.window.performance.mark('SkObject collection-end');
2368-
html.window.performance.measure('SkObject collection',
2367+
domWindow.performance.mark('SkObject collection-end');
2368+
domWindow.performance.measure('SkObject collection',
23692369
'SkObject collection-start', 'SkObject collection-end');
23702370

23712371
// It's safe to throw the error here, now that we've processed the queue.
@@ -2539,14 +2539,14 @@ extension SkPartialImageInfoExtension on SkPartialImageInfo {
25392539
// TODO(hterkelsen): Rather than this monkey-patch hack, we should
25402540
// build CanvasKit ourselves. See:
25412541
// https://github.com/flutter/flutter/issues/52588
2542-
void patchCanvasKitModule(html.ScriptElement canvasKitScript) {
2542+
void patchCanvasKitModule(DomHTMLScriptElement canvasKitScript) {
25432543
// First check if `exports` and `module` are already defined. If so, then
25442544
// CommonJS is being used, and we shouldn't have any problems.
25452545
final js.JsFunction objectConstructor = js.context['Object'] as js.JsFunction;
25462546
if (js.context['exports'] == null) {
25472547
final js.JsObject exportsAccessor = js.JsObject.jsify(<String, dynamic>{
25482548
'get': allowInterop(() {
2549-
if (html.document.currentScript == canvasKitScript) {
2549+
if (domDocument.currentScript == canvasKitScript) {
25502550
return js.JsObject(objectConstructor);
25512551
} else {
25522552
return js.context['_flutterWebCachedExports'];
@@ -2563,7 +2563,7 @@ void patchCanvasKitModule(html.ScriptElement canvasKitScript) {
25632563
if (js.context['module'] == null) {
25642564
final js.JsObject moduleAccessor = js.JsObject.jsify(<String, dynamic>{
25652565
'get': allowInterop(() {
2566-
if (html.document.currentScript == canvasKitScript) {
2566+
if (domDocument.currentScript == canvasKitScript) {
25672567
return js.JsObject(objectConstructor);
25682568
} else {
25692569
return js.context['_flutterWebCachedModule'];
@@ -2577,5 +2577,5 @@ void patchCanvasKitModule(html.ScriptElement canvasKitScript) {
25772577
objectConstructor.callMethod(
25782578
'defineProperty', <dynamic>[js.context, 'module', moduleAccessor]);
25792579
}
2580-
html.document.head!.append(canvasKitScript);
2580+
domDocument.head!.appendChild(canvasKitScript);
25812581
}

lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -509,19 +509,20 @@ class HtmlViewEmbedder {
509509
final Surface? overlay = _overlays[viewId];
510510
if (overlay != null) {
511511
skiaSceneHost!
512-
.insertBefore(overlay.htmlElement, elementToInsertBefore);
512+
.insertBefore(overlay.htmlElement as html.Element, elementToInsertBefore);
513513
}
514514
} else {
515515
final html.Element platformViewRoot = _viewClipChains[viewId]!.root;
516516
skiaSceneHost!.append(platformViewRoot);
517517
final Surface? overlay = _overlays[viewId];
518518
if (overlay != null) {
519-
skiaSceneHost!.append(overlay.htmlElement);
519+
skiaSceneHost!.append(overlay.htmlElement as html.Element);
520520
}
521521
}
522522
}
523523
insertBeforeMap?.forEach((int viewId, int viewIdToInsertBefore) {
524-
final html.Element overlay = _overlays[viewId]!.htmlElement;
524+
final html.Element overlay = _overlays[viewId]!.htmlElement as
525+
html.Element;
525526
if (viewIdToInsertBefore != -1) {
526527
final html.Element nextSibling =
527528
_viewClipChains[viewIdToInsertBefore]!.root;
@@ -532,7 +533,8 @@ class HtmlViewEmbedder {
532533
});
533534
if (_didPaintBackupSurface) {
534535
skiaSceneHost!
535-
.append(SurfaceFactory.instance.backupSurface.htmlElement);
536+
.append(SurfaceFactory.instance.backupSurface.htmlElement as
537+
html.Element);
536538
}
537539
} else {
538540
SurfaceFactory.instance.removeSurfacesFromDom();
@@ -551,14 +553,15 @@ class HtmlViewEmbedder {
551553
final Surface? overlay = _overlays[viewId];
552554
skiaSceneHost!.append(platformViewRoot);
553555
if (overlay != null) {
554-
skiaSceneHost!.append(overlay.htmlElement);
556+
skiaSceneHost!.append(overlay.htmlElement as html.Element);
555557
}
556558
_activeCompositionOrder.add(viewId);
557559
unusedViews.remove(viewId);
558560
}
559561
if (_didPaintBackupSurface) {
560562
skiaSceneHost!
561-
.append(SurfaceFactory.instance.backupSurface.htmlElement);
563+
.append(SurfaceFactory.instance.backupSurface.htmlElement as
564+
html.Element);
562565
}
563566
}
564567

lib/web_ui/lib/src/engine/canvaskit/initialization.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'dart:html' as html;
99
import '../../engine.dart' show kProfileMode;
1010
import '../browser_detection.dart';
1111
import '../configuration.dart';
12+
import '../dom.dart';
1213
import '../safe_browser_api.dart';
1314
import 'canvaskit_api.dart';
1415
import 'fonts.dart';
@@ -91,15 +92,17 @@ Future<void> _downloadCanvasKitJs({String? canvasKitBase}) {
9192
? canvasKitBase + 'canvaskit.js'
9293
: canvasKitJavaScriptBindingsUrl;
9394

94-
final html.ScriptElement canvasKitScript = html.ScriptElement();
95+
final DomHTMLScriptElement canvasKitScript = createDomHTMLScriptElement();
9596
canvasKitScript.src = canvasKitJavaScriptUrl;
9697

9798
final Completer<void> canvasKitLoadCompleter = Completer<void>();
98-
late StreamSubscription<html.Event> loadSubscription;
99-
loadSubscription = canvasKitScript.onLoad.listen((_) {
100-
loadSubscription.cancel();
99+
late DomEventListener callback;
100+
void loadEventHandler(DomEvent _) {
101101
canvasKitLoadCompleter.complete();
102-
});
102+
canvasKitScript.removeEventListener('load', callback);
103+
}
104+
callback = allowInterop(loadEventHandler);
105+
canvasKitScript.addEventListener('load', callback);
103106

104107
patchCanvasKitModule(canvasKitScript);
105108

lib/web_ui/lib/src/engine/canvaskit/surface.dart

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import 'package:ui/ui.dart' as ui;
88

99
import '../browser_detection.dart';
1010
import '../configuration.dart';
11+
import '../dom.dart';
1112
import '../platform_dispatcher.dart';
13+
import '../safe_browser_api.dart';
1214
import '../util.dart';
1315
import '../window.dart';
1416
import 'canvas.dart';
@@ -70,15 +72,15 @@ class Surface {
7072
/// We must cache this function because each time we access the tear-off it
7173
/// creates a new object, meaning we won't be able to remove this listener
7274
/// later.
73-
void Function(html.Event)? _cachedContextLostListener;
75+
void Function(DomEvent)? _cachedContextLostListener;
7476

7577
/// A cached copy of the most recently created `webglcontextrestored`
7678
/// listener.
7779
///
7880
/// We must cache this function because each time we access the tear-off it
7981
/// creates a new object, meaning we won't be able to remove this listener
8082
/// later.
81-
void Function(html.Event)? _cachedContextRestoredListener;
83+
void Function(DomEvent)? _cachedContextRestoredListener;
8284

8385
SkGrContext? _grContext;
8486
int? _glContext;
@@ -93,10 +95,10 @@ class Surface {
9395
/// Conversely, the canvas that lives inside this element can be swapped, for
9496
/// example, when the screen size changes, or when the WebGL context is lost
9597
/// due to the browser tab becoming dormant.
96-
final html.Element htmlElement = html.Element.tag('flt-canvas-container');
98+
final DomElement htmlElement = createDomElement('flt-canvas-container');
9799

98100
/// The underlying `<canvas>` element used for this surface.
99-
html.CanvasElement? htmlCanvas;
101+
DomCanvasElement? htmlCanvas;
100102
int _pixelWidth = -1;
101103
int _pixelHeight = -1;
102104

@@ -131,7 +133,7 @@ class Surface {
131133

132134
void addToScene() {
133135
if (!_addedToScene) {
134-
skiaSceneHost!.children.insert(0, htmlElement);
136+
skiaSceneHost!.children.insert(0, htmlElement as html.Element);
135137
}
136138
_addedToScene = true;
137139
}
@@ -207,9 +209,9 @@ class Surface {
207209
void _updateLogicalHtmlCanvasSize() {
208210
final double logicalWidth = _pixelWidth / window.devicePixelRatio;
209211
final double logicalHeight = _pixelHeight / window.devicePixelRatio;
210-
htmlCanvas!.style
211-
..width = '${logicalWidth}px'
212-
..height = '${logicalHeight}px';
212+
final DomCSSStyleDeclaration style = htmlCanvas!.style;
213+
style.setProperty('width', '${logicalWidth}px');
214+
style.setProperty('height', '${logicalHeight}px');
213215
}
214216

215217
/// Translate the canvas so the surface covers the visible portion of the
@@ -224,10 +226,10 @@ class Surface {
224226
final int surfaceHeight = _currentSurfaceSize!.height.ceil();
225227
final double offset =
226228
(_pixelHeight - surfaceHeight) / window.devicePixelRatio;
227-
htmlCanvas!.style.transform = 'translate(0, -${offset}px)';
229+
htmlCanvas!.style.setProperty('transform', 'translate(0, -${offset}px)');
228230
}
229231

230-
void _contextRestoredListener(html.Event event) {
232+
void _contextRestoredListener(DomEvent event) {
231233
assert(
232234
_contextLost,
233235
'Received "webglcontextrestored" event but never received '
@@ -239,7 +241,7 @@ class Surface {
239241
event.preventDefault();
240242
}
241243

242-
void _contextLostListener(html.Event event) {
244+
void _contextLostListener(DomEvent event) {
243245
assert(event.target == htmlCanvas,
244246
'Received a context lost event for a disposed canvas');
245247
final SurfaceFactory factory = SurfaceFactory.instance;
@@ -277,7 +279,7 @@ class Surface {
277279
// we ensure that the rendred picture covers the entire browser window.
278280
_pixelWidth = physicalSize.width.ceil();
279281
_pixelHeight = physicalSize.height.ceil();
280-
final html.CanvasElement htmlCanvas = html.CanvasElement(
282+
final DomCanvasElement htmlCanvas = createDomCanvasElement(
281283
width: _pixelWidth,
282284
height: _pixelHeight,
283285
);
@@ -294,7 +296,7 @@ class Surface {
294296
// accessible.
295297
htmlCanvas.setAttribute('aria-hidden', 'true');
296298

297-
htmlCanvas.style.position = 'absolute';
299+
htmlCanvas.style.setProperty('position', 'absolute');
298300
_updateLogicalHtmlCanvasSize();
299301

300302
// When the browser tab using WebGL goes dormant the browser and/or OS may
@@ -303,8 +305,8 @@ class Surface {
303305
// notification. When we receive this notification we force a new context.
304306
//
305307
// See also: https://www.khronos.org/webgl/wiki/HandlingContextLost
306-
_cachedContextRestoredListener = _contextRestoredListener;
307-
_cachedContextLostListener = _contextLostListener;
308+
_cachedContextRestoredListener = allowInterop(_contextRestoredListener);
309+
_cachedContextLostListener = allowInterop(_contextLostListener);
308310
htmlCanvas.addEventListener(
309311
'webglcontextlost',
310312
_cachedContextLostListener,
@@ -377,7 +379,7 @@ class Surface {
377379
static bool _didWarnAboutWebGlInitializationFailure = false;
378380

379381
CkSurface _makeSoftwareCanvasSurface(
380-
html.CanvasElement htmlCanvas, String reason) {
382+
DomCanvasElement htmlCanvas, String reason) {
381383
if (!_didWarnAboutWebGlInitializationFailure) {
382384
printWarning('WARNING: Falling back to CPU-only rendering. $reason.');
383385
_didWarnAboutWebGlInitializationFailure = true;

0 commit comments

Comments
 (0)