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

Commit 6635168

Browse files
authored
[web] Migrate Flutter Web DOM usage to JS static interop - 36. (#33372)
1 parent 6781c68 commit 6635168

18 files changed

+263
-168
lines changed

lib/web_ui/lib/src/engine/canvas_pool.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ class CanvasPool extends _SaveStackTracking {
219219
return tryCreateCanvasElement(
220220
(width * _density).ceil(),
221221
(height * _density).ceil(),
222-
) as DomCanvasElement?;
222+
);
223223
}
224224

225225
@override

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ Future<Uint8List> encodeVideoFrameAsPng(VideoFrame videoFrame) async {
458458
final DomCanvasElement canvas = createDomCanvasElement(width: width, height:
459459
height);
460460
final DomCanvasRenderingContext2D ctx = canvas.context2D;
461-
ctx.drawImage(videoFrame as DomCanvasImageSource, 0, 0);
461+
ctx.drawImage(videoFrame, 0, 0);
462462
final String pngBase64 = canvas.toDataURL().substring('data:image/png;base64,'.length);
463463
return base64.decode(pngBase64);
464464
}

lib/web_ui/lib/src/engine/dom.dart

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ extension DomWindowExtension on DomWindow {
4040
external DomURL get URL;
4141
external bool dispatchEvent(DomEvent event);
4242
external DomMediaQueryList matchMedia(String? query);
43-
external DomCSSStyleDeclaration getComputedStyle(DomElement elt);
43+
DomCSSStyleDeclaration getComputedStyle(DomElement elt,
44+
[String? pseudoElt]) =>
45+
js_util.callMethod(this, 'getComputedStyle', <Object>[
46+
elt,
47+
if (pseudoElt != null) pseudoElt
48+
]) as DomCSSStyleDeclaration;
4449
}
4550

4651
@JS()
@@ -88,6 +93,7 @@ extension DomDocumentExtension on DomDocument {
8893
String namespaceURI, String qualifiedName);
8994
external DomText createTextNode(String data);
9095
external DomEvent createEvent(String eventType);
96+
external DomElement? get activeElement;
9197
}
9298

9399
@JS()
@@ -196,6 +202,15 @@ extension DomNodeExtension on DomNode {
196202
js_util.setProperty<String?>(this, 'textContent', value);
197203
external DomNode cloneNode(bool? deep);
198204
external bool contains(DomNode? other);
205+
external void append(DomNode node);
206+
Iterable<DomNode> get childNodes => createDomListWrapper<DomElement>(
207+
js_util.getProperty<_DomList>(this, 'childNodes'));
208+
external DomDocument? get ownerDocument;
209+
void clearChildren() {
210+
while (firstChild != null) {
211+
removeChild(firstChild!);
212+
}
213+
}
199214
}
200215

