blob: c06b7e69c80a5dc0a9b05f7f6854d15c9f0e4e2f [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of engine;
/// A surface containing a platform view, which is an HTML element.
class PersistedPlatformView extends PersistedLeafSurface {
final int viewId;
final double dx;
final double dy;
final double width;
final double height;
late html.ShadowRoot _shadowRoot;
PersistedPlatformView(this.viewId, this.dx, this.dy, this.width, this.height);
@override
html.Element createElement() {
html.Element element = defaultCreateElement('flt-platform-view');
// Allow the platform view host element to receive pointer events.
//
// This is to allow platform view HTML elements to be interactive.
//
// ACCESSIBILITY NOTE: The way we enable accessibility on Flutter for web
// is to have a full-page button which waits for a double tap. Placing this
// full-page button in front of the scene would cause platform views not
// to receive pointer events. The tradeoff is that by placing the scene in
// front of the semantics placeholder will cause platform views to block
// pointer events from reaching the placeholder. This means that in order
// to enable accessibility, you must double tap the app *outside of a
// platform view*. As a consequence, a full-screen platform view will make
// it impossible to enable accessibility.
element.style.pointerEvents = 'auto';
// Enforce the effective size of the PlatformView.
element.style.overflow = 'hidden';
_shadowRoot = element.attachShadow(<String, String>{'mode': 'open'});
final html.StyleElement _styleReset = html.StyleElement();
_styleReset.innerHtml = '''
:host {
all: initial;
cursor: inherit;
}''';
_shadowRoot.append(_styleReset);
final html.Element? platformView =
ui.platformViewRegistry.getCreatedView(viewId);
if (platformView != null) {
_shadowRoot.append(platformView);
} else {
printWarning('No platform view created for id $viewId');
}
return element;
}
@override
Matrix4? get localTransformInverse => null;
@override
void apply() {
rootElement!.style
..transform = 'translate(${dx}px, ${dy}px)'
..width = '${width}px'
..height = '${height}px';
// Set size of the root element created by the PlatformView.
final html.Element? platformView =
ui.platformViewRegistry.getCreatedView(viewId);
if (platformView != null) {
platformView.style
..width = '${width}px'
..height = '${height}px';
}
}
// Platform Views can only be updated if their viewId matches.
@override
bool canUpdateAsMatch(PersistedSurface oldSurface) {
if (super.canUpdateAsMatch(oldSurface)) {
// super checks the runtimeType of the surface, so we can just cast...
return viewId == ((oldSurface as PersistedPlatformView).viewId);
}
return false;
}
@override
double matchForUpdate(PersistedPlatformView existingSurface) {
return existingSurface.viewId == viewId ? 0.0 : 1.0;
}
@override
void update(PersistedPlatformView oldSurface) {
assert(
viewId == oldSurface.viewId,
'PersistedPlatformView with different viewId should never be updated. Check the canUpdateAsMatch method.',
);
super.update(oldSurface);
// Only update if the view has been resized
if (dx != oldSurface.dx ||
dy != oldSurface.dy ||
width != oldSurface.width ||
height != oldSurface.height) {
// A change in any of the dimensions is performed by calling apply.
apply();
}
}
}