[web] Migrate Flutter Web DOM usage to JS static interop - 38. (#33374)

diff --git a/lib/web_ui/lib/initialization.dart b/lib/web_ui/lib/initialization.dart
index 75f1f24..8ee067b 100644
--- a/lib/web_ui/lib/initialization.dart
+++ b/lib/web_ui/lib/initialization.dart
@@ -4,6 +4,8 @@
 
 // TODO(yjbanov): rename this file to web_only_api.dart.
 //                https://github.com/flutter/flutter/issues/100394
+//                Rather than extending this file with new APIs, we
+//                should instead use js interop.
 
 // This file contains extra web-only API that non-web engines do not have.
 //
@@ -129,13 +131,13 @@
   engine.pluginMessageCallHandler = handler;
 }
 
-/// A function which takes a unique `id` and creates an HTML element.
-typedef PlatformViewFactory = html.Element Function(int viewId);
-
 /// A registry for factories that create platform views.
 class PlatformViewRegistry {
-  /// Register [viewTypeId] as being creating by the given [factory].
-  bool registerViewFactory(String viewTypeId, PlatformViewFactory viewFactory,
+  /// Register [viewTypeId] as being creating by the given [viewFactory].
+  /// [viewFactory] can be any function that takes an integer and returns an
+  /// `HTMLElement` DOM object.
+  bool registerViewFactory(String viewTypeId,
+      Object Function(int viewId) viewFactory,
       {bool isVisible = true}) {
     // TODO(web): Deprecate this once there's another way of calling `registerFactory` (js interop?)
     return engine.platformViewManager
diff --git a/lib/web_ui/lib/src/engine/browser_detection.dart b/lib/web_ui/lib/src/engine/browser_detection.dart
index 59dc018..8718be3 100644
--- a/lib/web_ui/lib/src/engine/browser_detection.dart
+++ b/lib/web_ui/lib/src/engine/browser_detection.dart
@@ -185,7 +185,7 @@
     return OperatingSystem.iOs;
   } else if (userAgent.contains('Android')) {
     // The Android OS reports itself as "Linux armv8l" in
-    // [html.window.navigator.platform]. So we have to check the user-agent to
+    // [domWindow.navigator.platform]. So we have to check the user-agent to
     // determine if the OS is Android or not.
     return OperatingSystem.android;
   } else if (platform.startsWith('Linux')) {
diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart
index 88dcd3e..4775a89 100644
--- a/lib/web_ui/lib/src/engine/dom.dart
+++ b/lib/web_ui/lib/src/engine/dom.dart
@@ -47,8 +47,11 @@
         if (pseudoElt != null) pseudoElt
       ]) as DomCSSStyleDeclaration;
   external DomScreen? get screen;
+  external int requestAnimationFrame(DomRequestAnimationFrameCallback callback);
 }
 
+typedef DomRequestAnimationFrameCallback = void Function(num highResTime);
+
 @JS()
 @staticInterop
 class DomConsole {}
diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart
index 0aa7f84..a343133 100644
--- a/lib/web_ui/lib/src/engine/embedder.dart
+++ b/lib/web_ui/lib/src/engine/embedder.dart
@@ -345,7 +345,7 @@
       //
       // VisualViewport API is not enabled in Firefox as well. On the other hand
       // Firefox returns correct values for innerHeight, innerWidth.
-      // Firefox also triggers html.window.onResize therefore this timer does
+      // Firefox also triggers domWindow.onResize therefore this timer does
       // not need to be set up for Firefox.
       final int initialInnerWidth = domWindow.innerWidth!;
       // Counts how many times screen size was checked. It is checked up to 5
@@ -539,7 +539,7 @@
   String get currentHtml => _rootApplicationElement?.outerHTML ?? '';
 }
 
