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

Commit a48eedb

Browse files
authored
Revert "[web] Move text editing nodes outside of shadowDOM" (#40847)
Reverts #39688 Looks like this is causing the roll to the framework to fail. See https://ci.chromium.org/ui/p/flutter/builders/try/Linux%20web_long_running_tests_4_5/34083/overview ``` 00:03 �[32m+1�[0m�[31m -1�[0m: Hello World App enable accessibility �[1m�[31m[E]�[0m�[0m JavaScriptException (500): javascript error: Cannot read properties of null (reading 'querySelector') (Session info: headless chrome=96.0.4664.0) package:webdriver/src/handler/w3c/utils.dart 57:9 parseW3cResponse package:webdriver/src/handler/w3c/core.dart 59:19 W3cCoreHandler.parseExecuteResponse package:webdriver/src/async/web_driver.dart 260:37 WebDriver.execute.<fn> package:webdriver/src/common/request_client.dart 96:32 AsyncRequestClient.send ===== asynchronous gap =========================== test_driver/smoke_web_engine_test.dart 41:40 main.<fn>.<fn> ===== asynchronous gap =========================== package:test_api/src/backend/declarer.dart 215:9 Declarer.test.<fn>.<fn> ===== asynchronous gap =========================== package:test_api/src/backend/declarer.dart 213:7 Declarer.test.<fn> ===== asynchronous gap =========================== package:test_api/src/backend/invoker.dart 258:9 Invoker._waitForOutstandingCallbacks.<fn> 00:03 �[32m+1�[0m�[31m -1�[0m: Hello World App (tearDownAll)�[0m ```
1 parent b1ba58f commit a48eedb

File tree

12 files changed

+165
-192
lines changed

12 files changed

+165
-192
lines changed

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

+12-39
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,6 @@ class FlutterViewEmbedder {
124124
HostNode get glassPaneShadow => _glassPaneShadow;
125125
late HostNode _glassPaneShadow;
126126

127-
DomElement get textEditingHostNode => _textEditingHostNode;
128-
late DomElement _textEditingHostNode;
129-
130127
static const String defaultFontStyle = 'normal';
131128
static const String defaultFontWeight = 'normal';
132129
static const double defaultFontSize = 14;
@@ -171,9 +168,6 @@ class FlutterViewEmbedder {
171168
);
172169
_glassPaneShadow = glassPaneElementHostNode;
173170

174-
_textEditingHostNode =
175-
createTextEditingHostNode(glassPaneElement, defaultCssFont);
176-
177171
// Don't allow the scene to receive pointer events.
178172
_sceneHostElement = domDocument.createElement('flt-scene-host')
179173
..style.pointerEvents = 'none';
@@ -195,19 +189,19 @@ class FlutterViewEmbedder {
195189
glassPaneElementHostNode.appendAll(<DomNode>[
196190
accessibilityPlaceholder,
197191
_sceneHostElement!,
198-
]);
199192

200-
// The semantic host goes last because hit-test order-wise it must be
201-
// first. If semantics goes under the scene host, platform views will
202-
// obscure semantic elements.
203-
//
204-
// You may be wondering: wouldn't semantics obscure platform views and
205-
// make then not accessible? At least with some careful planning, that
206-
// should not be the case. The semantics tree makes all of its non-leaf
207-
// elements transparent. This way, if a platform view appears among other
208-
// interactive Flutter widgets, as long as those widgets do not intersect
209-
// with the platform view, the platform view will be reachable.
210-
glassPaneElement.appendChild(semanticsHostElement);
193+
// The semantic host goes last because hit-test order-wise it must be
194+
// first. If semantics goes under the scene host, platform views will
195+
// obscure semantic elements.
196+
//
197+
// You may be wondering: wouldn't semantics obscure platform views and
198+
// make then not accessible? At least with some careful planning, that
199+
// should not be the case. The semantics tree makes all of its non-leaf
200+
// elements transparent. This way, if a platform view appears among other
201+
// interactive Flutter widgets, as long as those widgets do not intersect
202+
// with the platform view, the platform view will be reachable.
203+
semanticsHostElement,
204+
]);
211205

212206
// When debugging semantics, make the scene semi-transparent so that the
213207
// semantics tree is more prominent.
@@ -399,24 +393,3 @@ FlutterViewEmbedder? _flutterViewEmbedder;
399393
FlutterViewEmbedder ensureFlutterViewEmbedderInitialized() =>
400394
_flutterViewEmbedder ??=
401395
FlutterViewEmbedder(hostElement: configuration.hostElement);
402-
403-
/// Creates a node to host text editing elements and applies a stylesheet
404-
/// to Flutter nodes that exist outside of the shadowDOM.
405-
DomElement createTextEditingHostNode(DomElement root, String defaultFont) {
406-
final DomElement domElement =
407-
domDocument.createElement('flt-text-editing-host');
408-
final DomHTMLStyleElement styleElement = createDomHTMLStyleElement();
409-
410-
styleElement.id = 'flt-text-editing-stylesheet';
411-
root.appendChild(styleElement);
412-
applyGlobalCssRulesToSheet(
413-
styleElement.sheet! as DomCSSStyleSheet,
414-
hasAutofillOverlay: browserHasAutofillOverlay(),
415-
cssSelectorPrefix: FlutterViewEmbedder.glassPaneTagName,
416-
defaultCssFont: defaultFont,
417-
);
418-
419-
root.appendChild(domElement);
420-
421-
return domElement;
422-
}

lib/web_ui/lib/src/engine/host_node.dart

+5-12
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ abstract class HostNode {
9494
/// See:
9595
/// * [Document.querySelectorAll](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll)
9696
Iterable<DomElement> querySelectorAll(String selectors);
97-
98-
DomElement get renderHost;
9997
}
10098

10199
/// A [HostNode] implementation, backed by a [DomShadowRoot].
@@ -112,10 +110,11 @@ class ShadowDomHostNode implements HostNode {
112110
/// This also calls [applyGlobalCssRulesToSheet], with the [defaultFont]
113111
/// to be used as the default font definition.
114112
ShadowDomHostNode(DomElement root, String defaultFont)
115-
: assert(root.isConnected ?? true,
116-
'The `root` of a ShadowDomHostNode must be connected to the Document object or a ShadowRoot.') {
117-
root.appendChild(renderHost);
118-
_shadow = renderHost.attachShadow(<String, dynamic>{
113+
: assert(
114+
root.isConnected ?? true,
115+
'The `root` of a ShadowDomHostNode must be connected to the Document object or a ShadowRoot.'
116+
) {
117+
_shadow = root.attachShadow(<String, dynamic>{
119118
'mode': 'open',
120119
// This needs to stay false to prevent issues like this:
121120
// - https://github.com/flutter/flutter/issues/85759
@@ -136,9 +135,6 @@ class ShadowDomHostNode implements HostNode {
136135

137136
late DomShadowRoot _shadow;
138137

139-
@override
140-
final DomElement renderHost = domDocument.createElement('flt-render-host');
141-
142138
@override
143139
DomElement? get activeElement => _shadow.activeElement;
144140

@@ -195,9 +191,6 @@ class ElementHostNode implements HostNode {
195191

196192
late DomElement _element;
197193

198-
@override
199-
final DomElement renderHost = domDocument.createElement('flt-render-host');
200-
201194
@override
202195
DomElement? get activeElement => _element.ownerDocument?.activeElement;
203196

lib/web_ui/lib/src/engine/platform_dispatcher.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
587587
_platformViewMessageHandler ??= PlatformViewMessageHandler(
588588
contentManager: platformViewManager,
589589
contentHandler: (DomElement content) {
590-
flutterViewEmbedder.glassPaneShadow.renderHost.append(content);
590+
flutterViewEmbedder.glassPaneElement.append(content);
591591
},
592592
);
593593
_platformViewMessageHandler!.handlePlatformViewCall(data, callback!);

lib/web_ui/lib/src/engine/platform_views/content_manager.dart

+1-2
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,8 @@ class PlatformViewManager {
128128
}
129129

130130
_ensureContentCorrectlySized(content, viewType);
131-
wrapper.append(content);
132131

133-
return wrapper;
132+
return wrapper..append(content);
134133
});
135134
}
136135

lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart

+6-8
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,20 @@ import '../semantics.dart' show EngineSemanticsOwner;
1919
/// It also takes into account semantics being enabled to fix the case where
2020
/// offsetX, offsetY == 0 (TalkBack events).
2121
ui.Offset computeEventOffsetToTarget(DomMouseEvent event, DomElement actualTarget) {
22+
// On top of a platform view
23+
if (event.target != actualTarget) {
24+
return _computeOffsetOnPlatformView(event, actualTarget);
25+
}
2226
// On a TalkBack event
2327
if (EngineSemanticsOwner.instance.semanticsEnabled && event.offsetX == 0 && event.offsetY == 0) {
2428
return _computeOffsetForTalkbackEvent(event, actualTarget);
2529
}
26-
27-
final bool isTargetOutsideOfShadowDOM = event.target != actualTarget;
28-
if (isTargetOutsideOfShadowDOM) {
29-
return _computeOffsetRelativeToActualTarget(event, actualTarget);
30-
}
3130
// Return the offsetX/Y in the normal case.
3231
// (This works with 3D translations of the parent element.)
3332
return ui.Offset(event.offsetX, event.offsetY);
3433
}
3534

36-
/// Computes the event offset when hovering over any nodes that don't exist in
37-
/// the shadowDOM such as platform views or text editing nodes.
35+
/// Computes the event offset when hovering over a platformView.
3836
///
3937
/// This still uses offsetX/Y, but adds the offset from the top/left corner of the
4038
/// platform view to the glass pane (`actualTarget`).
@@ -59,7 +57,7 @@ ui.Offset computeEventOffsetToTarget(DomMouseEvent event, DomElement actualTarge
5957
///
6058
/// Event offset relative to FlutterView = (offsetX + xP, offsetY + yP)
6159
// TODO(dit): Make this understand 3D transforms, https://github.com/flutter/flutter/issues/117091
62-
ui.Offset _computeOffsetRelativeToActualTarget(DomMouseEvent event, DomElement actualTarget) {
60+
ui.Offset _computeOffsetOnPlatformView(DomMouseEvent event, DomElement actualTarget) {
6361
final DomElement target = event.target! as DomElement;
6462
final DomRect targetRect = target.getBoundingClientRect();
6563
final DomRect actualTargetRect = actualTarget.getBoundingClientRect();

lib/web_ui/lib/src/engine/semantics/text_field.dart

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:ui/ui.dart' as ui;
77

88
import '../browser_detection.dart';
99
import '../dom.dart';
10+
import '../embedder.dart';
1011
import '../platform_dispatcher.dart';
1112
import '../safe_browser_api.dart';
1213
import '../text_editing/text_editing.dart';
@@ -421,14 +422,14 @@ class TextField extends RoleManager {
421422
..height = '${semanticsObject.rect!.height}px';
422423

423424
if (semanticsObject.hasFocus) {
424-
if (domDocument.activeElement !=
425+
if (flutterViewEmbedder.glassPaneShadow.activeElement !=
425426
activeEditableElement) {
426427
semanticsObject.owner.addOneTimePostUpdateCallback(() {
427428
activeEditableElement.focus();
428429
});
429430
}
430431
SemanticsTextEditingStrategy._instance?.activate(this);
431-
} else if (domDocument.activeElement ==
432+
} else if (flutterViewEmbedder.glassPaneShadow.activeElement ==
432433
activeEditableElement) {
433434
if (!isIosSafari) {
434435
SemanticsTextEditingStrategy._instance?.deactivate(this);

lib/web_ui/lib/src/engine/text_editing/text_editing.dart

+1-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ void _emptyCallback(dynamic _) {}
5151

5252
/// The default [HostNode] that hosts all DOM required for text editing when a11y is not enabled.
5353
@visibleForTesting
54-
DomElement get defaultTextEditingRoot =>
55-
flutterViewEmbedder.textEditingHostNode;
54+
HostNode get defaultTextEditingRoot => flutterViewEmbedder.glassPaneShadow;
5655

5756
/// These style attributes are constant throughout the life time of an input
5857
/// element.

lib/web_ui/test/engine/host_node_test.dart

+4-5
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,19 @@ void testMain() {
1616

1717
group('ShadowDomHostNode', () {
1818
final HostNode hostNode = ShadowDomHostNode(rootNode, '14px monospace');
19-
final DomElement renderHost = domDocument.querySelector('flt-render-host')!;
2019

2120
test('Initializes and attaches a shadow root', () {
2221
expect(domInstanceOfString(hostNode.node, 'ShadowRoot'), isTrue);
23-
expect((hostNode.node as DomShadowRoot).host, renderHost);
24-
expect(hostNode.node, renderHost.shadowRoot);
22+
expect((hostNode.node as DomShadowRoot).host, rootNode);
23+
expect(hostNode.node, rootNode.shadowRoot);
2524

2625
// The shadow root should be initialized with correct parameters.
27-
expect(renderHost.shadowRoot!.mode, 'open');
26+
expect(rootNode.shadowRoot!.mode, 'open');
2827
if (browserEngine != BrowserEngine.firefox &&
2928
browserEngine != BrowserEngine.webkit) {
3029
// Older versions of Safari and Firefox don't support this flag yet.
3130
// See: https://caniuse.com/mdn-api_shadowroot_delegatesfocus
32-
expect(renderHost.shadowRoot!.delegatesFocus, isFalse);
31+
expect(rootNode.shadowRoot!.delegatesFocus, isFalse);
3332
}
3433
});
3534

0 commit comments

Comments
 (0)