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 - 5 (flutter/engine#33020)
This commit is contained in:
parent
7585f8938d
commit
d493db8aac
@ -10,6 +10,7 @@ import 'package:ui/ui.dart' as ui;
|
||||
|
||||
import '../../engine.dart' show platformViewManager;
|
||||
import '../configuration.dart';
|
||||
import '../dom.dart';
|
||||
import '../html/path_to_svg_clip.dart';
|
||||
import '../platform_views/slots.dart';
|
||||
import '../util.dart';
|
||||
@ -212,10 +213,10 @@ class HtmlViewEmbedder {
|
||||
void _compositeWithParams(int viewId, EmbeddedViewParams params) {
|
||||
// If we haven't seen this viewId yet, cache it for clips/transforms.
|
||||
final ViewClipChain clipChain = _viewClipChains.putIfAbsent(viewId, () {
|
||||
return ViewClipChain(view: createPlatformViewSlot(viewId));
|
||||
return ViewClipChain(view: createPlatformViewSlot(viewId) as DomElement);
|
||||
});
|
||||
|
||||
final html.Element slot = clipChain.slot;
|
||||
final DomElement slot = clipChain.slot;
|
||||
|
||||
// See `apply()` in the PersistedPlatformView class for the HTML version
|
||||
// of this code.
|
||||
@ -228,8 +229,8 @@ class HtmlViewEmbedder {
|
||||
final int currentClippingCount = _countClips(params.mutators);
|
||||
final int previousClippingCount = clipChain.clipCount;
|
||||
if (currentClippingCount != previousClippingCount) {
|
||||
final html.Element oldPlatformViewRoot = clipChain.root;
|
||||
final html.Element newPlatformViewRoot = _reconstructClipViewsChain(
|
||||
final DomElement oldPlatformViewRoot = clipChain.root;
|
||||
final DomElement newPlatformViewRoot = _reconstructClipViewsChain(
|
||||
currentClippingCount,
|
||||
slot,
|
||||
oldPlatformViewRoot,
|
||||
@ -255,26 +256,26 @@ class HtmlViewEmbedder {
|
||||
return clipCount;
|
||||
}
|
||||
|
||||
html.Element _reconstructClipViewsChain(
|
||||
DomElement _reconstructClipViewsChain(
|
||||
int numClips,
|
||||
html.Element platformView,
|
||||
html.Element headClipView,
|
||||
DomElement platformView,
|
||||
DomElement headClipView,
|
||||
) {
|
||||
int indexInFlutterView = -1;
|
||||
if (headClipView.parent != null) {
|
||||
if (headClipView.parentElement != null) {
|
||||
indexInFlutterView = skiaSceneHost!.children.indexOf(headClipView);
|
||||
headClipView.remove();
|
||||
}
|
||||
html.Element head = platformView;
|
||||
DomElement head = platformView;
|
||||
int clipIndex = 0;
|
||||
// Re-use as much existing clip views as needed.
|
||||
while (head != headClipView && clipIndex < numClips) {
|
||||
head = head.parent!;
|
||||
head = head.parentElement!;
|
||||
clipIndex++;
|
||||
}
|
||||
// If there weren't enough existing clip views, add more.
|
||||
while (clipIndex < numClips) {
|
||||
final html.Element clippingView = html.Element.tag('flt-clip');
|
||||
final DomElement clippingView = createDomElement('flt-clip');
|
||||
clippingView.append(head);
|
||||
head = clippingView;
|
||||
clipIndex++;
|
||||
@ -309,9 +310,9 @@ class HtmlViewEmbedder {
|
||||
}
|
||||
|
||||
void _applyMutators(
|
||||
EmbeddedViewParams params, html.Element embeddedView, int viewId) {
|
||||
EmbeddedViewParams params, DomElement embeddedView, int viewId) {
|
||||
final MutatorsStack mutators = params.mutators;
|
||||
html.Element head = embeddedView;
|
||||
DomElement head = embeddedView;
|
||||
Matrix4 headTransform = params.offset == ui.Offset.zero
|
||||
? Matrix4.identity()
|
||||
: Matrix4.translationValues(params.offset.dx, params.offset.dy, 0);
|
||||
@ -329,7 +330,7 @@ class HtmlViewEmbedder {
|
||||
case MutatorType.clipRect:
|
||||
case MutatorType.clipRRect:
|
||||
case MutatorType.clipPath:
|
||||
final html.Element clipView = head.parent!;
|
||||
final DomElement clipView = head.parentElement!;
|
||||
clipView.style.clip = '';
|
||||
clipView.style.clipPath = '';
|
||||
headTransform = Matrix4.identity();
|
||||
@ -397,14 +398,15 @@ class HtmlViewEmbedder {
|
||||
final Matrix4 scaleMatrix =
|
||||
Matrix4.diagonal3Values(inverseScale, inverseScale, 1);
|
||||
headTransform = scaleMatrix.multiplied(headTransform);
|
||||
head.style.transform = float64ListToCssTransform(headTransform.storage);
|
||||
head.style.transform =
|
||||
float64ListToCssTransform(headTransform.storage);
|
||||
}
|
||||
|
||||
/// Sets the transform origin to the top-left corner of the element.
|
||||
///
|
||||
/// By default, the transform origin is the center of the element, but
|
||||
/// Flutter assumes the transform origin is the top-left point.
|
||||
void _resetAnchor(html.Element element) {
|
||||
void _resetAnchor(DomElement element) {
|
||||
element.style.transformOrigin = '0 0 0';
|
||||
element.style.position = 'absolute';
|
||||
}
|
||||
@ -424,7 +426,7 @@ class HtmlViewEmbedder {
|
||||
}
|
||||
_svgPathDefs = kSvgResourceHeader.clone(false) as svg.SvgSvgElement;
|
||||
_svgPathDefs!.append(svg.DefsElement()..id = 'sk_path_defs');
|
||||
skiaSceneHost!.append(_svgPathDefs!);
|
||||
skiaSceneHost!.append(_svgPathDefs! as DomElement);
|
||||
}
|
||||
|
||||
void submitFrame() {
|
||||
@ -489,7 +491,7 @@ class HtmlViewEmbedder {
|
||||
_activeCompositionOrder.addAll(_compositionOrder);
|
||||
unusedViews.removeAll(_compositionOrder);
|
||||
|
||||
html.Element? elementToInsertBefore;
|
||||
DomElement? elementToInsertBefore;
|
||||
if (diffResult.addToBeginning) {
|
||||
elementToInsertBefore =
|
||||
_viewClipChains[diffResult.viewToInsertBefore!]!.root;
|
||||
@ -504,27 +506,26 @@ class HtmlViewEmbedder {
|
||||
}
|
||||
}
|
||||
if (diffResult.addToBeginning) {
|
||||
final html.Element platformViewRoot = _viewClipChains[viewId]!.root;
|
||||
final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
|
||||
skiaSceneHost!.insertBefore(platformViewRoot, elementToInsertBefore);
|
||||
final Surface? overlay = _overlays[viewId];
|
||||
if (overlay != null) {
|
||||
skiaSceneHost!
|
||||
.insertBefore(overlay.htmlElement as html.Element, elementToInsertBefore);
|
||||
.insertBefore(overlay.htmlElement, elementToInsertBefore);
|
||||
}
|
||||
} else {
|
||||
final html.Element platformViewRoot = _viewClipChains[viewId]!.root;
|
||||
final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
|
||||
skiaSceneHost!.append(platformViewRoot);
|
||||
final Surface? overlay = _overlays[viewId];
|
||||
if (overlay != null) {
|
||||
skiaSceneHost!.append(overlay.htmlElement as html.Element);
|
||||
skiaSceneHost!.append(overlay.htmlElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
insertBeforeMap?.forEach((int viewId, int viewIdToInsertBefore) {
|
||||
final html.Element overlay = _overlays[viewId]!.htmlElement as
|
||||
html.Element;
|
||||
final DomElement overlay = _overlays[viewId]!.htmlElement;
|
||||
if (viewIdToInsertBefore != -1) {
|
||||
final html.Element nextSibling =
|
||||
final DomElement nextSibling =
|
||||
_viewClipChains[viewIdToInsertBefore]!.root;
|
||||
skiaSceneHost!.insertBefore(overlay, nextSibling);
|
||||
} else {
|
||||
@ -533,8 +534,7 @@ class HtmlViewEmbedder {
|
||||
});
|
||||
if (_didPaintBackupSurface) {
|
||||
skiaSceneHost!
|
||||
.append(SurfaceFactory.instance.backupSurface.htmlElement as
|
||||
html.Element);
|
||||
.append(SurfaceFactory.instance.backupSurface.htmlElement);
|
||||
}
|
||||
} else {
|
||||
SurfaceFactory.instance.removeSurfacesFromDom();
|
||||
@ -549,19 +549,18 @@ class HtmlViewEmbedder {
|
||||
}
|
||||
}
|
||||
|
||||
final html.Element platformViewRoot = _viewClipChains[viewId]!.root;
|
||||
final DomElement platformViewRoot = _viewClipChains[viewId]!.root;
|
||||
final Surface? overlay = _overlays[viewId];
|
||||
skiaSceneHost!.append(platformViewRoot);
|
||||
if (overlay != null) {
|
||||
skiaSceneHost!.append(overlay.htmlElement as html.Element);
|
||||
skiaSceneHost!.append(overlay.htmlElement);
|
||||
}
|
||||
_activeCompositionOrder.add(viewId);
|
||||
unusedViews.remove(viewId);
|
||||
}
|
||||
if (_didPaintBackupSurface) {
|
||||
skiaSceneHost!
|
||||
.append(SurfaceFactory.instance.backupSurface.htmlElement as
|
||||
html.Element);
|
||||
.append(SurfaceFactory.instance.backupSurface.htmlElement);
|
||||
}
|
||||
}
|
||||
|
||||
@ -770,19 +769,19 @@ class HtmlViewEmbedder {
|
||||
/// * The slot view in the stack (the actual contents of the platform view).
|
||||
/// * The number of clipping elements used last time the view was composited.
|
||||
class ViewClipChain {
|
||||
html.Element _root;
|
||||
html.Element _slot;
|
||||
DomElement _root;
|
||||
DomElement _slot;
|
||||
int _clipCount = -1;
|
||||
|
||||
ViewClipChain({required html.Element view})
|
||||
ViewClipChain({required DomElement view})
|
||||
: _root = view,
|
||||
_slot = view;
|
||||
|
||||
html.Element get root => _root;
|
||||
html.Element get slot => _slot;
|
||||
DomElement get root => _root;
|
||||
DomElement get slot => _slot;
|
||||
int get clipCount => _clipCount;
|
||||
|
||||
void updateClipChain({required html.Element root, required int clipCount}) {
|
||||
void updateClipChain({required DomElement root, required int clipCount}) {
|
||||
_root = root;
|
||||
_clipCount = clipCount;
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
library canvaskit_initialization;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:html' as html;
|
||||
|
||||
import '../../engine.dart' show kProfileMode;
|
||||
import '../browser_detection.dart';
|
||||
@ -119,4 +118,4 @@ void ensureSkiaFontCollectionInitialized() {
|
||||
}
|
||||
|
||||
/// The scene host, where the root canvas and overlay canvases are added to.
|
||||
html.Element? skiaSceneHost;
|
||||
DomElement? skiaSceneHost;
|
||||
|
||||
@ -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';
|
||||
@ -133,7 +131,7 @@ class Surface {
|
||||
|
||||
void addToScene() {
|
||||
if (!_addedToScene) {
|
||||
skiaSceneHost!.children.insert(0, htmlElement as html.Element);
|
||||
skiaSceneHost!.prepend(htmlElement);
|
||||
}
|
||||
_addedToScene = true;
|
||||
}
|
||||
@ -210,8 +208,8 @@ class Surface {
|
||||
final double logicalWidth = _pixelWidth / window.devicePixelRatio;
|
||||
final double logicalHeight = _pixelHeight / window.devicePixelRatio;
|
||||
final DomCSSStyleDeclaration style = htmlCanvas!.style;
|
||||
style.setProperty('width', '${logicalWidth}px');
|
||||
style.setProperty('height', '${logicalHeight}px');
|
||||
style.width = '${logicalWidth}px';
|
||||
style.height = '${logicalHeight}px';
|
||||
}
|
||||
|
||||
/// Translate the canvas so the surface covers the visible portion of the
|
||||
@ -226,7 +224,7 @@ class Surface {
|
||||
final int surfaceHeight = _currentSurfaceSize!.height.ceil();
|
||||
final double offset =
|
||||
(_pixelHeight - surfaceHeight) / window.devicePixelRatio;
|
||||
htmlCanvas!.style.setProperty('transform', 'translate(0, -${offset}px)');
|
||||
htmlCanvas!.style.transform = 'translate(0, -${offset}px)';
|
||||
}
|
||||
|
||||
void _contextRestoredListener(DomEvent event) {
|
||||
@ -296,7 +294,7 @@ class Surface {
|
||||
// accessible.
|
||||
htmlCanvas.setAttribute('aria-hidden', 'true');
|
||||
|
||||
htmlCanvas.style.setProperty('position', 'absolute');
|
||||
htmlCanvas.style.position = 'absolute';
|
||||
_updateLogicalHtmlCanvasSize();
|
||||
|
||||
// When the browser tab using WebGL goes dormant the browser and/or OS may
|
||||
|
||||
@ -112,6 +112,7 @@ extension DomElementExtension on DomElement {
|
||||
external /* List<DomElement> */ List<Object?> get children;
|
||||
external DomCSSStyleDeclaration get style;
|
||||
external void append(DomNode node);
|
||||
external void prepend(DomNode node);
|
||||
external void setAttribute(String name, Object value);
|
||||
}
|
||||
|
||||
@ -120,6 +121,23 @@ extension DomElementExtension on DomElement {
|
||||
class DomCSSStyleDeclaration {}
|
||||
|
||||
extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
|
||||
set width(String value) => setProperty('width', value);
|
||||
set height(String value) => setProperty('height', value);
|
||||
set position(String value) => setProperty('position', value);
|
||||
set clip(String value) => setProperty('clip', value);
|
||||
set clipPath(String value) => setProperty('clip-path', value);
|
||||
set transform(String value) => setProperty('transform', value);
|
||||
set transformOrigin(String value) => setProperty('transform-origin', value);
|
||||
set opacity(String value) => setProperty('opacity', value);
|
||||
String get width => getPropertyValue('width');
|
||||
String get height => getPropertyValue('height');
|
||||
String get position => getPropertyValue('position');
|
||||
String get clip => getPropertyValue('clip');
|
||||
String get clipPath => getPropertyValue('clip-path');
|
||||
String get transform => getPropertyValue('transform');
|
||||
String get transformOrigin => getPropertyValue('transform-origin');
|
||||
String get opacity => getPropertyValue('opacity');
|
||||
|
||||
external String getPropertyValue(String property);
|
||||
external void setProperty(String propertyName, String value, [String
|
||||
priority]);
|
||||
|
||||
@ -11,6 +11,7 @@ import '../engine.dart' show buildMode, registerHotRestartListener;
|
||||
import 'browser_detection.dart';
|
||||
import 'canvaskit/initialization.dart';
|
||||
import 'configuration.dart';
|
||||
import 'dom.dart';
|
||||
import 'host_node.dart';
|
||||
import 'keyboard_binding.dart';
|
||||
import 'platform_dispatcher.dart';
|
||||
@ -295,8 +296,8 @@ class FlutterViewEmbedder {
|
||||
/// added eagerly during initialization here and never touched, unless the
|
||||
/// system is reset due to hot restart or in a test.
|
||||
if (useCanvasKit) {
|
||||
skiaSceneHost = html.Element.tag('flt-scene');
|
||||
addSceneToSceneHost(skiaSceneHost);
|
||||
skiaSceneHost = createDomElement('flt-scene');
|
||||
addSceneToSceneHost(skiaSceneHost as html.Element?);
|
||||
}
|
||||
|
||||
final html.Element semanticsHostElement =
|
||||
|
||||
@ -29,8 +29,8 @@ void testMain() {
|
||||
// Expect exact requested dimensions.
|
||||
expect(original.width, 9);
|
||||
expect(original.height, 19);
|
||||
expect(original.style.getPropertyValue('width'), '9px');
|
||||
expect(original.style.getPropertyValue('height'), '19px');
|
||||
expect(original.style.width, '9px');
|
||||
expect(original.style.height, '19px');
|
||||
expect(originalSurface.width(), 9);
|
||||
expect(originalSurface.height(), 19);
|
||||
|
||||
@ -39,8 +39,8 @@ void testMain() {
|
||||
surface.acquireFrame(const ui.Size(5, 15)).skiaSurface;
|
||||
final DomCanvasElement shrunk = surface.htmlCanvas!;
|
||||
expect(shrunk, same(original));
|
||||
expect(shrunk.style.getPropertyValue('width'), '9px');
|
||||
expect(shrunk.style.getPropertyValue('height'), '19px');
|
||||
expect(shrunk.style.width, '9px');
|
||||
expect(shrunk.style.height, '19px');
|
||||
expect(shrunkSurface, isNot(same(original)));
|
||||
expect(shrunkSurface.width(), 5);
|
||||
expect(shrunkSurface.height(), 15);
|
||||
@ -56,8 +56,8 @@ void testMain() {
|
||||
// Expect overallocated dimensions
|
||||
expect(firstIncrease.width, 14);
|
||||
expect(firstIncrease.height, 28);
|
||||
expect(firstIncrease.style.getPropertyValue('width'), '14px');
|
||||
expect(firstIncrease.style.getPropertyValue('height'), '28px');
|
||||
expect(firstIncrease.style.width, '14px');
|
||||
expect(firstIncrease.style.height, '28px');
|
||||
expect(firstIncreaseSurface.width(), 10);
|
||||
expect(firstIncreaseSurface.height(), 20);
|
||||
|
||||
@ -79,8 +79,8 @@ void testMain() {
|
||||
// Also over-allocated
|
||||
expect(huge.width, 28);
|
||||
expect(huge.height, 56);
|
||||
expect(huge.style.getPropertyValue('width'), '28px');
|
||||
expect(huge.style.getPropertyValue('height'), '56px');
|
||||
expect(huge.style.width, '28px');
|
||||
expect(huge.style.height, '56px');
|
||||
expect(hugeSurface.width(), 20);
|
||||
expect(hugeSurface.height(), 40);
|
||||
|
||||
@ -154,8 +154,8 @@ void testMain() {
|
||||
|
||||
expect(original.width(), 10);
|
||||
expect(original.height(), 16);
|
||||
expect(surface.htmlCanvas!.style.getPropertyValue('width'), '10px');
|
||||
expect(surface.htmlCanvas!.style.getPropertyValue('height'), '16px');
|
||||
expect(surface.htmlCanvas!.style.width, '10px');
|
||||
expect(surface.htmlCanvas!.style.height, '16px');
|
||||
|
||||
// Increase device-pixel ratio: this makes CSS pixels bigger, so we need
|
||||
// fewer of them to cover the browser window.
|
||||
@ -164,8 +164,8 @@ void testMain() {
|
||||
surface.acquireFrame(const ui.Size(10, 16)).skiaSurface;
|
||||
expect(highDpr.width(), 10);
|
||||
expect(highDpr.height(), 16);
|
||||
expect(surface.htmlCanvas!.style.getPropertyValue('width'), '5px');
|
||||
expect(surface.htmlCanvas!.style.getPropertyValue('height'), '8px');
|
||||
expect(surface.htmlCanvas!.style.width, '5px');
|
||||
expect(surface.htmlCanvas!.style.height, '8px');
|
||||
|
||||
// Decrease device-pixel ratio: this makes CSS pixels smaller, so we need
|
||||
// more of them to cover the browser window.
|
||||
@ -174,8 +174,8 @@ void testMain() {
|
||||
surface.acquireFrame(const ui.Size(10, 16)).skiaSurface;
|
||||
expect(lowDpr.width(), 10);
|
||||
expect(lowDpr.height(), 16);
|
||||
expect(surface.htmlCanvas!.style.getPropertyValue('width'), '20px');
|
||||
expect(surface.htmlCanvas!.style.getPropertyValue('height'), '32px');
|
||||
expect(surface.htmlCanvas!.style.width, '20px');
|
||||
expect(surface.htmlCanvas!.style.height, '32px');
|
||||
});
|
||||
}, skip: isIosSafari);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user