mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[web] Migrate Flutter Web DOM usage to JS static interop - 36. (flutter/engine#33372)
This commit is contained in:
parent
ffd7eadb73
commit
73a8bd7c5b
@ -219,7 +219,7 @@ class CanvasPool extends _SaveStackTracking {
|
||||
return tryCreateCanvasElement(
|
||||
(width * _density).ceil(),
|
||||
(height * _density).ceil(),
|
||||
) as DomCanvasElement?;
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -458,7 +458,7 @@ Future<Uint8List> encodeVideoFrameAsPng(VideoFrame videoFrame) async {
|
||||
final DomCanvasElement canvas = createDomCanvasElement(width: width, height:
|
||||
height);
|
||||
final DomCanvasRenderingContext2D ctx = canvas.context2D;
|
||||
ctx.drawImage(videoFrame as DomCanvasImageSource, 0, 0);
|
||||
ctx.drawImage(videoFrame, 0, 0);
|
||||
final String pngBase64 = canvas.toDataURL().substring('data:image/png;base64,'.length);
|
||||
return base64.decode(pngBase64);
|
||||
}
|
||||
|
||||
@ -40,7 +40,12 @@ extension DomWindowExtension on DomWindow {
|
||||
external DomURL get URL;
|
||||
external bool dispatchEvent(DomEvent event);
|
||||
external DomMediaQueryList matchMedia(String? query);
|
||||
external DomCSSStyleDeclaration getComputedStyle(DomElement elt);
|
||||
DomCSSStyleDeclaration getComputedStyle(DomElement elt,
|
||||
[String? pseudoElt]) =>
|
||||
js_util.callMethod(this, 'getComputedStyle', <Object>[
|
||||
elt,
|
||||
if (pseudoElt != null) pseudoElt
|
||||
]) as DomCSSStyleDeclaration;
|
||||
}
|
||||
|
||||
@JS()
|
||||
@ -88,6 +93,7 @@ extension DomDocumentExtension on DomDocument {
|
||||
String namespaceURI, String qualifiedName);
|
||||
external DomText createTextNode(String data);
|
||||
external DomEvent createEvent(String eventType);
|
||||
external DomElement? get activeElement;
|
||||
}
|
||||
|
||||
@JS()
|
||||
@ -196,6 +202,15 @@ extension DomNodeExtension on DomNode {
|
||||
js_util.setProperty<String?>(this, 'textContent', value);
|
||||
external DomNode cloneNode(bool? deep);
|
||||
external bool contains(DomNode? other);
|
||||
external void append(DomNode node);
|
||||
Iterable<DomNode> get childNodes => createDomListWrapper<DomElement>(
|
||||
js_util.getProperty<_DomList>(this, 'childNodes'));
|
||||
external DomDocument? get ownerDocument;
|
||||
void clearChildren() {
|
||||
while (firstChild != null) {
|
||||
removeChild(firstChild!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JS()
|
||||
@ -255,7 +270,12 @@ extension DomElementExtension on DomElement {
|
||||
this, 'getElementsByClassName', <Object>[className]).cast<DomNode>();
|
||||
external void click();
|
||||
external bool hasAttribute(String name);
|
||||
external DomNodeList get childNodes;
|
||||
Iterable<DomNode> get childNodes => createDomListWrapper<DomElement>(
|
||||
js_util.getProperty<_DomList>(this, 'childNodes'));
|
||||
DomShadowRoot attachShadow(Map<Object?, Object?> initDict) => js_util
|
||||
.callMethod(this, 'attachShadow', <Object?>[js_util.jsify(initDict)])
|
||||
as DomShadowRoot;
|
||||
external DomShadowRoot? get shadowRoot;
|
||||
void clearChildren() {
|
||||
while (firstChild != null) {
|
||||
removeChild(firstChild!);
|
||||
@ -506,8 +526,12 @@ class DomHTMLStyleElement extends DomHTMLElement {}
|
||||
|
||||
extension DomHTMLStyleElementExtension on DomHTMLStyleElement {
|
||||
external set type(String? value);
|
||||
external DomStyleSheet? get sheet;
|
||||
}
|
||||
|
||||
DomHTMLStyleElement createDomHTMLStyleElement() =>
|
||||
domDocument.createElement('style') as DomHTMLStyleElement;
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class DomPerformance extends DomEventTarget {}
|
||||
@ -549,8 +573,8 @@ extension DomCanvasElementExtension on DomCanvasElement {
|
||||
external int? get height;
|
||||
external set height(int? value);
|
||||
external bool? get isConnected;
|
||||
String toDataURL([String? type]) =>
|
||||
js_util.callMethod(this, 'toDataURL', <Object>[if (type != null) type]);
|
||||
String toDataURL([String type = 'image/png']) =>
|
||||
js_util.callMethod(this, 'toDataURL', <Object>[type]);
|
||||
|
||||
Object? getContext(String contextType, [Map<dynamic, dynamic>? attributes]) {
|
||||
return js_util.callMethod(this, 'getContext', <Object?>[
|
||||
@ -635,6 +659,9 @@ extension DomCanvasRenderingContext2DExtension on DomCanvasRenderingContext2D {
|
||||
@staticInterop
|
||||
class DomImageData {}
|
||||
|
||||
DomImageData createDomImageData(Object? data, int sw, int sh) => js_util
|
||||
.callConstructor(domGetConstructor('ImageData')!, <Object?>[data, sw, sh]);
|
||||
|
||||
extension DomImageDataExtension on DomImageData {
|
||||
external Uint8ClampedList get data;
|
||||
}
|
||||
@ -1126,12 +1153,71 @@ DomHTMLLabelElement createDomHTMLLabelElement() =>
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class DomNodeList {}
|
||||
class DomOffscreenCanvas extends DomEventTarget {}
|
||||
|
||||
extension DomNodeListExtension on DomNodeList {
|
||||
external DomNode? item(int index);
|
||||
extension DomOffscreenCanvasExtension on DomOffscreenCanvas {
|
||||
external int? get height;
|
||||
external int? get width;
|
||||
external set height(int? value);
|
||||
external set width(int? value);
|
||||
Object? getContext(String contextType, [Map<dynamic, dynamic>? attributes]) {
|
||||
return js_util.callMethod(this, 'getContext', <Object?>[
|
||||
contextType,
|
||||
if (attributes != null) js_util.jsify(attributes)
|
||||
]);
|
||||
}
|
||||
|
||||
Future<DomBlob> convertToBlob([Map<Object?, Object?>? options]) =>
|
||||
js_util.promiseToFuture(js_util.callMethod(this, 'convertToBlob',
|
||||
<Object>[if (options != null) js_util.jsify(options)]));
|
||||
}
|
||||
|
||||
DomOffscreenCanvas createDomOffscreenCanvas(int width, int height) =>
|
||||
js_util.callConstructor(
|
||||
domGetConstructor('OffscreenCanvas')!, <Object>[width, height]);
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class DomFileReader extends DomEventTarget {}
|
||||
|
||||
extension DomFileReaderExtension on DomFileReader {
|
||||
external void readAsDataURL(DomBlob blob);
|
||||
}
|
||||
|
||||
DomFileReader createDomFileReader() =>
|
||||
js_util.callConstructor(domGetConstructor('FileReader')!, <Object>[])
|
||||
as DomFileReader;
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class DomDocumentFragment extends DomNode {}
|
||||
|
||||
extension DomDocumentFragmentExtension on DomDocumentFragment {
|
||||
external DomElement? querySelector(String selectors);
|
||||
Iterable<DomElement> querySelectorAll(String selectors) =>
|
||||
createDomListWrapper<DomElement>(js_util
|
||||
.callMethod<_DomList>(this, 'querySelectorAll', <Object>[selectors]));
|
||||
}
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class DomShadowRoot extends DomDocumentFragment {}
|
||||
|
||||
extension DomShadowRootExtension on DomShadowRoot {
|
||||
external DomElement? get activeElement;
|
||||
external DomElement? get host;
|
||||
external String? get mode;
|
||||
external bool? get delegatesFocus;
|
||||
}
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class DomStyleSheet {}
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class DomCSSStyleSheet extends DomStyleSheet {}
|
||||
|
||||
// A helper class for managing a subscription. On construction it will add an
|
||||
// event listener of the requested type to the target. Calling [cancel] will
|
||||
// remove the listener. Caller is still responsible for calling [allowInterop]
|
||||
|
||||
@ -313,9 +313,9 @@ class FlutterViewEmbedder {
|
||||
.instance.semanticsHelper
|
||||
.prepareAccessibilityPlaceholder() as html.Element;
|
||||
|
||||
glassPaneElementHostNode.nodes.addAll(<html.Node>[
|
||||
_accessibilityPlaceholder,
|
||||
_sceneHostElement!,
|
||||
glassPaneElementHostNode.appendAll(<DomNode>[
|
||||
_accessibilityPlaceholder as DomNode,
|
||||
_sceneHostElement! as DomNode,
|
||||
|
||||
// The semantic host goes last because hit-test order-wise it must be
|
||||
// first. If semantics goes under the scene host, platform views will
|
||||
@ -327,7 +327,7 @@ class FlutterViewEmbedder {
|
||||
// elements transparent. This way, if a platform view appears among other
|
||||
// interactive Flutter widgets, as long as those widgets do not intersect
|
||||
// with the platform view, the platform view will be reachable.
|
||||
semanticsHostElement,
|
||||
semanticsHostElement as DomNode,
|
||||
]);
|
||||
|
||||
// When debugging semantics, make the scene semi-transparent so that the
|
||||
@ -384,10 +384,10 @@ class FlutterViewEmbedder {
|
||||
// Creates a [HostNode] into a `root` [html.Element].
|
||||
HostNode _createHostNode(html.Element root) {
|
||||
if (getJsProperty<Object?>(root, 'attachShadow') != null) {
|
||||
return ShadowDomHostNode(root);
|
||||
return ShadowDomHostNode(root as DomElement);
|
||||
} else {
|
||||
// attachShadow not available, fall back to ElementHostNode.
|
||||
return ElementHostNode(root);
|
||||
return ElementHostNode(root as DomElement);
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,7 +526,7 @@ class FlutterViewEmbedder {
|
||||
bodyNode.insertBefore(_resourcesHost!, bodyNode.firstChild);
|
||||
} else {
|
||||
_glassPaneShadow!.node.insertBefore(
|
||||
_resourcesHost!, _glassPaneShadow!.node.firstChild);
|
||||
_resourcesHost! as DomNode, _glassPaneShadow!.node.firstChild);
|
||||
}
|
||||
}
|
||||
_resourcesHost!.append(element);
|
||||
|
||||
@ -5,21 +5,22 @@
|
||||
import 'dart:html' as html;
|
||||
|
||||
import 'browser_detection.dart';
|
||||
import 'dom.dart';
|
||||
import 'embedder.dart';
|
||||
import 'text_editing/text_editing.dart';
|
||||
|
||||
/// The interface required to host a flutter app in the DOM, and its tests.
|
||||
///
|
||||
/// Consider this as the intersection in functionality between [html.ShadowRoot]
|
||||
/// (preferred Flutter rendering method) and [html.Document] (fallback).
|
||||
/// Consider this as the intersection in functionality between [DomShadowRoot]
|
||||
/// (preferred Flutter rendering method) and [DomDocument] (fallback).
|
||||
///
|
||||
/// Not to be confused with [html.DocumentOrShadowRoot].
|
||||
/// Not to be confused with [DomDocumentOrShadowRoot].
|
||||
abstract class HostNode {
|
||||
/// Retrieves the [html.Element] that currently has focus.
|
||||
/// Retrieves the [DomElement] that currently has focus.
|
||||
///
|
||||
/// See:
|
||||
/// * [Document.activeElement](https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement)
|
||||
html.Element? get activeElement;
|
||||
DomElement? get activeElement;
|
||||
|
||||
/// Adds a node to the end of the child [nodes] list of this node.
|
||||
///
|
||||
@ -31,18 +32,18 @@ abstract class HostNode {
|
||||
///
|
||||
/// See:
|
||||
/// * [Node.appendChild](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild)
|
||||
html.Node append(html.Node node);
|
||||
DomNode append(DomNode node);
|
||||
|
||||
/// Appends all of an [Iterable<DomNode>] to this [HostNode].
|
||||
void appendAll(Iterable<DomNode> nodes);
|
||||
|
||||
/// Returns true if this node contains the specified node.
|
||||
/// See:
|
||||
/// * [Node.contains](https://developer.mozilla.org/en-US/docs/Web/API/Node.contains)
|
||||
bool contains(html.Node? other);
|
||||
bool contains(DomNode? other);
|
||||
|
||||
/// Returns the currently wrapped [html.Node].
|
||||
html.Node get node;
|
||||
|
||||
/// A modifiable list of this node's children.
|
||||
List<html.Node> get nodes;
|
||||
/// Returns the currently wrapped [DomNode].
|
||||
DomNode get node;
|
||||
|
||||
/// Finds the first descendant element of this document that matches the
|
||||
/// specified group of selectors.
|
||||
@ -59,7 +60,7 @@ abstract class HostNode {
|
||||
///
|
||||
/// See:
|
||||
/// * [Document.querySelector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)
|
||||
html.Element? querySelector(String selectors);
|
||||
DomElement? querySelector(String selectors);
|
||||
|
||||
/// Finds all descendant elements of this document that match the specified
|
||||
/// group of selectors.
|
||||
@ -75,10 +76,10 @@ abstract class HostNode {
|
||||
///
|
||||
/// See:
|
||||
/// * [Document.querySelectorAll](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll)
|
||||
List<html.Element> querySelectorAll(String selectors);
|
||||
Iterable<DomElement> querySelectorAll(String selectors);
|
||||
}
|
||||
|
||||
/// A [HostNode] implementation, backed by a [html.ShadowRoot].
|
||||
/// A [HostNode] implementation, backed by a [DomShadowRoot].
|
||||
///
|
||||
/// This is the preferred flutter implementation, but it might not be supported
|
||||
/// by all browsers yet.
|
||||
@ -87,12 +88,12 @@ abstract class HostNode {
|
||||
/// supported in the current environment. In this case, a fallback [ElementHostNode]
|
||||
/// should be created instead.
|
||||
class ShadowDomHostNode implements HostNode {
|
||||
late html.ShadowRoot _shadow;
|
||||
late DomShadowRoot _shadow;
|
||||
|
||||
/// Build a HostNode by attaching a [html.ShadowRoot] to the `root` element.
|
||||
/// Build a HostNode by attaching a [DomShadowRoot] to the `root` element.
|
||||
///
|
||||
/// This also calls [applyGlobalCssRulesToSheet], defined in dom_renderer.
|
||||
ShadowDomHostNode(html.Element root) :
|
||||
ShadowDomHostNode(DomElement root) :
|
||||
assert(
|
||||
root.isConnected ?? true,
|
||||
'The `root` of a ShadowDomHostNode must be connected to the Document object or a ShadowRoot.',
|
||||
@ -104,9 +105,9 @@ class ShadowDomHostNode implements HostNode {
|
||||
'delegatesFocus': false,
|
||||
});
|
||||
|
||||
final html.StyleElement shadowRootStyleElement = html.StyleElement();
|
||||
final DomHTMLStyleElement shadowRootStyleElement = createDomHTMLStyleElement();
|
||||
// The shadowRootStyleElement must be appended to the DOM, or its `sheet` will be null later.
|
||||
_shadow.append(shadowRootStyleElement);
|
||||
_shadow.appendChild(shadowRootStyleElement);
|
||||
|
||||
// TODO(dit): Apply only rules for the shadow root
|
||||
applyGlobalCssRulesToSheet(
|
||||
@ -117,74 +118,74 @@ class ShadowDomHostNode implements HostNode {
|
||||
}
|
||||
|
||||
@override
|
||||
html.Element? get activeElement => _shadow.activeElement;
|
||||
DomElement? get activeElement => _shadow.activeElement;
|
||||
|
||||
@override
|
||||
html.Element? querySelector(String selectors) {
|
||||
DomElement? querySelector(String selectors) {
|
||||
return _shadow.querySelector(selectors);
|
||||
}
|
||||
|
||||
@override
|
||||
List<html.Element> querySelectorAll(String selectors) {
|
||||
Iterable<DomElement> querySelectorAll(String selectors) {
|
||||
return _shadow.querySelectorAll(selectors);
|
||||
}
|
||||
|
||||
@override
|
||||
html.Node append(html.Node node) {
|
||||
return _shadow.append(node);
|
||||
DomNode append(DomNode node) {
|
||||
return _shadow.appendChild(node);
|
||||
}
|
||||
|
||||
@override
|
||||
bool contains(html.Node? other) {
|
||||
bool contains(DomNode? other) {
|
||||
return _shadow.contains(other);
|
||||
}
|
||||
|
||||
@override
|
||||
html.Node get node => _shadow;
|
||||
DomNode get node => _shadow;
|
||||
|
||||
@override
|
||||
List<html.Node> get nodes => _shadow.nodes;
|
||||
void appendAll(Iterable<DomNode> nodes) => nodes.forEach(append);
|
||||
}
|
||||
|
||||
/// A [HostNode] implementation, backed by a [html.Element].
|
||||
/// A [HostNode] implementation, backed by a [DomElement].
|
||||
///
|
||||
/// This is a fallback implementation, in case [ShadowDomHostNode] fails when
|
||||
/// being constructed.
|
||||
class ElementHostNode implements HostNode {
|
||||
late html.Element _element;
|
||||
late DomElement _element;
|
||||
|
||||
/// Build a HostNode by attaching a child [html.Element] to the `root` element.
|
||||
ElementHostNode(html.Element root) {
|
||||
_element = html.document.createElement('flt-element-host-node');
|
||||
root.append(_element);
|
||||
/// Build a HostNode by attaching a child [DomElement] to the `root` element.
|
||||
ElementHostNode(DomElement root) {
|
||||
_element = domDocument.createElement('flt-element-host-node');
|
||||
root.appendChild(_element);
|
||||
}
|
||||
|
||||
@override
|
||||
html.Element? get activeElement => _element.ownerDocument?.activeElement;
|
||||
DomElement? get activeElement => _element.ownerDocument?.activeElement;
|
||||
|
||||
@override
|
||||
html.Element? querySelector(String selectors) {
|
||||
DomElement? querySelector(String selectors) {
|
||||
return _element.querySelector(selectors);
|
||||
}
|
||||
|
||||
@override
|
||||
List<html.Element> querySelectorAll(String selectors) {
|
||||
Iterable<DomElement> querySelectorAll(String selectors) {
|
||||
return _element.querySelectorAll(selectors);
|
||||
}
|
||||
|
||||
@override
|
||||
html.Node append(html.Node node) {
|
||||
return _element.append(node);
|
||||
DomNode append(DomNode node) {
|
||||
return _element.appendChild(node);
|
||||
}
|
||||
|
||||
@override
|
||||
bool contains(html.Node? other) {
|
||||
bool contains(DomNode? other) {
|
||||
return _element.contains(other);
|
||||
}
|
||||
|
||||
@override
|
||||
html.Node get node => _element;
|
||||
DomNode get node => _element;
|
||||
|
||||
@override
|
||||
List<html.Node> get nodes => _element.nodes;
|
||||
void appendAll(Iterable<DomNode> nodes) => nodes.forEach(append);
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:html' as html;
|
||||
import 'dart:math' as math;
|
||||
import 'dart:typed_data';
|
||||
|
||||
@ -300,7 +299,7 @@ class _WebGlRenderer implements GlRenderer {
|
||||
|
||||
context!.save();
|
||||
context.resetTransform();
|
||||
gl.drawImage(context as html.CanvasRenderingContext2D, offsetX, offsetY);
|
||||
gl.drawImage(context, offsetX, offsetY);
|
||||
context.restore();
|
||||
}
|
||||
|
||||
|
||||
@ -1184,7 +1184,6 @@ const double _defaultRootFontSize = 16.0;
|
||||
/// Finds the text scale factor of the browser by looking at the computed style
|
||||
/// of the browser's <html> element.
|
||||
double findBrowserTextScaleFactor() {
|
||||
final num fontSize = parseFontSize(domDocument.documentElement! as
|
||||
html.Element) ?? _defaultRootFontSize;
|
||||
final num fontSize = parseFontSize(domDocument.documentElement!) ?? _defaultRootFontSize;
|
||||
return fontSize / _defaultRootFontSize;
|
||||
}
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:html' as html;
|
||||
|
||||
import '../browser_detection.dart';
|
||||
import '../dom.dart';
|
||||
import '../embedder.dart';
|
||||
@ -163,8 +161,7 @@ class PlatformViewManager {
|
||||
final DomElement slot = domDocument.createElement('slot')
|
||||
..style.display = 'none'
|
||||
..setAttribute('name', tombstoneName);
|
||||
// Remove cast to [html.Node] after migration.
|
||||
flutterViewEmbedder.glassPaneShadow!.append(slot as html.Node);
|
||||
flutterViewEmbedder.glassPaneShadow!.append(slot);
|
||||
// Link the element to the new slot
|
||||
element.setAttribute('slot', tombstoneName);
|
||||
// Delete both the element, and the new slot
|
||||
|
||||
@ -12,7 +12,6 @@
|
||||
library browser_api;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:html' as html;
|
||||
import 'dart:js' as js;
|
||||
import 'dart:js_util' as js_util;
|
||||
import 'dart:math' as math;
|
||||
@ -22,6 +21,7 @@ import 'package:js/js.dart';
|
||||
import 'package:ui/ui.dart' as ui;
|
||||
|
||||
import 'browser_detection.dart';
|
||||
import 'dom.dart';
|
||||
import 'platform_dispatcher.dart';
|
||||
import 'vector_math.dart';
|
||||
|
||||
@ -87,7 +87,7 @@ typedef OnBenchmark = void Function(String name, double value);
|
||||
///
|
||||
/// [eventOptions] supply additional configuration parameters.
|
||||
///
|
||||
/// This is different from [html.Element.addEventListener] in that the listener
|
||||
/// This is different from [DomElement.addEventListener] in that the listener
|
||||
/// is added as a plain JavaScript function, as opposed to a Dart function.
|
||||
///
|
||||
/// To remove the listener, call [removeJsEventListener].
|
||||
@ -139,11 +139,11 @@ num? parseFloat(String source) {
|
||||
}
|
||||
|
||||
final bool supportsFontLoadingApi =
|
||||
js_util.hasProperty(html.window, 'FontFace');
|
||||
js_util.hasProperty(domWindow, 'FontFace');
|
||||
|
||||
final bool supportsFontsClearApi =
|
||||
js_util.hasProperty(html.document, 'fonts') &&
|
||||
js_util.hasProperty(html.document.fonts!, 'clear');
|
||||
js_util.hasProperty(domDocument, 'fonts') &&
|
||||
js_util.hasProperty(domDocument.fonts!, 'clear');
|
||||
|
||||
/// Used to decide if the browser tab still has the focus.
|
||||
///
|
||||
@ -154,10 +154,10 @@ final bool supportsFontsClearApi =
|
||||
/// See for more details:
|
||||
/// https://developer.mozilla.org/en-US/docs/Web/API/Document/hasFocus
|
||||
bool get windowHasFocus =>
|
||||
js_util.callMethod<bool>(html.document, 'hasFocus', <dynamic>[]);
|
||||
js_util.callMethod<bool>(domDocument, 'hasFocus', <dynamic>[]);
|
||||
|
||||
/// Parses the font size of [element] and returns the value without a unit.
|
||||
num? parseFontSize(html.Element element) {
|
||||
num? parseFontSize(DomElement element) {
|
||||
num? fontSize;
|
||||
|
||||
if (hasJsProperty(element, 'computedStyleMap')) {
|
||||
@ -175,7 +175,8 @@ num? parseFontSize(html.Element element) {
|
||||
|
||||
if (fontSize == null) {
|
||||
// Fallback to `getComputedStyle`.
|
||||
final String fontSizeString = element.getComputedStyle().fontSize;
|
||||
final String fontSizeString =
|
||||
domWindow.getComputedStyle(element).getPropertyValue('font-size');
|
||||
fontSize = parseFloat(fontSizeString);
|
||||
}
|
||||
|
||||
@ -184,7 +185,7 @@ num? parseFontSize(html.Element element) {
|
||||
|
||||
/// Provides haptic feedback.
|
||||
void vibrate(int durationMs) {
|
||||
final html.Navigator navigator = html.window.navigator;
|
||||
final DomNavigator navigator = domWindow.navigator;
|
||||
if (hasJsProperty(navigator, 'vibrate')) {
|
||||
js_util.callMethod<void>(navigator, 'vibrate', <num>[durationMs]);
|
||||
}
|
||||
@ -192,12 +193,12 @@ void vibrate(int durationMs) {
|
||||
|
||||
/// Creates a `<canvas>` but anticipates that the result may be null.
|
||||
///
|
||||
/// The [html.CanvasElement] factory assumes that element allocation will
|
||||
/// The [DomCanvasElement] factory assumes that element allocation will
|
||||
/// succeed and will return a non-null element. This is not always true. For
|
||||
/// example, when Safari on iOS runs out of memory it returns null.
|
||||
html.CanvasElement? tryCreateCanvasElement(int width, int height) {
|
||||
final html.CanvasElement? canvas = js_util.callMethod<html.CanvasElement?>(
|
||||
html.document,
|
||||
DomCanvasElement? tryCreateCanvasElement(int width, int height) {
|
||||
final DomCanvasElement? canvas = js_util.callMethod<DomCanvasElement?>(
|
||||
domDocument,
|
||||
'createElement',
|
||||
<dynamic>['CANVAS'],
|
||||
);
|
||||
@ -331,7 +332,7 @@ class DecodeOptions {
|
||||
/// * https://www.w3.org/TR/webcodecs/#videoframe-interface
|
||||
@JS()
|
||||
@anonymous
|
||||
class VideoFrame implements html.CanvasImageSource {
|
||||
class VideoFrame implements DomCanvasImageSource {
|
||||
external int allocationSize();
|
||||
external JsPromise copyTo(Uint8List destination);
|
||||
external String? get format;
|
||||
@ -447,14 +448,14 @@ class GlContext {
|
||||
offScreenCanvas.canvasElement!, webGLVersion == WebGLVersion.webgl1);
|
||||
}
|
||||
|
||||
GlContext._fromOffscreenCanvas(html.OffscreenCanvas canvas)
|
||||
GlContext._fromOffscreenCanvas(DomOffscreenCanvas canvas)
|
||||
: glContext = canvas.getContext('webgl2', <String, dynamic>{'premultipliedAlpha': false})!,
|
||||
isOffscreen = true {
|
||||
_programCache = <String, GlProgram?>{};
|
||||
_canvas = canvas;
|
||||
}
|
||||
|
||||
GlContext._fromCanvasElement(html.CanvasElement canvas, bool useWebGl1)
|
||||
GlContext._fromCanvasElement(DomCanvasElement canvas, bool useWebGl1)
|
||||
: glContext = canvas.getContext(useWebGl1 ? 'webgl' : 'webgl2',
|
||||
<String, dynamic>{'premultipliedAlpha': false})!,
|
||||
isOffscreen = false {
|
||||
@ -468,7 +469,7 @@ class GlContext {
|
||||
}
|
||||
|
||||
/// Draws Gl context contents to canvas context.
|
||||
void drawImage(html.CanvasRenderingContext2D context,
|
||||
void drawImage(DomCanvasRenderingContext2D context,
|
||||
double left, double top) {
|
||||
// Actual size of canvas may be larger than viewport size. Use
|
||||
// source/destination to draw part of the image data.
|
||||
@ -808,7 +809,7 @@ class GlContext {
|
||||
/// Reads gl contents as image data.
|
||||
///
|
||||
/// Warning: data is read bottom up (flipped).
|
||||
html.ImageData readImageData() {
|
||||
DomImageData readImageData() {
|
||||
const int kBytesPerPixel = 4;
|
||||
final int bufferWidth = _widthInPixels!;
|
||||
final int bufferHeight = _heightInPixels!;
|
||||
@ -818,14 +819,14 @@ class GlContext {
|
||||
Uint8List(bufferWidth * bufferHeight * kBytesPerPixel);
|
||||
js_util.callMethod<void>(glContext, 'readPixels',
|
||||
<dynamic>[0, 0, bufferWidth, bufferHeight, kRGBA, kUnsignedByte, pixels]);
|
||||
return html.ImageData(
|
||||
return createDomImageData(
|
||||
Uint8ClampedList.fromList(pixels), bufferWidth, bufferHeight);
|
||||
} else {
|
||||
final Uint8ClampedList pixels =
|
||||
Uint8ClampedList(bufferWidth * bufferHeight * kBytesPerPixel);
|
||||
js_util.callMethod<void>(glContext, 'readPixels',
|
||||
<dynamic>[0, 0, bufferWidth, bufferHeight, kRGBA, kUnsignedByte, pixels]);
|
||||
return html.ImageData(pixels, bufferWidth, bufferHeight);
|
||||
return createDomImageData(pixels, bufferWidth, bufferHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -845,8 +846,8 @@ class GlContext {
|
||||
<dynamic>[]);
|
||||
return imageBitmap;
|
||||
} else {
|
||||
final html.CanvasElement canvas = html.CanvasElement(width: _widthInPixels, height: _heightInPixels);
|
||||
final html.CanvasRenderingContext2D ctx = canvas.context2D;
|
||||
final DomCanvasElement canvas = createDomCanvasElement(width: _widthInPixels, height: _heightInPixels);
|
||||
final DomCanvasRenderingContext2D ctx = canvas.context2D;
|
||||
drawImage(ctx, 0, 0);
|
||||
return canvas;
|
||||
}
|
||||
@ -854,10 +855,10 @@ class GlContext {
|
||||
|
||||
/// Returns image data in data url format.
|
||||
String toImageUrl() {
|
||||
final html.CanvasElement canvas = html.CanvasElement(width: _widthInPixels, height: _heightInPixels);
|
||||
final html.CanvasRenderingContext2D ctx = canvas.context2D;
|
||||
final DomCanvasElement canvas = createDomCanvasElement(width: _widthInPixels, height: _heightInPixels);
|
||||
final DomCanvasRenderingContext2D ctx = canvas.context2D;
|
||||
drawImage(ctx, 0, 0);
|
||||
final String dataUrl = canvas.toDataUrl();
|
||||
final String dataUrl = canvas.toDataURL();
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
return dataUrl;
|
||||
@ -950,19 +951,19 @@ dynamic tileModeToGlWrapping(GlContext gl, ui.TileMode tileMode) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Polyfill for html.OffscreenCanvas that is not supported on some browsers.
|
||||
/// Polyfill for DomOffscreenCanvas that is not supported on some browsers.
|
||||
class OffScreenCanvas {
|
||||
html.OffscreenCanvas? offScreenCanvas;
|
||||
html.CanvasElement? canvasElement;
|
||||
DomOffscreenCanvas? offScreenCanvas;
|
||||
DomCanvasElement? canvasElement;
|
||||
int width;
|
||||
int height;
|
||||
static bool? _supported;
|
||||
|
||||
OffScreenCanvas(this.width, this.height) {
|
||||
if (OffScreenCanvas.supported) {
|
||||
offScreenCanvas = html.OffscreenCanvas(width, height);
|
||||
offScreenCanvas = createDomOffscreenCanvas(width, height);
|
||||
} else {
|
||||
canvasElement = html.CanvasElement(
|
||||
canvasElement = createDomCanvasElement(
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
@ -971,7 +972,7 @@ class OffScreenCanvas {
|
||||
}
|
||||
}
|
||||
|
||||
void _updateCanvasCssSize(html.CanvasElement element) {
|
||||
void _updateCanvasCssSize(DomCanvasElement element) {
|
||||
final double cssWidth = width / EnginePlatformDispatcher.browserDevicePixelRatio;
|
||||
final double cssHeight = height / EnginePlatformDispatcher.browserDevicePixelRatio;
|
||||
element.style
|
||||
@ -1034,18 +1035,18 @@ class OffScreenCanvas {
|
||||
Future<String> toDataUrl() {
|
||||
final Completer<String> completer = Completer<String>();
|
||||
if (offScreenCanvas != null) {
|
||||
offScreenCanvas!.convertToBlob().then((html.Blob value) {
|
||||
final html.FileReader fileReader = html.FileReader();
|
||||
fileReader.onLoad.listen((html.ProgressEvent event) {
|
||||
offScreenCanvas!.convertToBlob().then((DomBlob value) {
|
||||
final DomFileReader fileReader = createDomFileReader();
|
||||
fileReader.addEventListener('load', allowInterop((DomEvent event) {
|
||||
completer.complete(
|
||||
js_util.getProperty<String>(js_util.getProperty<Object>(event, 'target'), 'result'),
|
||||
);
|
||||
});
|
||||
fileReader.readAsDataUrl(value);
|
||||
}));
|
||||
fileReader.readAsDataURL(value);
|
||||
});
|
||||
return completer.future;
|
||||
} else {
|
||||
return Future<String>.value(canvasElement!.toDataUrl());
|
||||
return Future<String>.value(canvasElement!.toDataURL());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1057,5 +1058,5 @@ class OffScreenCanvas {
|
||||
|
||||
/// Feature detects OffscreenCanvas.
|
||||
static bool get supported => _supported ??=
|
||||
js_util.hasProperty(html.window, 'OffscreenCanvas');
|
||||
js_util.hasProperty(domWindow, 'OffscreenCanvas');
|
||||
}
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:html' as html;
|
||||
|
||||
import '../../engine.dart' show registerHotRestartListener;
|
||||
import '../dom.dart';
|
||||
import '../embedder.dart';
|
||||
@ -31,7 +29,7 @@ class RulerHost {
|
||||
..height = '0';
|
||||
|
||||
if (root == null) {
|
||||
flutterViewEmbedder.glassPaneShadow!.node.append(_rulerHost as html.Node);
|
||||
flutterViewEmbedder.glassPaneShadow!.node.appendChild(_rulerHost);
|
||||
} else {
|
||||
root.appendChild(_rulerHost);
|
||||
}
|
||||
|
||||
@ -274,7 +274,7 @@ class EngineAutofillForm {
|
||||
|
||||
void placeForm(DomHTMLElement mainTextEditingElement) {
|
||||
formElement.append(mainTextEditingElement);
|
||||
defaultTextEditingRoot.append(formElement as html.Node);
|
||||
defaultTextEditingRoot.append(formElement);
|
||||
}
|
||||
|
||||
void storeForm() {
|
||||
@ -1154,7 +1154,7 @@ abstract class DefaultTextEditingStrategy with CompositionAwareMixin implements
|
||||
// DOM later, when the first location information arrived.
|
||||
// Otherwise, on Blink based Desktop browsers, the autofill menu appears
|
||||
// on top left of the screen.
|
||||
defaultTextEditingRoot.append(activeDomElement as html.Node);
|
||||
defaultTextEditingRoot.append(activeDomElement);
|
||||
_appendedToForm = false;
|
||||
}
|
||||
|
||||
@ -1633,7 +1633,7 @@ class AndroidTextEditingStrategy extends GloballyPositionedTextEditingStrategy {
|
||||
if (hasAutofillGroup) {
|
||||
placeForm();
|
||||
} else {
|
||||
defaultTextEditingRoot.append(activeDomElement as html.Node);
|
||||
defaultTextEditingRoot.append(activeDomElement);
|
||||
}
|
||||
inputConfig.textCapitalization.setAutocapitalizeAttribute(
|
||||
activeDomElement);
|
||||
|
||||
@ -95,7 +95,9 @@ void testMain() {
|
||||
embedder.addResource(regularTextField);
|
||||
|
||||
regularTextField.focus();
|
||||
html.CssStyleDeclaration? style = embedder.glassPaneShadow?.querySelector('input')?.getComputedStyle('::placeholder');
|
||||
html.CssStyleDeclaration? style = domWindow.getComputedStyle(
|
||||
embedder.glassPaneShadow!.querySelector('input')!,
|
||||
'::placeholder') as html.CssStyleDeclaration?;
|
||||
expect(style, isNotNull);
|
||||
expect(style?.opacity, isNot('0'));
|
||||
|
||||
@ -105,7 +107,9 @@ void testMain() {
|
||||
embedder.addResource(textField);
|
||||
|
||||
textField.focus();
|
||||
style = embedder.glassPaneShadow?.querySelector('input.flt-text-editing')?.getComputedStyle('::placeholder');
|
||||
style = domWindow.getComputedStyle(
|
||||
embedder.glassPaneShadow!.querySelector('input.flt-text-editing')!,
|
||||
'::placeholder') as html.CssStyleDeclaration?;
|
||||
expect(style, isNotNull);
|
||||
expect(style?.opacity, '0');
|
||||
}, skip: browserEngine != BrowserEngine.firefox);
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:html' as html;
|
||||
|
||||
import 'package:test/bootstrap/browser.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:ui/src/engine.dart';
|
||||
@ -13,15 +11,15 @@ void main() {
|
||||
}
|
||||
|
||||
void testMain() {
|
||||
final html.Element rootNode = html.document.createElement('div');
|
||||
html.document.body!.append(rootNode);
|
||||
final DomElement rootNode = domDocument.createElement('div');
|
||||
domDocument.body!.append(rootNode);
|
||||
|
||||
group('ShadowDomHostNode', () {
|
||||
final HostNode hostNode = ShadowDomHostNode(rootNode);
|
||||
|
||||
test('Initializes and attaches a shadow root', () {
|
||||
expect(hostNode.node, isA<html.ShadowRoot>());
|
||||
expect((hostNode.node as html.ShadowRoot).host, rootNode);
|
||||
expect(domInstanceOfString(hostNode.node, 'ShadowRoot'), isTrue);
|
||||
expect((hostNode.node as DomShadowRoot).host, rootNode);
|
||||
expect(hostNode.node, rootNode.shadowRoot);
|
||||
|
||||
// The shadow root should be initialized with correct parameters.
|
||||
@ -35,8 +33,8 @@ void testMain() {
|
||||
});
|
||||
|
||||
test('Attaches a stylesheet to the shadow root', () {
|
||||
final html.Element firstChild =
|
||||
(hostNode.node as html.ShadowRoot).children.first;
|
||||
final DomElement firstChild =
|
||||
(hostNode.node as DomShadowRoot).childNodes.toList()[0] as DomElement;
|
||||
|
||||
expect(firstChild.tagName, equalsIgnoringCase('style'));
|
||||
});
|
||||
@ -48,9 +46,9 @@ void testMain() {
|
||||
final HostNode hostNode = ElementHostNode(rootNode);
|
||||
|
||||
test('Initializes and attaches a child element', () {
|
||||
expect(hostNode.node, isA<html.Element>());
|
||||
expect((hostNode.node as html.Element).shadowRoot, isNull);
|
||||
expect(hostNode.node.parent, rootNode);
|
||||
expect(domInstanceOfString(hostNode.node, 'Element'), isTrue);
|
||||
expect((hostNode.node as DomElement).shadowRoot, isNull);
|
||||
expect(hostNode.node.parentNode, rootNode);
|
||||
});
|
||||
|
||||
_runDomTests(hostNode);
|
||||
@ -60,29 +58,29 @@ void testMain() {
|
||||
// The common test suite that all types of HostNode implementations need to pass.
|
||||
void _runDomTests(HostNode hostNode) {
|
||||
group('DOM operations', () {
|
||||
final html.Element target = html.document.createElement('div')..id = 'yep';
|
||||
final DomElement target = domDocument.createElement('div')..id = 'yep';
|
||||
|
||||
setUp(() {
|
||||
hostNode.nodes.addAll(<html.Node>[
|
||||
html.document.createElement('div'),
|
||||
hostNode.appendAll(<DomNode>[
|
||||
domDocument.createElement('div'),
|
||||
target,
|
||||
html.document.createElement('flt-span'),
|
||||
html.document.createElement('div'),
|
||||
domDocument.createElement('flt-span'),
|
||||
domDocument.createElement('div'),
|
||||
]);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
hostNode.nodes.clear();
|
||||
hostNode.node.clearChildren();
|
||||
});
|
||||
|
||||
test('querySelector', () {
|
||||
final html.Element? found = hostNode.querySelector('#yep');
|
||||
final DomElement? found = hostNode.querySelector('#yep');
|
||||
|
||||
expect(identical(found, target), isTrue);
|
||||
});
|
||||
|
||||
test('.contains and .append', () {
|
||||
final html.Element another = html.document.createElement('div')
|
||||
final DomElement another = domDocument.createElement('div')
|
||||
..id = 'another';
|
||||
|
||||
expect(hostNode.contains(target), isTrue);
|
||||
@ -94,7 +92,7 @@ void _runDomTests(HostNode hostNode) {
|
||||
});
|
||||
|
||||
test('querySelectorAll', () {
|
||||
final List<html.Node> found = hostNode.querySelectorAll('div');
|
||||
final List<DomNode> found = hostNode.querySelectorAll('div').toList();
|
||||
|
||||
expect(found.length, 3);
|
||||
expect(found[1], target);
|
||||
|
||||
@ -97,7 +97,7 @@ void _testEngineSemanticsOwner() {
|
||||
|
||||
// Synthesize a click on the placeholder.
|
||||
final html.Element placeholder =
|
||||
appHostNode.querySelector('flt-semantics-placeholder')!;
|
||||
appHostNode.querySelector('flt-semantics-placeholder')! as html.Element;
|
||||
|
||||
expect(placeholder.isConnected, isTrue);
|
||||
|
||||
@ -193,7 +193,7 @@ void _testEngineSemanticsOwner() {
|
||||
isFalse);
|
||||
|
||||
final html.Element placeholder =
|
||||
appHostNode.querySelector('flt-semantics-placeholder')!;
|
||||
appHostNode.querySelector('flt-semantics-placeholder')! as html.Element;
|
||||
|
||||
expect(placeholder.isConnected, isTrue);
|
||||
|
||||
@ -522,9 +522,9 @@ void _testContainer() {
|
||||
</sem>''');
|
||||
|
||||
final html.Element parentElement =
|
||||
appHostNode.querySelector('flt-semantics')!;
|
||||
appHostNode.querySelector('flt-semantics')! as html.Element;
|
||||
final html.Element container =
|
||||
appHostNode.querySelector('flt-semantics-container')!;
|
||||
appHostNode.querySelector('flt-semantics-container')! as html.Element;
|
||||
|
||||
if (isMacOrIOS) {
|
||||
expect(parentElement.style.top, '0px');
|
||||
@ -576,9 +576,9 @@ void _testContainer() {
|
||||
</sem>''');
|
||||
|
||||
final html.Element parentElement =
|
||||
appHostNode.querySelector('flt-semantics')!;
|
||||
appHostNode.querySelector('flt-semantics')! as html.Element;
|
||||
final html.Element container =
|
||||
appHostNode.querySelector('flt-semantics-container')!;
|
||||
appHostNode.querySelector('flt-semantics-container')! as html.Element;
|
||||
|
||||
expect(parentElement.style.transform, 'matrix(1, 0, 0, 1, 10, 10)');
|
||||
expect(parentElement.style.transformOrigin, '0px 0px 0px');
|
||||
@ -619,9 +619,9 @@ void _testContainer() {
|
||||
</sem>''');
|
||||
|
||||
final html.Element parentElement =
|
||||
appHostNode.querySelector('flt-semantics')!;
|
||||
appHostNode.querySelector('flt-semantics')! as html.Element;
|
||||
final html.Element container =
|
||||
appHostNode.querySelector('flt-semantics-container')!;
|
||||
appHostNode.querySelector('flt-semantics-container')! as html.Element;
|
||||
|
||||
if (isMacOrIOS) {
|
||||
expect(parentElement.style.top, '0px');
|
||||
@ -758,13 +758,13 @@ void _testContainer() {
|
||||
</sem-c>
|
||||
</sem>''');
|
||||
|
||||
final html.Element root = appHostNode.querySelector('#flt-semantic-node-0')!;
|
||||
final DomElement root = appHostNode.querySelector('#flt-semantic-node-0')!;
|
||||
expect(root.style.pointerEvents, 'none');
|
||||
|
||||
final html.Element child1 = appHostNode.querySelector('#flt-semantic-node-1')!;
|
||||
final DomElement child1 = appHostNode.querySelector('#flt-semantic-node-1')!;
|
||||
expect(child1.style.pointerEvents, 'all');
|
||||
|
||||
final html.Element child2 = appHostNode.querySelector('#flt-semantic-node-2')!;
|
||||
final DomElement child2 = appHostNode.querySelector('#flt-semantic-node-2')!;
|
||||
expect(child2.style.pointerEvents, 'all');
|
||||
|
||||
semantics().semanticsEnabled = false;
|
||||
@ -1239,7 +1239,8 @@ void _testTextField() {
|
||||
semantics().updateSemantics(builder.build());
|
||||
|
||||
final html.Element textField =
|
||||
appHostNode.querySelector('input[data-semantics-role="text-field"]')!;
|
||||
appHostNode.querySelector('input[data-semantics-role="text-field"]')! as
|
||||
html.Element;
|
||||
|
||||
expect(appHostNode.activeElement, isNot(textField));
|
||||
|
||||
@ -1768,7 +1769,7 @@ void _testPlatformView() {
|
||||
semantics().updateSemantics(builder.build());
|
||||
|
||||
expectSemanticsTree('<sem style="$rootSemanticStyle"></sem>');
|
||||
final html.Element element = appHostNode.querySelector('flt-semantics')!;
|
||||
final DomElement element = appHostNode.querySelector('flt-semantics')!;
|
||||
expect(element.style.pointerEvents, 'none');
|
||||
|
||||
semantics().semanticsEnabled = false;
|
||||
@ -1857,10 +1858,11 @@ void _testPlatformView() {
|
||||
</sem-c>
|
||||
</sem>''');
|
||||
|
||||
final html.Element root = appHostNode.querySelector('#flt-semantic-node-0')!;
|
||||
final DomElement root = appHostNode.querySelector('#flt-semantic-node-0')!;
|
||||
expect(root.style.pointerEvents, 'none');
|
||||
|
||||
final html.Element child1 = appHostNode.querySelector('#flt-semantic-node-1')!;
|
||||
final html.Element child1 =
|
||||
appHostNode.querySelector('#flt-semantic-node-1')! as html.Element;
|
||||
expect(child1.style.pointerEvents, 'all');
|
||||
final html.Rectangle<num> child1Rect = child1.getBoundingClientRect();
|
||||
expect(child1Rect.left, 0);
|
||||
@ -1868,7 +1870,8 @@ void _testPlatformView() {
|
||||
expect(child1Rect.right, 20);
|
||||
expect(child1Rect.bottom, 25);
|
||||
|
||||
final html.Element child2 = appHostNode.querySelector('#flt-semantic-node-2')!;
|
||||
final html.Element child2 =
|
||||
appHostNode.querySelector('#flt-semantic-node-2')! as html.Element;
|
||||
expect(child2.style.pointerEvents, 'none');
|
||||
final html.Rectangle<num> child2Rect = child2.getBoundingClientRect();
|
||||
expect(child2Rect.left, 0);
|
||||
@ -1876,7 +1879,8 @@ void _testPlatformView() {
|
||||
expect(child2Rect.right, 20);
|
||||
expect(child2Rect.bottom, 45);
|
||||
|
||||
final html.Element child3 = appHostNode.querySelector('#flt-semantic-node-3')!;
|
||||
final html.Element child3 =
|
||||
appHostNode.querySelector('#flt-semantic-node-3')! as html.Element;
|
||||
expect(child3.style.pointerEvents, 'all');
|
||||
final html.Rectangle<num> child3Rect = child3.getBoundingClientRect();
|
||||
expect(child3Rect.left, 0);
|
||||
|
||||
@ -8,6 +8,7 @@ import 'dart:typed_data';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:ui/src/engine/browser_detection.dart';
|
||||
import 'package:ui/src/engine/dom.dart';
|
||||
import 'package:ui/src/engine/embedder.dart';
|
||||
import 'package:ui/src/engine/host_node.dart';
|
||||
import 'package:ui/src/engine/semantics.dart';
|
||||
@ -362,7 +363,7 @@ class SemanticsTester {
|
||||
void expectSemanticsTree(String semanticsHtml) {
|
||||
const List<String> ignoredAttributes = <String>['pointer-events'];
|
||||
expect(
|
||||
canonicalizeHtml(appHostNode.querySelector('flt-semantics')!.outerHtml!, ignoredAttributes: ignoredAttributes),
|
||||
canonicalizeHtml(appHostNode.querySelector('flt-semantics')!.outerHTML!, ignoredAttributes: ignoredAttributes),
|
||||
canonicalizeHtml(semanticsHtml),
|
||||
);
|
||||
}
|
||||
@ -370,12 +371,12 @@ void expectSemanticsTree(String semanticsHtml) {
|
||||
/// Finds the first HTML element in the semantics tree used for scrolling.
|
||||
html.Element? findScrollable() {
|
||||
return appHostNode.querySelectorAll('flt-semantics').firstWhereOrNull(
|
||||
(html.Element element) {
|
||||
return element.style.overflow == 'hidden' ||
|
||||
(DomElement? element) {
|
||||
return element!.style.overflow == 'hidden' ||
|
||||
element.style.overflowY == 'scroll' ||
|
||||
element.style.overflowX == 'scroll';
|
||||
},
|
||||
);
|
||||
) as html.Element?;
|
||||
}
|
||||
|
||||
/// Logs semantics actions dispatched to [ui.window].
|
||||
|
||||
@ -78,7 +78,8 @@ void testMain() {
|
||||
createTextFieldSemantics(value: 'hello');
|
||||
|
||||
final html.Element textField = appHostNode
|
||||
.querySelector('input[data-semantics-role="text-field"]')!;
|
||||
.querySelector('input[data-semantics-role="text-field"]')! as
|
||||
html.Element;
|
||||
|
||||
expect(appHostNode.activeElement, isNot(textField));
|
||||
|
||||
@ -215,7 +216,7 @@ void testMain() {
|
||||
|
||||
// It doesn't remove the DOM element.
|
||||
final TextField textField = textFieldSemantics.debugRoleManagerFor(Role.textField)! as TextField;
|
||||
expect(appHostNode.contains(textField.editableElement as html.Node), isTrue);
|
||||
expect(appHostNode.contains(textField.editableElement), isTrue);
|
||||
// Editing element is not enabled.
|
||||
expect(strategy.isEnabled, isFalse);
|
||||
expect(html.document.activeElement, html.document.body);
|
||||
@ -303,7 +304,7 @@ void testMain() {
|
||||
|
||||
strategy.disable();
|
||||
// It doesn't remove the textarea from the DOM.
|
||||
expect(appHostNode.contains(textArea), isTrue);
|
||||
expect(appHostNode.contains(textArea as DomNode), isTrue);
|
||||
// Editing element is not enabled.
|
||||
expect(strategy.isEnabled, isFalse);
|
||||
semantics().semanticsEnabled = false;
|
||||
|
||||
@ -32,7 +32,8 @@ Future<void> testMain() async {
|
||||
testScene.style.transform = 'scale(0.3)';
|
||||
}
|
||||
testScene.append(canvas.rootElement as html.Node);
|
||||
flutterViewEmbedder.glassPaneShadow!.querySelector('flt-scene-host')!.append(testScene);
|
||||
flutterViewEmbedder.glassPaneShadow!.querySelector('flt-scene-host')!.append(testScene
|
||||
as DomElement);
|
||||
}
|
||||
|
||||
setUpStableTestFonts();
|
||||
@ -260,7 +261,7 @@ Future<void> testMain() async {
|
||||
}
|
||||
|
||||
sceneElement.querySelector('flt-clip')!.append(canvas.rootElement);
|
||||
flutterViewEmbedder.glassPaneShadow!.querySelector('flt-scene-host')!.append(sceneElement as html.Node);
|
||||
flutterViewEmbedder.glassPaneShadow!.querySelector('flt-scene-host')!.append(sceneElement);
|
||||
|
||||
await matchGoldenFile(
|
||||
'bitmap_canvas_draws_text_on_top_of_canvas.png',
|
||||
|
||||
@ -105,7 +105,8 @@ Future<void> testMain() async {
|
||||
defaultTextEditingRoot.querySelectorAll('input'),
|
||||
hasLength(1),
|
||||
);
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')!;
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')! as
|
||||
Element;
|
||||
// Now the editing element should have focus.
|
||||
|
||||
expect(document.activeElement, flutterViewEmbedder.glassPaneElement);
|
||||
@ -115,8 +116,7 @@ Future<void> testMain() async {
|
||||
expect(input.getAttribute('type'), null);
|
||||
|
||||
// Input is appended to the right point of the DOM.
|
||||
expect(defaultTextEditingRoot.contains(editingStrategy!.domElement as
|
||||
Node?), isTrue);
|
||||
expect(defaultTextEditingRoot.contains(editingStrategy!.domElement), isTrue);
|
||||
|
||||
editingStrategy!.disable();
|
||||
expect(
|
||||
@ -138,7 +138,8 @@ Future<void> testMain() async {
|
||||
onAction: trackInputAction,
|
||||
);
|
||||
expect(defaultTextEditingRoot.querySelectorAll('input'), hasLength(1));
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')!;
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')! as
|
||||
Element;
|
||||
expect(editingStrategy!.domElement, input);
|
||||
expect(input.getAttribute('readonly'), 'readonly');
|
||||
|
||||
@ -155,7 +156,8 @@ Future<void> testMain() async {
|
||||
onAction: trackInputAction,
|
||||
);
|
||||
expect(defaultTextEditingRoot.querySelectorAll('input'), hasLength(1));
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')!;
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')! as
|
||||
Element;
|
||||
expect(editingStrategy!.domElement, input);
|
||||
expect(input.getAttribute('type'), 'password');
|
||||
|
||||
@ -172,7 +174,8 @@ Future<void> testMain() async {
|
||||
onAction: trackInputAction,
|
||||
);
|
||||
expect(defaultTextEditingRoot.querySelectorAll('input'), hasLength(1));
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')!;
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')! as
|
||||
Element;
|
||||
expect(editingStrategy!.domElement, input);
|
||||
expect(input.getAttribute('autocorrect'), 'off');
|
||||
|
||||
@ -189,7 +192,8 @@ Future<void> testMain() async {
|
||||
onAction: trackInputAction,
|
||||
);
|
||||
expect(defaultTextEditingRoot.querySelectorAll('input'), hasLength(1));
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')!;
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')! as
|
||||
Element;
|
||||
expect(editingStrategy!.domElement, input);
|
||||
expect(input.getAttribute('autocorrect'), 'on');
|
||||
|
||||
@ -206,7 +210,8 @@ Future<void> testMain() async {
|
||||
onAction: trackInputAction,
|
||||
);
|
||||
expect(defaultTextEditingRoot.querySelectorAll('input'), hasLength(1));
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')!;
|
||||
final Element input = defaultTextEditingRoot.querySelector('input')! as
|
||||
Element;
|
||||
expect(editingStrategy!.domElement, input);
|
||||
expect(input.getAttribute('autocomplete'), 'off');
|
||||
|
||||
@ -1970,7 +1975,7 @@ Future<void> testMain() async {
|
||||
// 3 child nodes.
|
||||
expect(form.childNodes, hasLength(3));
|
||||
|
||||
final DomHTMLInputElement firstElement = form.childNodes.item(0)! as
|
||||
final DomHTMLInputElement firstElement = form.childNodes.toList()[0] as
|
||||
DomHTMLInputElement;
|
||||
// Autofill value is applied to the element.
|
||||
expect(firstElement.name,
|
||||
@ -2063,7 +2068,7 @@ Future<void> testMain() async {
|
||||
final DomHTMLFormElement form = autofillForm.formElement;
|
||||
// Submit button is added to the form.
|
||||
expect(form.childNodes, isNotEmpty);
|
||||
final InputElement inputElement = form.childNodes.item(0)! as InputElement;
|
||||
final InputElement inputElement = form.childNodes.toList()[0] as InputElement;
|
||||
expect(inputElement.type, 'submit');
|
||||
|
||||
// The submit button should have class `submitBtn`.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user