-// Applies the required global CSS to an incoming [html.CssStyleSheet] `sheet`.
+// Applies the required global CSS to an incoming [DomCSSStyleSheet] `sheet`.
 void applyGlobalCssRulesToSheet(
   DomCSSStyleSheet sheet, {
   required BrowserEngine browserEngine,
diff --git a/lib/web_ui/lib/src/engine/font_change_util.dart b/lib/web_ui/lib/src/engine/font_change_util.dart
index 14cfcf0..c4b8767 100644
--- a/lib/web_ui/lib/src/engine/font_change_util.dart
+++ b/lib/web_ui/lib/src/engine/font_change_util.dart
@@ -3,10 +3,11 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:html' as html;
 import 'dart:typed_data';
 
+import 'dom.dart';
 import 'platform_dispatcher.dart';
+import 'safe_browser_api.dart';
 import 'services.dart';
 
 final ByteData? _fontChangeMessage =
@@ -22,13 +23,13 @@
   if (!_fontChangeScheduled) {
     _fontChangeScheduled = true;
     // Batch updates into next animationframe.
-    html.window.requestAnimationFrame((num _) {
+    domWindow.requestAnimationFrame(allowInterop((num _) {
       _fontChangeScheduled = false;
       EnginePlatformDispatcher.instance.invokeOnPlatformMessage(
         'flutter/system',
         _fontChangeMessage,
         (_) {},
       );
-    });
+    }));
   }
 }
diff --git a/lib/web_ui/lib/src/engine/initialization.dart b/lib/web_ui/lib/src/engine/initialization.dart
index f1210d8..71da02a 100644
--- a/lib/web_ui/lib/src/engine/initialization.dart
+++ b/lib/web_ui/lib/src/engine/initialization.dart
@@ -4,7 +4,6 @@
 
 import 'dart:async';
 import 'dart:developer' as developer;
-import 'dart:html' as html;
 
 import 'package:ui/src/engine/assets.dart';
 import 'package:ui/src/engine/browser_detection.dart';
@@ -22,6 +21,8 @@
 import 'package:ui/src/engine/window.dart';
 import 'package:ui/ui.dart' as ui;
 
+import 'dom.dart';
+
 /// The mode the app is running in.
 /// Keep these in sync with the same constants on the framework-side under foundation/constants.dart.
 const bool kReleaseMode =
@@ -178,7 +179,7 @@
     // fires.
     if (!waitingForAnimation) {
       waitingForAnimation = true;
-      html.window.requestAnimationFrame((num highResTime) {
+      domWindow.requestAnimationFrame(allowInterop((num highResTime) {
         frameTimingsOnVsync();
 
         // Reset immediately, because `frameHandler` can schedule more frames.
@@ -210,7 +211,7 @@
           //                implement it properly.
           EnginePlatformDispatcher.instance.invokeOnDrawFrame();
         }
-      });
+      }));
     }
   };
 
diff --git a/lib/web_ui/lib/src/engine/safe_browser_api.dart b/lib/web_ui/lib/src/engine/safe_browser_api.dart
index b2b29a4..3b918a1 100644
--- a/lib/web_ui/lib/src/engine/safe_browser_api.dart
+++ b/lib/web_ui/lib/src/engine/safe_browser_api.dart
@@ -64,7 +64,7 @@
     'Attempted to set property "$name" on a JavaScript object. This property '
     'has not been checked for safety. Possible solutions to this problem:\n'
     ' - Do not set this property.\n'
-    ' - Use a `dart:html` API that does the same thing.\n'
+    ' - Use a `js_util` API that does the same thing.\n'
     ' - Ensure that the property is safe then add it to _safeJsProperties set.',
   );
   return js_util.setProperty<T>(object, name, value);
diff --git a/lib/web_ui/lib/ui.dart b/lib/web_ui/lib/ui.dart
index baa2a5c..a01d539 100644
--- a/lib/web_ui/lib/ui.dart
+++ b/lib/web_ui/lib/ui.dart
@@ -10,7 +10,6 @@
 import 'dart:async';
 import 'dart:collection' as collection;
 import 'dart:convert';
-import 'dart:html' as html;
 import 'dart:math' as math;
 import 'dart:typed_data';
 
