Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[web] Reland "Migrate Flutter Web DOM usage to JS static interop - 3" #33114

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import 'dart:typed_data';
import 'package:js/js.dart';
import 'package:ui/ui.dart' as ui;

import '../dom.dart';
import '../profiler.dart';

/// Entrypoint into the CanvasKit API.
Expand Down Expand Up @@ -2332,7 +2333,7 @@ class ProductionCollector implements Collector {
/// emptied out to prevent memory leaks. This may happen, for example, when the
/// same object is deleted more than once.
void collectSkiaObjectsNow() {
html.window.performance.mark('SkObject collection-start');
domWindow.performance.mark('SkObject collection-start');
final int length = _skiaObjectCollectionQueue.length;
dynamic firstError;
StackTrace? firstStackTrace;
Expand Down Expand Up @@ -2364,8 +2365,8 @@ class ProductionCollector implements Collector {
}
_skiaObjectCollectionQueue = <SkDeletable>[];

html.window.performance.mark('SkObject collection-end');
html.window.performance.measure('SkObject collection',
domWindow.performance.mark('SkObject collection-end');
domWindow.performance.measure('SkObject collection',
'SkObject collection-start', 'SkObject collection-end');

// It's safe to throw the error here, now that we've processed the queue.
Expand Down Expand Up @@ -2539,14 +2540,14 @@ extension SkPartialImageInfoExtension on SkPartialImageInfo {
// TODO(hterkelsen): Rather than this monkey-patch hack, we should
// build CanvasKit ourselves. See:
// https://github.com/flutter/flutter/issues/52588
void patchCanvasKitModule(html.ScriptElement canvasKitScript) {
void patchCanvasKitModule(DomHTMLScriptElement canvasKitScript) {
// First check if `exports` and `module` are already defined. If so, then
// CommonJS is being used, and we shouldn't have any problems.
final js.JsFunction objectConstructor = js.context['Object'] as js.JsFunction;
if (js.context['exports'] == null) {
final js.JsObject exportsAccessor = js.JsObject.jsify(<String, dynamic>{
'get': allowInterop(() {
if (html.document.currentScript == canvasKitScript) {
if (domDocument.currentScript == canvasKitScript) {
return js.JsObject(objectConstructor);
} else {
return js.context['_flutterWebCachedExports'];
Expand All @@ -2563,7 +2564,7 @@ void patchCanvasKitModule(html.ScriptElement canvasKitScript) {
if (js.context['module'] == null) {
final js.JsObject moduleAccessor = js.JsObject.jsify(<String, dynamic>{
'get': allowInterop(() {
if (html.document.currentScript == canvasKitScript) {
if (domDocument.currentScript == canvasKitScript) {
return js.JsObject(objectConstructor);
} else {
return js.context['_flutterWebCachedModule'];
Expand All @@ -2577,5 +2578,5 @@ void patchCanvasKitModule(html.ScriptElement canvasKitScript) {
objectConstructor.callMethod(
'defineProperty', <dynamic>[js.context, 'module', moduleAccessor]);
}
html.document.head!.append(canvasKitScript);
domDocument.head!.appendChild(canvasKitScript);
}
13 changes: 8 additions & 5 deletions lib/web_ui/lib/src/engine/canvaskit/initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'dart:html' as html;
import '../../engine.dart' show kProfileMode;
import '../browser_detection.dart';
import '../configuration.dart';
import '../dom.dart';
import '../safe_browser_api.dart';
import 'canvaskit_api.dart';
import 'fonts.dart';
Expand Down Expand Up @@ -91,15 +92,17 @@ Future<void> _downloadCanvasKitJs({String? canvasKitBase}) {
? canvasKitBase + 'canvaskit.js'
: canvasKitJavaScriptBindingsUrl;

final html.ScriptElement canvasKitScript = html.ScriptElement();
final DomHTMLScriptElement canvasKitScript = createDomHTMLScriptElement();
canvasKitScript.src = canvasKitJavaScriptUrl;

final Completer<void> canvasKitLoadCompleter = Completer<void>();
late StreamSubscription<html.Event> loadSubscription;
loadSubscription = canvasKitScript.onLoad.listen((_) {
loadSubscription.cancel();
late DomEventListener callback;
void loadEventHandler(DomEvent _) {
canvasKitLoadCompleter.complete();
});
canvasKitScript.removeEventListener('load', callback);
}
callback = allowInterop(loadEventHandler);
canvasKitScript.addEventListener('load', callback);

patchCanvasKitModule(canvasKitScript);

Expand Down
63 changes: 63 additions & 0 deletions lib/web_ui/lib/src/engine/dom.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class DomWindow {}
extension DomWindowExtension on DomWindow {
external DomDocument get document;
external DomNavigator get navigator;
external DomPerformance get performance;
}

@JS('window')
Expand All @@ -44,16 +45,45 @@ class DomDocument {}
extension DomDocumentExtension on DomDocument {
external /* List<Node> */ List<Object?> querySelectorAll(String selectors);
external DomElement createElement(String name, [dynamic options]);
external DomHTMLScriptElement? get currentScript;
}

@JS()
@staticInterop
class DomHTMLDocument extends DomDocument {}

extension DomHTMLDocumentExtension on DomHTMLDocument {
external DomHTMLHeadElement? get head;
}

@JS('document')
external DomHTMLDocument get domDocument;

@JS()
@staticInterop
class DomEventTarget {}

extension DomEventTargetExtension on DomEventTarget {
external void addEventListener(String type, DomEventListener? listener,
[bool? useCapture]);
external void removeEventListener(String type, DomEventListener? listener,
[bool? useCapture]);
}

typedef DomEventListener = void Function(DomEvent event);

@JS()
@staticInterop
class DomEvent {}

@JS()
@staticInterop
class DomNode extends DomEventTarget {}

extension DomNodeExtension on DomNode {
external DomNode appendChild(DomNode node);
}

@JS()
@staticInterop
class DomElement extends DomNode {}
Expand All @@ -72,6 +102,39 @@ extension DomHTMLMetaElementExtension on DomHTMLMetaElement {
external String get content;
}

@JS()
@staticInterop
class DomHTMLHeadElement extends DomHTMLElement {}

@JS()
@staticInterop
class DomHTMLScriptElement extends DomHTMLElement {}

extension DomHTMLScriptElementExtension on DomHTMLScriptElement {
external set src(String value);
}

DomHTMLScriptElement createDomHTMLScriptElement() =>
domDocument.createElement('script') as DomHTMLScriptElement;

@JS()
@staticInterop
class DomPerformance extends DomEventTarget {}

extension DomPerformanceExtension on DomPerformance {
external DomPerformanceEntry? mark(String markName);
external DomPerformanceMeasure? measure(
String measureName, String? startMark, String? endMark);
}

@JS()
@staticInterop
class DomPerformanceEntry {}

@JS()
@staticInterop
class DomPerformanceMeasure extends DomPerformanceEntry {}

@JS()
@staticInterop
class DomCanvasElement extends DomHTMLElement {}
Expand Down