-
Notifications
You must be signed in to change notification settings - Fork 6k
[web] PointerBinding per view #48248
Conversation
252b4df to
df9bbd8
Compare
df9bbd8 to
bc10542
Compare
bc10542 to
7281436
Compare
|
|
||
| DomElement get _viewTarget => _view.dom.rootElement; | ||
| DomEventTarget get _globalTarget { | ||
| // When the Flutter app owns the full page, we want to listen on window for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't returning thew view target implictily covering this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. The root element is always a <flutter-view> element that we insert somewhere. But in the implicitView case, we want this to return window.
ditman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! I had a bunch of comments here and there, but I don't think they're blocking! (I hope! :P)
| _detector = detector { | ||
| if (isIosSafari) { | ||
| SafariPointerEventWorkaround.instance.workAroundMissingPointerEvents(); | ||
| _safariWorkaround = safariWorkaround ?? SafariPointerEventWorkaround(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this Safari workaround could be a singleton? It only needs to be applied once into the document, and not on every view, right?
(The only thing it's doing is adding an empty listener to document.ontouchstart it seems?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the "default" workaround instance a static member on PointerBinding (so we only ever create one). And the instance only attaches the event listener once (even it gets called multiple times).
| KeyboardBinding.initInstance(); | ||
| PointerBinding.initInstance( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So little stuff remaining in this reset function!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I can't wait to get rid of it!
| /// Resets global pointer state that's not tied to any single [PointerBinding] | ||
| /// instance. | ||
| static void resetGlobalState() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot find any prod code calling this, so I'm assuming it's only for tests?
Can this be called debugResetGlobalState (or indicate that this is for tests in any other way, with @visibleForTesting or documentation?)
| if (_view == EnginePlatformDispatcher.instance.implicitView) { | ||
| return domWindow; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe have an eventsTarget getter on the view that returns the proper object? The embedding strategy for "full page" already has a bunch of domDocument hardcoded in certain places, it could return a domWindow very easily.
Also: do you think we could migrate the "embedded" mode to use the rootElement as its target in this PR as well? That way we'd only have two cases:
- embedded element -> rootElement
- whole window -> domWindow
Rather than distinguishing them by being an "implicitView" or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the change but I'm not sure if I captured exactly what you wanted. Please see 1de6ab9
| // Why `domWindow` you ask? See this fiddle: https://jsfiddle.net/ditman/7towxaqp | ||
| _addPointerEventListener(domWindow, 'pointermove', (DomPointerEvent event) { | ||
| _addPointerEventListener(_globalTarget, 'pointermove', (DomPointerEvent event) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Rant) I wonder if the solution to all this "listening to global events craze" is to have:
- A per-view listener that is targeted to the view itself for normal mouse moves
- A global listener on window that we can tap from as needed in special cases (when the mouse leaves the window, etc...)
That way we might simplify the general case of pointer handling :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do need to figure this out at some point, yes. For example, do we care about hover events happening outside flutter views? What if the pointer is down and moves outside of the view? etc.
| assert(() { | ||
| registerHotRestartListener(reset); | ||
| return true; | ||
| }()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we landing in the following pattern:
resetfor hot restart + testsdisposefor actual code paths that could happen at runtime?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I think about these is reset means the instance is back to its original state and can be used further. OTOH, dispose means the object cleaned after itself and can't be used anymore.
| assert(_pointers.containsKey(device)); | ||
| final _PointerState state = _pointers[device]!; | ||
| assert(globalPointerState.pointers.containsKey(device)); | ||
| final _PointerDeviceState state = globalPointerState.pointers[device]!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind globalPointerState being a global, but it could be modeled as a property of a PointerDevice object and do:
_PointerDeviceState state = pointerDevices[deviceId].state!;But since we don't care about anything else of the pointerDevice -> ship it like this!
| // Remove <body> margins to avoid messing up with all the test coordinates. | ||
| domDocument.body!.style.margin = '0'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we didn't need this before because the (full-screen) implicitView has this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly! The full page embedding strategy was doing this for us.
…139936) flutter/engine@5587d26...4c30919 2023-12-11 [email protected] [web] PointerBinding per view (flutter/engine#48248) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
PointerBinding/KeyboardBindingout ofFlutterViewEmbedder.computeEventOffsetToTargetproperly handles events within a given view.PointerBindingoperates on the given Flutter view (it still listens to somedomWindowevents for the implicit view).ui.window,KeyboardBinding.instance,SafariPointerEventWorkaround.instance, etc.pointer_binding_test.dartdoesn't use globals either.clickDebounceris now a static property onPointerBinding.Fixes flutter/flutter#137289