201216
@JS()
@@ -255,7 +270,12 @@ extension DomElementExtension on DomElement {
255270
this, 'getElementsByClassName', <Object>[className]).cast<DomNode>();
256271
external void click();
257272
external bool hasAttribute(String name);
258-
external DomNodeList get childNodes;
273+
Iterable<DomNode> get childNodes => createDomListWrapper<DomElement>(
274+
js_util.getProperty<_DomList>(this, 'childNodes'));
275+
DomShadowRoot attachShadow(Map<Object?, Object?> initDict) => js_util
276+
.callMethod(this, 'attachShadow', <Object?>[js_util.jsify(initDict)])
277+
as DomShadowRoot;
278+
external DomShadowRoot? get shadowRoot;
259279
void clearChildren() {
260280
while (firstChild != null) {
261281
removeChild(firstChild!);
@@ -506,8 +526,12 @@ class DomHTMLStyleElement extends DomHTMLElement {}
506526

507527
extension DomHTMLStyleElementExtension on DomHTMLStyleElement {
508528
external set type(String? value);
529+
external DomStyleSheet? get sheet;
509530
}
510531

532+
DomHTMLStyleElement createDomHTMLStyleElement() =>
533+
domDocument.createElement('style') as DomHTMLStyleElement;
534+
511535
@JS()
512536
@staticInterop
513537
class DomPerformance extends DomEventTarget {}
@@ -549,8 +573,8 @@ extension DomCanvasElementExtension on DomCanvasElement {
549573
external int? get height;
550574
external set height(int? value);
551575
external bool? get isConnected;
552-
String toDataURL([String? type]) =>
553-
js_util.callMethod(this, 'toDataURL', <Object>[if (type != null) type]);
576+
String toDataURL([String type = 'image/png']) =>
577+
js_util.callMethod(this, 'toDataURL', <Object>[type]);
554578

555579
Object? getContext(String contextType, [Map<dynamic, dynamic>? attributes]) {
556580
return js_util.callMethod(this, 'getContext', <Object?>[
@@ -635,6 +659,9 @@ extension DomCanvasRenderingContext2DExtension on DomCanvasRenderingContext2D {
635659
@staticInterop
636660
class DomImageData {}
637661

662+
DomImageData createDomImageData(Object? data, int sw, int sh) => js_util
663+
.callConstructor(domGetConstructor('ImageData')!, <Object?>[data, sw, sh]);
664+
638665
extension DomImageDataExtension on DomImageData {
639666
external Uint8ClampedList get data;
640667
}
@@ -1126,12 +1153,71 @@ DomHTMLLabelElement createDomHTMLLabelElement() =>
11261153

11271154
@JS()
11281155
@staticInterop
1129-
class DomNodeList {}
1156+
class DomOffscreenCanvas extends DomEventTarget {}
1157+
1158+
extension DomOffscreenCanvasExtension on DomOffscreenCanvas {
1159+
external int? get height;
1160+
external int? get width;
1161+
external set height(int? value);
1162+
external set width(int? value);
1163+
Object? getContext(String contextType, [Map<dynamic, dynamic>? attributes]) {
1164+
return js_util.callMethod(this, 'getContext', <Object?>[
1165+
contextType,
1166+
if (attributes != null) js_util.jsify(attributes)
1167+
]);
1168+
}
1169+
1170+
Future<DomBlob> convertToBlob([Map<Object?, Object?>? options]) =>
1171+
js_util.promiseToFuture(js_util.callMethod(this, 'convertToBlob',
1172+
<Object>[if (options != null) js_util.jsify(options)]));
1173+
}
1174+
1175+
DomOffscreenCanvas createDomOffscreenCanvas(int width, int height) =>
1176+
js_util.callConstructor(
1177+
domGetConstructor('OffscreenCanvas')!, <Object>[width, height]);
1178+
1179+
@JS()
1180+
@staticInterop
1181+
class DomFileReader extends DomEventTarget {}
1182+
1183+
extension DomFileReaderExtension on DomFileReader {
1184+
external void readAsDataURL(DomBlob blob);
1185+
}
1186+
1187+
DomFileReader createDomFileReader() =>
1188+
js_util.callConstructor(domGetConstructor('FileReader')!, <Object>[])
1189+
as DomFileReader;
1190+
1191+
@JS()
1192+
@staticInterop
1193+
class DomDocumentFragment extends DomNode {}
1194+
1195+
extension DomDocumentFragmentExtension on DomDocumentFragment {
1196+
external DomElement? querySelector(String selectors);
1197+
Iterable<DomElement> querySelectorAll(String selectors) =>
1198+
createDomListWrapper<DomElement>(js_util
1199+
.callMethod<_DomList>(this, 'querySelectorAll', <Object>[selectors]));
1200+
}
1201+
1202+
@JS()
1203+
@staticInterop
1204+
class DomShadowRoot extends DomDocumentFragment {}
11301205

1131-
extension DomNodeListExtension on DomNodeList {
1132-
external DomNode? item(int index);
1206+
extension DomShadowRootExtension on DomShadowRoot {
1207+
external DomElement? get activeElement;
1208+
external DomElement? get host;
1209+
external String? get mode;
1210+
external bool? get delegatesFocus;
11331211
}
11341212

1213+
@JS()
1214+
@staticInterop
1215+
class DomStyleSheet {}
1216+
1217+
@JS()
1218+
@staticInterop
1219+
class DomCSSStyleSheet extends DomStyleSheet {}
1220+
11351221
// A helper class for managing a subscription. On construction it will add an
11361222
// event listener of the requested type to the target. Calling [cancel] will
11371223
// remove the listener. Caller is still responsible for calling [allowInterop]

lib/web_ui/lib/src/engine/embedder.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,9 @@ class FlutterViewEmbedder {
313313
.instance.semanticsHelper
314314
.prepareAccessibilityPlaceholder() as html.Element;
315315

316-
glassPaneElementHostNode.nodes.addAll(<html.Node>[
317-
_accessibilityPlaceholder,
318-
_sceneHostElement!,
316+
glassPaneElementHostNode.appendAll(<DomNode>[
317+
_accessibilityPlaceholder as DomNode,
318+
_sceneHostElement! as DomNode,
319319

320320
// The semantic host goes last because hit-test order-wise it must be
321321
// first. If semantics goes under the scene host, platform views will
@@ -327,7 +327,7 @@ class FlutterViewEmbedder {
327327
// elements transparent. This way, if a platform view appears among other
328328
// interactive Flutter widgets, as long as those widgets do not intersect
329329
// with the platform view, the platform view will be reachable.
330-
semanticsHostElement,
330+
semanticsHostElement as DomNode,
331331
]);
332332

333333
// When debugging semantics, make the scene semi-transparent so that the
@@ -384,10 +384,10 @@ class FlutterViewEmbedder {
384384
// Creates a [HostNode] into a `root` [html.Element].
385385
HostNode _createHostNode(html.Element root) {
386386
if (getJsProperty<Object?>(root, 'attachShadow') != null) {
387-
return ShadowDomHostNode(root);
387+
return ShadowDomHostNode(root as DomElement);
388388
} else {
389389
// attachShadow not available, fall back to ElementHostNode.
390-
return ElementHostNode(root);
390+
return ElementHostNode(root as DomElement);
391391
}
392392
}
393393

@@ -526,7 +526,7 @@ class FlutterViewEmbedder {
526526
bodyNode.insertBefore(_resourcesHost!, bodyNode.firstChild);
527527
} else {
528528
_glassPaneShadow!.node.insertBefore(
529-
_resourcesHost!, _glassPaneShadow!.node.firstChild);
529+
_resourcesHost! as DomNode, _glassPaneShadow!.node.firstChild);
530530
}
531531
}
532532
_resourcesHost!.append(element);

0 commit comments

Comments
 (0)