diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index 2c619b76e8828..0905ca66cd61b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -425,7 +425,7 @@ class HtmlViewEmbedder { if (_svgPathDefs != null) { return; } - _svgPathDefs = kSvgResourceHeader.clone(false) as SVGElement; + _svgPathDefs = kSvgResourceHeader.cloneNode(false) as SVGElement; _svgPathDefs!.append(createSVGDefsElement()..id = 'sk_path_defs'); skiaSceneHost!.append(_svgPathDefs!); } diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 3198c5d6d7ffe..9f98ee22cc07e 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -256,6 +256,11 @@ extension DomElementExtension on DomElement { external void click(); external bool hasAttribute(String name); external DomNodeList get childNodes; + void clearChildren() { + while (firstChild != null) { + removeChild(firstChild!); + } + } } @JS() @@ -421,8 +426,12 @@ extension DomHTMLMetaElementExtension on DomHTMLMetaElement { external String get name; external set name(String value); external String get content; + external set content(String value); } +DomHTMLMetaElement createDomHTMLMetaElement() => + domDocument.createElement('meta') as DomHTMLMetaElement; + @JS() @staticInterop class DomHTMLHeadElement extends DomHTMLElement {} @@ -507,6 +516,7 @@ extension DomPerformanceExtension on DomPerformance { external DomPerformanceEntry? mark(String markName); external DomPerformanceMeasure? measure( String measureName, String? startMark, String? endMark); + external double now(); } @JS() @@ -1107,6 +1117,13 @@ extension DomHTMLFormElementExtension on DomHTMLFormElement { DomHTMLFormElement createDomHTMLFormElement() => domDocument.createElement('form') as DomHTMLFormElement; +@JS() +@staticInterop +class DomHTMLLabelElement extends DomHTMLElement {} + +DomHTMLLabelElement createDomHTMLLabelElement() => + domDocument.createElement('label') as DomHTMLLabelElement; + @JS() @staticInterop class DomNodeList {} diff --git a/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart b/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart index 63b6b9c7edc2b..1b208e9f45d31 100644 --- a/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart @@ -851,8 +851,8 @@ class BitmapCanvas extends EngineCanvas { SurfacePaintData paint) { // For srcIn blendMode, we use an svg filter to apply to image element. final SvgFilter svgFilter = svgFilterFromBlendMode(filterColor, colorFilterBlendMode); - rootElement.append(svgFilter.element as DomElement); - _children.add(svgFilter.element as DomElement); + rootElement.append(svgFilter.element); + _children.add(svgFilter.element); final DomHTMLElement imgElement = _reuseOrCreateImage(image); imgElement.style.filter = 'url(#${svgFilter.id})'; if (colorFilterBlendMode == ui.BlendMode.saturation) { @@ -866,8 +866,8 @@ class BitmapCanvas extends EngineCanvas { HtmlImage image, List matrix, SurfacePaintData paint) { // For srcIn blendMode, we use an svg filter to apply to image element. final SvgFilter svgFilter = svgFilterFromColorMatrix(matrix); - rootElement.append(svgFilter.element as DomElement); - _children.add(svgFilter.element as DomElement); + rootElement.append(svgFilter.element); + _children.add(svgFilter.element); final DomHTMLElement imgElement = _reuseOrCreateImage(image); imgElement.style.filter = 'url(#${svgFilter.id})'; return imgElement; diff --git a/lib/web_ui/lib/src/engine/html/clip.dart b/lib/web_ui/lib/src/engine/html/clip.dart index ec414ce800d32..947ed34eeacdd 100644 --- a/lib/web_ui/lib/src/engine/html/clip.dart +++ b/lib/web_ui/lib/src/engine/html/clip.dart @@ -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:svg' as svg; - import 'package:ui/ui.dart' as ui; import '../dom.dart'; @@ -344,7 +342,7 @@ class PersistedPhysicalShape extends PersistedContainerSurface /// we size the inner container to cover full pathBounds instead of sizing /// to clipping rect bounds (which is the case for elevation == 0.0 where /// we shift outer/inner clip area instead to position clip-path). - final svg.SvgSvgElement svgClipPath = elevation == 0.0 + final SVGSVGElement svgClipPath = elevation == 0.0 ? pathToSvgClipPath(path, offsetX: -pathBounds.left, offsetY: -pathBounds.top, @@ -360,7 +358,7 @@ class PersistedPhysicalShape extends PersistedContainerSurface /// svg clip and render elements. _clipElement?.remove(); _svgElement?.remove(); - _clipElement = svgClipPath as DomElement; + _clipElement = svgClipPath; rootElement!.append(_clipElement!); if (elevation == 0.0) { setClipPath(rootElement!, createSvgClipUrl()); @@ -517,8 +515,7 @@ class PersistedClipPath extends PersistedContainerSurface SVGSVGElement createSvgClipDef(DomElement element, ui.Path clipPath) { final ui.Rect pathBounds = clipPath.getBounds(); final SVGSVGElement svgClipPath = pathToSvgClipPath(clipPath, - scaleX: 1.0 / pathBounds.right, scaleY: 1.0 / pathBounds.bottom) as - SVGSVGElement; + scaleX: 1.0 / pathBounds.right, scaleY: 1.0 / pathBounds.bottom); setClipPath(element, createSvgClipUrl()); // We need to set width and height for the clipElement to cover the // bounds of the path since browsers such as Safari and Edge diff --git a/lib/web_ui/lib/src/engine/html/color_filter.dart b/lib/web_ui/lib/src/engine/html/color_filter.dart index a23ebed126708..71beada45618f 100644 --- a/lib/web_ui/lib/src/engine/html/color_filter.dart +++ b/lib/web_ui/lib/src/engine/html/color_filter.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:html' as html; -import 'dart:svg' as svg; import 'package:ui/ui.dart' as ui; @@ -12,6 +11,7 @@ import '../canvaskit/color_filter.dart'; import '../color_filter.dart'; import '../dom.dart'; import '../embedder.dart'; +import '../svg.dart'; import '../util.dart'; import 'bitmap_canvas.dart'; import 'path_to_svg_clip.dart'; @@ -33,7 +33,7 @@ class PersistedColorFilter extends PersistedContainerSurface /// Color filter to apply to this surface. final ui.ColorFilter filter; - html.Element? _filterElement; + DomElement? _filterElement; bool containerVisible = true; @override @@ -54,7 +54,7 @@ class PersistedColorFilter extends PersistedContainerSurface @override void discard() { super.discard(); - flutterViewEmbedder.removeResource(_filterElement); + flutterViewEmbedder.removeResource(_filterElement as html.Element?); // Do not detach the child container from the root. It is permanently // attached. The elements are reused together and are detached from the DOM // together. @@ -73,7 +73,7 @@ class PersistedColorFilter extends PersistedContainerSurface @override void apply() { - flutterViewEmbedder.removeResource(_filterElement); + flutterViewEmbedder.removeResource(_filterElement as html.Element?); _filterElement = null; final EngineColorFilter? engineValue = filter as EngineColorFilter?; if (engineValue == null) { @@ -139,7 +139,7 @@ class PersistedColorFilter extends PersistedContainerSurface // Use SVG filter for blend mode. final SvgFilter svgFilter = svgFilterFromBlendMode(filterColor, colorFilterBlendMode); _filterElement = svgFilter.element; - flutterViewEmbedder.addResource(_filterElement!); + flutterViewEmbedder.addResource(_filterElement! as html.Element); style.filter = 'url(#${svgFilter.id})'; if (colorFilterBlendMode == ui.BlendMode.saturation || colorFilterBlendMode == ui.BlendMode.multiply || @@ -151,7 +151,7 @@ class PersistedColorFilter extends PersistedContainerSurface void _applyMatrixColorFilter(CkMatrixColorFilter colorFilter) { final SvgFilter svgFilter = svgFilterFromColorMatrix(colorFilter.matrix); _filterElement = svgFilter.element; - flutterViewEmbedder.addResource(_filterElement!); + flutterViewEmbedder.addResource(_filterElement! as html.Element); childContainer!.style.filter = 'url(#${svgFilter.id})'; } @@ -272,20 +272,21 @@ class SvgFilterBuilder { } final String id; - final svg.SvgSvgElement root = kSvgResourceHeader.clone(false) as svg.SvgSvgElement; - final svg.FilterElement filter = svg.FilterElement(); + final SVGSVGElement root = kSvgResourceHeader.cloneNode(false) as + SVGSVGElement; + final SVGFilterElement filter = createSVGFilterElement(); set colorInterpolationFilters(String filters) { filter.setAttribute('color-interpolation-filters', filters); } void setFeColorMatrix(List matrix, { required String result }) { - final svg.FEColorMatrixElement element = svg.FEColorMatrixElement(); + final SVGFEColorMatrixElement element = createSVGFEColorMatrixElement(); element.type!.baseVal = kMatrixType; element.result!.baseVal = result; - final svg.NumberList value = element.values!.baseVal!; + final SVGNumberList value = element.values!.baseVal!; for (int i = 0; i < matrix.length; i++) { - value.appendItem(root.createSvgNumber()..value = matrix[i]); + value.appendItem(root.createSVGNumber()..value = matrix[i]); } filter.append(element); } @@ -295,7 +296,7 @@ class SvgFilterBuilder { required String floodOpacity, required String result, }) { - final svg.FEFloodElement element = svg.FEFloodElement(); + final SVGFEFloodElement element = createSVGFEFloodElement(); element.setAttribute('flood-color', floodColor); element.setAttribute('flood-opacity', floodOpacity); element.result!.baseVal = result; @@ -307,7 +308,7 @@ class SvgFilterBuilder { required String in2, required int mode, }) { - final svg.FEBlendElement element = svg.FEBlendElement(); + final SVGFEBlendElement element = createSVGFEBlendElement(); element.in1!.baseVal = in1; element.in2!.baseVal = in2; element.mode!.baseVal = mode; @@ -324,7 +325,7 @@ class SvgFilterBuilder { num? k4, required String result, }) { - final svg.FECompositeElement element = svg.SvgElement.tag('feComposite') as svg.FECompositeElement; + final SVGFECompositeElement element = createSVGFECompositeElement(); element.in1!.baseVal = in1; element.in2!.baseVal = in2; element.operator!.baseVal = operator; @@ -350,17 +351,17 @@ class SvgFilterBuilder { required double width, required double height, }) { - final svg.FEImageElement element = svg.FEImageElement(); + final SVGFEImageElement element = createSVGFEImageElement(); element.href!.baseVal = href; element.result!.baseVal = result; // WebKit will not render if x/y/width/height is specified. So we return // explicit size here unless running on WebKit. if (browserEngine != BrowserEngine.webkit) { - element.x!.baseVal!.newValueSpecifiedUnits(svg.Length.SVG_LENGTHTYPE_NUMBER, 0); - element.y!.baseVal!.newValueSpecifiedUnits(svg.Length.SVG_LENGTHTYPE_NUMBER, 0); - element.width!.baseVal!.newValueSpecifiedUnits(svg.Length.SVG_LENGTHTYPE_NUMBER, width); - element.height!.baseVal!.newValueSpecifiedUnits(svg.Length.SVG_LENGTHTYPE_NUMBER, height); + element.x!.baseVal!.newValueSpecifiedUnits(svgLengthTypeNumber, 0); + element.y!.baseVal!.newValueSpecifiedUnits(svgLengthTypeNumber, 0); + element.width!.baseVal!.newValueSpecifiedUnits(svgLengthTypeNumber, width); + element.height!.baseVal!.newValueSpecifiedUnits(svgLengthTypeNumber, height); } filter.append(element); } @@ -375,7 +376,7 @@ class SvgFilter { SvgFilter._(this.id, this.element); final String id; - final svg.SvgSvgElement element; + final SVGSVGElement element; } SvgFilter svgFilterFromColorMatrix(List matrix) { diff --git a/lib/web_ui/lib/src/engine/html/path_to_svg_clip.dart b/lib/web_ui/lib/src/engine/html/path_to_svg_clip.dart index 4a586e3212133..24f5fe5eb044e 100644 --- a/lib/web_ui/lib/src/engine/html/path_to_svg_clip.dart +++ b/lib/web_ui/lib/src/engine/html/path_to_svg_clip.dart @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:svg' as svg; - import 'package:ui/ui.dart' as ui; import '../browser_detection.dart'; +import '../dom.dart'; +import '../svg.dart'; import 'path/path.dart'; import 'path/path_to_svg.dart'; @@ -17,7 +17,7 @@ int _clipIdCounter = 0; /// /// Position needs to be absolute since these svgs are sandwiched between /// canvas elements and can cause layout shifts otherwise. -final svg.SvgSvgElement kSvgResourceHeader = svg.SvgSvgElement() +final SVGSVGElement kSvgResourceHeader = createSVGSVGElement() ..setAttribute('width', 0) ..setAttribute('height', 0) ..style.position = 'absolute'; @@ -26,22 +26,22 @@ final svg.SvgSvgElement kSvgResourceHeader = svg.SvgSvgElement() /// /// Calling this method updates [_clipIdCounter]. The HTML id of the generated /// clip is set to "svgClip${_clipIdCounter}", e.g. "svgClip123". -svg.SvgSvgElement pathToSvgClipPath(ui.Path path, +SVGSVGElement pathToSvgClipPath(ui.Path path, {double offsetX = 0, double offsetY = 0, double scaleX = 1.0, double scaleY = 1.0}) { _clipIdCounter += 1; - final svg.SvgSvgElement root = kSvgResourceHeader.clone(false) as svg.SvgSvgElement; - final svg.DefsElement defs = svg.DefsElement(); + final SVGSVGElement root = kSvgResourceHeader.cloneNode(false) as SVGSVGElement; + final SVGDefsElement defs = createSVGDefsElement(); root.append(defs); final String clipId = 'svgClip$_clipIdCounter'; - final svg.ClipPathElement clipPath = svg.ClipPathElement(); + final SVGClipPathElement clipPath = createSVGClipPathElement(); defs.append(clipPath); clipPath.id = clipId; - final svg.PathElement svgPath = svg.PathElement(); + final SVGPathElement svgPath = createSVGPathElement(); clipPath.append(svgPath); svgPath.setAttribute('fill', '#FFFFFF'); diff --git a/lib/web_ui/lib/src/engine/html/shader_mask.dart b/lib/web_ui/lib/src/engine/html/shader_mask.dart index af0e64a97658b..526bf880ad418 100644 --- a/lib/web_ui/lib/src/engine/html/shader_mask.dart +++ b/lib/web_ui/lib/src/engine/html/shader_mask.dart @@ -162,7 +162,7 @@ class PersistedShaderMask extends PersistedContainerSurface final SvgFilter svgFilter = svgMaskFilterFromImageAndBlendMode( imageUrl, blendModeTemp, maskRect.width, maskRect.height); - _shaderElement = svgFilter.element; + _shaderElement = svgFilter.element as html.Element; if (isWebKit) { _childContainer!.style.filter = 'url(#${svgFilter.id})'; } else { diff --git a/lib/web_ui/lib/src/engine/profiler.dart b/lib/web_ui/lib/src/engine/profiler.dart index 369c47489e570..13dc6ed1726d4 100644 --- a/lib/web_ui/lib/src/engine/profiler.dart +++ b/lib/web_ui/lib/src/engine/profiler.dart @@ -3,10 +3,10 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:html' as html; import 'package:ui/ui.dart' as ui; +import 'dom.dart'; import 'platform_dispatcher.dart'; import 'safe_browser_api.dart'; @@ -107,7 +107,7 @@ class Profiler { // out at certain optimization levels in dart2js, leading to obscure errors // later on. final Object? onBenchmark = getJsProperty( - html.window, + domWindow, '_flutter_internal_on_benchmark', ); onBenchmark as OnBenchmark?; @@ -224,7 +224,7 @@ void frameTimingsOnRasterFinish() { /// particularly notes about Firefox rounding to 1ms for security reasons, /// which can be bypassed in tests by setting certain browser options. int _nowMicros() { - return (html.window.performance.now() * 1000).toInt(); + return (domWindow.performance.now() * 1000).toInt(); } /// Counts various events that take place while the app is running. diff --git a/lib/web_ui/lib/src/engine/semantics/accessibility.dart b/lib/web_ui/lib/src/engine/semantics/accessibility.dart index 2a63357d53255..612473e9567b0 100644 --- a/lib/web_ui/lib/src/engine/semantics/accessibility.dart +++ b/lib/web_ui/lib/src/engine/semantics/accessibility.dart @@ -3,10 +3,10 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:html' as html; import 'dart:typed_data'; import '../../engine.dart' show registerHotRestartListener; +import '../dom.dart'; import '../services.dart'; import '../util.dart'; @@ -52,9 +52,9 @@ class AccessibilityAnnouncements { /// This element has aria-live attribute. /// /// It also has id 'accessibility-element' for testing purposes. - html.HtmlElement? _element; + DomHTMLElement? _element; - html.HtmlElement get _domElement => _element ??= _createElement(); + DomHTMLElement get _domElement => _element ??= _createElement(); /// Decodes the message coming from the 'flutter/accessibility' channel. void handleMessage(StandardMessageCodec codec, ByteData? data) { @@ -73,11 +73,11 @@ class AccessibilityAnnouncements { void _initLiveRegion(String message) { _domElement.setAttribute('aria-live', 'polite'); _domElement.text = message; - html.document.body!.append(_domElement); + domDocument.body!.append(_domElement); } - html.LabelElement _createElement() { - final html.LabelElement liveRegion = html.LabelElement(); + DomHTMLLabelElement _createElement() { + final DomHTMLLabelElement liveRegion = createDomHTMLLabelElement(); liveRegion.setAttribute('id', 'accessibility-element'); liveRegion.style ..position = 'fixed' diff --git a/lib/web_ui/lib/src/engine/svg.dart b/lib/web_ui/lib/src/engine/svg.dart index 791fffcd04f34..8f0ffbc743b90 100644 --- a/lib/web_ui/lib/src/engine/svg.dart +++ b/lib/web_ui/lib/src/engine/svg.dart @@ -28,6 +28,12 @@ SVGSVGElement createSVGSVGElement() { return el as SVGSVGElement; } +extension SVGSVGElementExtension on SVGSVGElement { + external SVGNumber createSVGNumber(); + external SVGAnimatedLength? get height; + external SVGAnimatedLength? get width; +} + @JS() @staticInterop class SVGClipPathElement extends SVGGraphicsElement {} @@ -55,3 +61,162 @@ class SVGPathElement extends SVGGeometryElement {} SVGPathElement createSVGPathElement() => domDocument.createElementNS('http://www.w3.org/2000/svg', 'path') as SVGPathElement; + +@JS() +@staticInterop +class SVGFilterElement extends SVGElement {} + +extension SVGFilterElementExtension on SVGFilterElement { + external SVGAnimatedEnumeration? get filterUnits; + external SVGAnimatedLength? get height; + external SVGAnimatedLength? get width; + external SVGAnimatedLength? get x; + external SVGAnimatedLength? get y; +} + +SVGFilterElement createSVGFilterElement() => + domDocument.createElementNS('http://www.w3.org/2000/svg', 'filter') + as SVGFilterElement; + +@JS() +@staticInterop +class SVGAnimatedLength {} + +extension SVGAnimatedLengthExtension on SVGAnimatedLength { + external SVGLength? get baseVal; +} + +@JS() +@staticInterop +class SVGLength {} + +extension SVGLengthExtension on SVGLength { + external set valueAsString(String? value); + external void newValueSpecifiedUnits(int unitType, num valueInSpecifiedUnits); +} + +const int svgLengthTypeNumber = 1; + +@JS() +@staticInterop +class SVGAnimatedEnumeration {} + +extension SVGAnimatedEnumerationExtenson on SVGAnimatedEnumeration { + external set baseVal(int? value); +} + +@JS() +@staticInterop +class SVGFEColorMatrixElement extends SVGElement {} + +extension SVGFEColorMatrixElementExtension on SVGFEColorMatrixElement { + external SVGAnimatedEnumeration? get type; + external SVGAnimatedString? get result; + external SVGAnimatedNumberList? get values; +} + +SVGFEColorMatrixElement createSVGFEColorMatrixElement() => + domDocument.createElementNS('http://www.w3.org/2000/svg', 'feColorMatrix') + as SVGFEColorMatrixElement; + +@JS() +@staticInterop +class SVGFEFloodElement extends SVGElement {} + +extension SVGFEFloodElementExtension on SVGFEFloodElement { + external SVGAnimatedString? get result; +} + +SVGFEFloodElement createSVGFEFloodElement() => + domDocument.createElementNS('http://www.w3.org/2000/svg', 'feFlood') + as SVGFEFloodElement; + +@JS() +@staticInterop +class SVGFEBlendElement extends SVGElement {} + +extension SVGFEBlendElementExtension on SVGFEBlendElement { + external SVGAnimatedString? get in1; + external SVGAnimatedString? get in2; + external SVGAnimatedEnumeration? get mode; +} + +SVGFEBlendElement createSVGFEBlendElement() => + domDocument.createElementNS('http://www.w3.org/2000/svg', 'feBlend') + as SVGFEBlendElement; + +@JS() +@staticInterop +class SVGFEImageElement extends SVGElement {} + +extension SVGFEImageElementExtension on SVGFEImageElement { + external SVGAnimatedLength? get height; + external SVGAnimatedLength? get width; + external SVGAnimatedString? get result; + external SVGAnimatedLength? get x; + external SVGAnimatedLength? get y; + external SVGAnimatedString? get href; +} + +SVGFEImageElement createSVGFEImageElement() => + domDocument.createElementNS('http://www.w3.org/2000/svg', 'feImage') + as SVGFEImageElement; + +@JS() +@staticInterop +class SVGFECompositeElement extends SVGElement {} + +SVGFECompositeElement createSVGFECompositeElement() => + domDocument.createElementNS('http://www.w3.org/2000/svg', 'feComposite') + as SVGFECompositeElement; + +extension SVGFEBlendCompositeExtension on SVGFECompositeElement { + external SVGAnimatedString? get in1; + external SVGAnimatedString? get in2; + external SVGAnimatedNumber? get k1; + external SVGAnimatedNumber? get k2; + external SVGAnimatedNumber? get k3; + external SVGAnimatedNumber? get k4; + external SVGAnimatedEnumeration? get operator; + external SVGAnimatedString? get result; +} + +@JS() +@staticInterop +class SVGAnimatedString {} + +extension SVGAnimatedStringExtension on SVGAnimatedString { + external set baseVal(String? value); +} + +@JS() +@staticInterop +class SVGAnimatedNumber {} + +extension SVGAnimatedNumberExtension on SVGAnimatedNumber { + external set baseVal(num? value); +} + +@JS() +@staticInterop +class SVGAnimatedNumberList {} + +extension SVGAnimatedNumberListExtension on SVGAnimatedNumberList { + external SVGNumberList? get baseVal; +} + +@JS() +@staticInterop +class SVGNumberList {} + +extension SVGNumberListExtension on SVGNumberList { + external SVGNumber appendItem(SVGNumber newItem); +} + +@JS() +@staticInterop +class SVGNumber {} + +extension SVGNumberExtension on SVGNumber { + external set value(num? value); +} diff --git a/lib/web_ui/lib/src/engine/text/measurement.dart b/lib/web_ui/lib/src/engine/text/measurement.dart index 6eac6daa733f9..07b162ebc990b 100644 --- a/lib/web_ui/lib/src/engine/text/measurement.dart +++ b/lib/web_ui/lib/src/engine/text/measurement.dart @@ -16,11 +16,11 @@ import '../embedder.dart'; // anything as of this writing. const double baselineRatioHack = 1.1662499904632568; -/// Hosts ruler DOM elements in a hidden container under a `root` [html.Node]. +/// Hosts ruler DOM elements in a hidden container under a `root` [DomNode]. /// -/// The `root` [html.Node] is optional. Defaults to [flutterViewEmbedder.glassPaneShadow]. +/// The `root` [DomNode] is optional. Defaults to [flutterViewEmbedder.glassPaneShadow]. class RulerHost { - RulerHost({html.Node? root}) { + RulerHost({DomNode? root}) { _rulerHost.style ..position = 'fixed' ..visibility = 'hidden' @@ -30,7 +30,11 @@ class RulerHost { ..width = '0' ..height = '0'; - (root ?? flutterViewEmbedder.glassPaneShadow!.node).append(_rulerHost); + if (root == null) { + flutterViewEmbedder.glassPaneShadow!.node.append(_rulerHost as html.Node); + } else { + root.appendChild(_rulerHost); + } registerHotRestartListener(dispose); } @@ -40,7 +44,7 @@ class RulerHost { /// rulers would be attached to the `` element polluting the element /// tree and making it hard to navigate. It does not serve any functional /// purpose. - final html.Element _rulerHost = html.Element.tag('flt-ruler-host'); + final DomElement _rulerHost = createDomElement('flt-ruler-host'); /// Releases the resources used by this [RulerHost]. /// @@ -50,7 +54,7 @@ class RulerHost { } /// Adds an element used for measuring text as a child of [_rulerHost]. - void addElement(html.HtmlElement element) { + void addElement(DomHTMLElement element) { _rulerHost.append(element); } } diff --git a/lib/web_ui/lib/src/engine/text/ruler.dart b/lib/web_ui/lib/src/engine/text/ruler.dart index 6e04287e8791d..18c2d80821e91 100644 --- a/lib/web_ui/lib/src/engine/text/ruler.dart +++ b/lib/web_ui/lib/src/engine/text/ruler.dart @@ -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:ui/ui.dart' as ui; import '../browser_detection.dart'; @@ -212,7 +210,7 @@ class TextHeightRuler { // [rulerHost] is not migrated yet so add a cast to [html.HtmlElement]. // This cast will be removed after the migration is complete. - rulerHost.addElement(host as html.HtmlElement); + rulerHost.addElement(host); return host; } diff --git a/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart b/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart index 12d854ab80b2a..f6204578d98fe 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart @@ -2,9 +2,8 @@ // 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'; /// Controls the capitalization of the text. /// @@ -58,7 +57,7 @@ class TextCapitalizationConfig { /// /// See: https://developers.google.com/web/updates/2015/04/autocapitalize /// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autocapitalize - void setAutocapitalizeAttribute(html.HtmlElement domElement) { + void setAutocapitalizeAttribute(DomHTMLElement domElement) { String autocapitalize = ''; switch (textCapitalization) { case TextCapitalization.words: @@ -82,11 +81,12 @@ class TextCapitalizationConfig { autocapitalize = 'off'; break; } - if (domElement is html.InputElement) { - final html.InputElement element = domElement; + if (domInstanceOfString(domElement, 'HTMLInputElement')) { + final DomHTMLInputElement element = domElement as DomHTMLInputElement; element.setAttribute('autocapitalize', autocapitalize); - } else if (domElement is html.TextAreaElement) { - final html.TextAreaElement element = domElement; + } else if (domInstanceOfString(domElement, 'HTMLTextAreaElement')) { + final DomHTMLTextAreaElement element = domElement as + DomHTMLTextAreaElement; element.setAttribute('autocapitalize', autocapitalize); } } diff --git a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart index d84704a920541..27df6e8353edb 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_editing.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_editing.dart @@ -1475,8 +1475,7 @@ class IOSTextEditingStrategy extends GloballyPositionedTextEditingStrategy { if (hasAutofillGroup) { placeForm(); } - inputConfig.textCapitalization.setAutocapitalizeAttribute(activeDomElement - as html.HtmlElement); + inputConfig.textCapitalization.setAutocapitalizeAttribute(activeDomElement); } @override @@ -1637,7 +1636,7 @@ class AndroidTextEditingStrategy extends GloballyPositionedTextEditingStrategy { defaultTextEditingRoot.append(activeDomElement as html.Node); } inputConfig.textCapitalization.setAutocapitalizeAttribute( - activeDomElement as html.HtmlElement); + activeDomElement); } @override diff --git a/lib/web_ui/lib/src/engine/util.dart b/lib/web_ui/lib/src/engine/util.dart index 67d8e66724bfe..0cea4ae4a03c3 100644 --- a/lib/web_ui/lib/src/engine/util.dart +++ b/lib/web_ui/lib/src/engine/util.dart @@ -5,7 +5,6 @@ library util; import 'dart:async'; -import 'dart:html' as html; import 'dart:math' as math; import 'dart:typed_data'; @@ -524,7 +523,7 @@ int clampInt(int value, int min, int max) { /// /// This function can be overridden in tests. This could be useful, for example, /// to verify that warnings are printed under certain circumstances. -void Function(String) printWarning = html.window.console.warn; +void Function(String) printWarning = domWindow.console.warn; /// Determines if lists [a] and [b] are deep equivalent. /// @@ -560,7 +559,7 @@ bool unsafeIsNull(dynamic object) { /// A typed variant of [html.Window.fetch]. Future httpFetch(String url) async { - final Object? result = await html.window.fetch(url); + final Object? result = await domWindow.fetch(url); return result! as DomResponse; } @@ -680,13 +679,13 @@ void setClipPath(DomElement element, String? value) { } void setThemeColor(ui.Color color) { - html.MetaElement? theme = - html.document.querySelector('#flutterweb-theme') as html.MetaElement?; + DomHTMLMetaElement? theme = + domDocument.querySelector('#flutterweb-theme') as DomHTMLMetaElement?; if (theme == null) { - theme = html.MetaElement() + theme = createDomHTMLMetaElement() ..id = 'flutterweb-theme' ..name = 'theme-color'; - html.document.head!.append(theme); + domDocument.head!.append(theme); } theme.content = colorToCssString(color)!; } diff --git a/lib/web_ui/test/html/path_to_svg_golden_test.dart b/lib/web_ui/test/html/path_to_svg_golden_test.dart index d274a002e3330..af39d75a4df28 100644 --- a/lib/web_ui/test/html/path_to_svg_golden_test.dart +++ b/lib/web_ui/test/html/path_to_svg_golden_test.dart @@ -2,9 +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:svg' as svg; - import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; @@ -61,7 +58,7 @@ Future testMain() async { canvas.drawPath(path, paint!); - final html.Element svgElement = pathToSvgElement(path, paint, enableFill); + final DomElement svgElement = pathToSvgElement(path, paint, enableFill); canvas.endRecording(); canvas.apply(bitmapCanvas, canvasBounds); @@ -75,7 +72,7 @@ Future testMain() async { sceneElement.style.transform = 'scale(0.3)'; } sceneElement.append(bitmapCanvas.rootElement); - sceneElement.append(svgElement as DomElement); + sceneElement.append(svgElement); await matchGoldenFile('$scubaFileName.png', region: region, maxDiffRatePercent: maxDiffRatePercent, write: write); @@ -85,7 +82,7 @@ Future testMain() async { } tearDown(() { - html.document.body!.children.clear(); + domDocument.body!.clearChildren(); }); test('render line strokes', () async { @@ -193,15 +190,15 @@ Future testMain() async { }); } -html.Element pathToSvgElement(Path path, Paint paint, bool enableFill) { +DomElement pathToSvgElement(Path path, Paint paint, bool enableFill) { final Rect bounds = path.getBounds(); - final svg.SvgSvgElement root = svg.SvgSvgElement(); + final SVGSVGElement root = createSVGSVGElement(); root.style.transform = 'translate(200px, 0px)'; root.setAttribute('viewBox', '0 0 ${bounds.right} ${bounds.bottom}'); - root.width!.baseVal!.newValueSpecifiedUnits(svg.Length.SVG_LENGTHTYPE_NUMBER, bounds.right); - root.height!.baseVal!.newValueSpecifiedUnits(svg.Length.SVG_LENGTHTYPE_NUMBER, bounds.bottom); + root.width!.baseVal!.newValueSpecifiedUnits(svgLengthTypeNumber, bounds.right); + root.height!.baseVal!.newValueSpecifiedUnits(svgLengthTypeNumber, bounds.bottom); - final svg.PathElement pathElement = svg.PathElement(); + final SVGPathElement pathElement = createSVGPathElement(); root.append(pathElement); if (paint.style == PaintingStyle.stroke || paint.strokeWidth != 0.0) {