diff --git a/lib/web_ui/test/canvaskit/embedded_views_test.dart b/lib/web_ui/test/canvaskit/embedded_views_test.dart
index 30b332f..2a796d3 100644
--- a/lib/web_ui/test/canvaskit/embedded_views_test.dart
+++ b/lib/web_ui/test/canvaskit/embedded_views_test.dart
@@ -27,7 +27,7 @@
     test('embeds interactive platform views', () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -63,7 +63,7 @@
     test('clips platform views with RRects', () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -103,7 +103,7 @@
     test('correctly transforms platform views', () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -135,7 +135,7 @@
     test('correctly offsets platform views', () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -175,7 +175,7 @@
     test('correctly offsets when clip chain length is changed', () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -228,7 +228,7 @@
       window.debugOverrideDevicePixelRatio(4);
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -255,7 +255,7 @@
       window.debugOverrideDevicePixelRatio(4);
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -297,7 +297,7 @@
       for (int i = 0; i < 16; i++) {
         ui.platformViewRegistry.registerViewFactory(
           'test-platform-view',
-          (int viewId) => html.DivElement()..id = 'view-$i',
+          (int viewId) => createDomHTMLDivElement()..id = 'view-$i',
         );
         await createPlatformView(i, 'test-platform-view');
         platformViewIds.add(i);
@@ -453,7 +453,7 @@
       for (int i = 0; i < 20; i++) {
         ui.platformViewRegistry.registerViewFactory(
           'test-platform-view',
-          (int viewId) => html.DivElement()..id = 'view-$i',
+          (int viewId) => createDomHTMLDivElement()..id = 'view-$i',
         );
         await createPlatformView(i, 'test-platform-view');
         platformViewIds.add(i);
@@ -583,7 +583,7 @@
     test('embeds and disposes of a platform view', () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -626,7 +626,7 @@
     test('removed the DOM node of an unrendered platform view', () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -688,7 +688,7 @@
         () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'test-view',
+        (int viewId) => createDomHTMLDivElement()..id = 'test-view',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -725,7 +725,7 @@
         () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -748,7 +748,7 @@
       HtmlViewEmbedder.debugDisableOverlays = true;
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
@@ -778,7 +778,7 @@
 
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
       await createPlatformView(1, 'test-platform-view');
@@ -824,7 +824,7 @@
       HtmlViewEmbedder.debugDisableOverlays = true;
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
       await createPlatformView(1, 'test-platform-view');
@@ -863,11 +863,11 @@
       ui.platformViewRegistry.registerViewFactory(
           'test-visible-view',
           (int viewId) =>
-              html.DivElement()..className = 'visible-platform-view');
+              createDomHTMLDivElement()..className = 'visible-platform-view');
       ui.platformViewRegistry.registerViewFactory(
         'test-invisible-view',
         (int viewId) =>
-            html.DivElement()..className = 'invisible-platform-view',
+            createDomHTMLDivElement()..className = 'invisible-platform-view',
         isVisible: false,
       );
       await createPlatformView(0, 'test-visible-view');
diff --git a/lib/web_ui/test/canvaskit/image_golden_test.dart b/lib/web_ui/test/canvaskit/image_golden_test.dart
index ca4626f..06cb0ff 100644
--- a/lib/web_ui/test/canvaskit/image_golden_test.dart
+++ b/lib/web_ui/test/canvaskit/image_golden_test.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:html' as html;
 import 'dart:typed_data';
 
 import 'package:js/js.dart';
@@ -533,7 +532,7 @@
     test('the same image can be rendered on difference surfaces', () async {
       ui.platformViewRegistry.registerViewFactory(
         'test-platform-view',
-        (int viewId) => html.DivElement()..id = 'view-0',
+        (int viewId) => createDomHTMLDivElement()..id = 'view-0',
       );
       await createPlatformView(0, 'test-platform-view');
 
diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart
index 972d24e..2a8eb8e 100644
--- a/lib/web_ui/test/engine/semantics/semantics_test.dart
+++ b/lib/web_ui/test/engine/semantics/semantics_test.dart
@@ -1806,7 +1806,7 @@
 
     ui.platformViewRegistry.registerViewFactory(
       'test-platform-view',
-      (int viewId) => html.DivElement()
+      (int viewId) => createDomHTMLDivElement()
         ..id = 'view-0'
         ..style.width = '100%'
         ..style.height = '100%',
diff --git a/lib/web_ui/test/engine/surface/platform_view_test.dart b/lib/web_ui/test/engine/surface/platform_view_test.dart
index 9c763a4..86c506a 100644
--- a/lib/web_ui/test/engine/surface/platform_view_test.dart
+++ b/lib/web_ui/test/engine/surface/platform_view_test.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:html' as html;
 
 import 'package:test/bootstrap/browser.dart';
 import 'package:test/test.dart';
@@ -28,11 +27,11 @@
     setUp(() async {
       platformViewRegistry.registerViewFactory(
         'test-0',
-        (int viewId) => html.DivElement(),
+        (int viewId) => createDomHTMLDivElement(),
       );
       platformViewRegistry.registerViewFactory(
         'test-1',
-        (int viewId) => html.DivElement(),
+        (int viewId) => createDomHTMLDivElement(),
       );
       // Ensure the views are created...
       await Future.wait(<Future<void>>[