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

Conversation

@knopp
Copy link
Member

@knopp knopp commented Jun 22, 2023

Fixes flutter/flutter#129085

Changes to FlutterMouseCursorPlugin

  • none cursor is not handled by hiding the cursor anymore. That was too big of a hammer as it also affects other views (and platform views). Instead empty cursor is created from empty NSImage.

  • Cursor plugin now notifies the engine when cursor has changed. The engine forwards the change to last FlutterView that handled mouse event. This is necessary because on occasion FlutterView needs to be able to restore cursor without framework being involved.

Preventing PlatformView from changing cursor when it is obscured by Flutter Content.

Generally in Cocoa cursor changes are done as response to mouseMoved event, which is driven by a NSTrackingArea. The issue here is that this is not affected by hit testing and tracking areas form a hierarchy parallel to view hierarchy and are not affected by being obscured by another view (or tracking area). This means that platform view will receive mouseMoved event even when is obscured by Flutter content. To work around this, the mutator view puts a tracking area above platform view, which means it gets the mouseMove event first, and when it decides that mouse is over Flutter content, it will prevent platform view from changing the cursor for the rest of RunLoop turn (see NSCursor+IgnoreChange).

Actual hit testing

This part is rather straightforward, the area where FlutterContent obscures mutator view is provided to the mutator view, which will return nil from hitTest: when the point is in the obscured area.

Example of hit testing

flutter-hit-test1.mov

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@knopp knopp force-pushed the macos_hit_testing branch 3 times, most recently from f6ab057 to 8c76f8b Compare June 23, 2023 06:56
@knopp knopp changed the title WIP: macOS: Implement hit testing and handle platform view cursor changes WIP: [macOS] Implement hit testing and handle platform view cursor changes Jun 25, 2023
@knopp knopp force-pushed the macos_hit_testing branch 4 times, most recently from cd17508 to 6b81cd5 Compare July 2, 2023 08:38
@chinmaygarde chinmaygarde changed the title WIP: [macOS] Implement hit testing and handle platform view cursor changes [macOS] Implement hit testing and handle platform view cursor changes Jul 6, 2023
@knopp knopp force-pushed the macos_hit_testing branch from 6b81cd5 to 0443432 Compare July 9, 2023 11:49
@chinmaygarde chinmaygarde removed their request for review July 13, 2023 20:04
@chinmaygarde
Copy link
Member

chinmaygarde commented Jul 13, 2023

Ping @cbracken. Perhaps @cyanglaz also has some context.

@cbracken cbracken requested a review from cyanglaz July 18, 2023 23:28
Copy link
Member

@cbracken cbracken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the embedder side changes right now, but a few comments on the pointer event/cursor side first.

Comment on lines 97 to 158
for (size_t j = i + 1; j < layers_count; j++) {
FlutterLayer* overlayLayer = (FlutterLayer*)layers[j];
if (overlayLayer->type == kFlutterLayerContentTypeBackingStore) {
auto present_info = overlayLayer->backing_store->present_info;
if (present_info != nullptr && present_info->paint_region != nullptr) {
for (size_t k = 0; k < present_info->paint_region->rects_count; k++) {
FlutterRect flutter_rect = present_info->paint_region->rects[k];
double scale = default_base_view.layer.contentsScale;
CGRect rect = CGRectMake(flutter_rect.left / scale, flutter_rect.top / scale,
(flutter_rect.right - flutter_rect.left) / scale,
(flutter_rect.bottom - flutter_rect.top) / scale);
CGRect intersection = CGRectIntersection(rect, mutator_view.frame);
if (!CGRectIsNull(intersection)) {
intersection.origin.x -= mutator_view.frame.origin.x;
intersection.origin.y -= mutator_view.frame.origin.y;
[mutator_view addHitTestIgnoreRegion:intersection];
}
}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider extracting this to its own method.

[self replaceSelector:@selector(set)
fromClass:[NSCursor class]
withSelector:@selector(_flutterSetCursorOverride)
fromClass:[NSCursor class]];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid swizzling in all code except for tests. If it's not in the style guide already, I'll add it -- we've had this conversation many times in code reviews (including in one of mine from back in 2016 or so when I tried to get rid of FlutterAppDelegate) and in the end we always end up making the same call -- avoid it.

We don't allow swizzling AppKit classes for a few reasons:

  • it can be a blocker for shipping on the App Store.
  • we shouldn't apply Flutter-specific logic to non-Flutter parts of the app -- in add-to-app scenarios, developers may have just a single Flutter view in a massive app.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swizzling in general does not prevent getting into AppStore. Using private / undocumented API does, which is not the case here. This also should not interfere with the rest of application, it just prevents changing cursor until the rest of RunLoop tick when Flutter content is over native view and already handled cursor change.

The application will be working without it, but with cursor flicker when moving over Flutter contents that have native view with active NSTrackingArea underneath (i.e. NSTextField).

if (flutterIgnoreCursorChange) {
return;
}
[self _flutterSetCursorOverride];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the sake of readability, at the very minimum this needs a comment pointing out that _flutterSetCursorOverride has been swizzled to use the original [NSCursor set] implementation and therefore this isn't an infinite loop. That said, see my comment on swizzling below.

@flutter-dashboard
Copy link

This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold.

@knopp knopp force-pushed the macos_hit_testing branch from 5f86374 to 8c2304d Compare September 1, 2023 17:37
@gspencergoog
Copy link
Contributor

@knopp Are you still planning on working on this? If not, could you either close it or mark it as draft so we can get it off the PR backlog? (Desktop Triage)

@cbracken
Copy link
Member

This is pending another round of review from me, but been stuck working on two internal customer issues, I'll try to get back to this soon. Apologies for the delay.

@gspencergoog gspencergoog marked this pull request as draft November 2, 2023 18:14
@gspencergoog
Copy link
Contributor

Converting this to Draft, as @cbracken is still looking at alternatives.

@goderbauer
Copy link
Member

Spoke to @cbracken and he says this is still on his radar.

@cyanglaz cyanglaz removed their request for review March 19, 2024 21:42
@knopp knopp force-pushed the macos_hit_testing branch from 6bc5add to eb819bd Compare April 7, 2024 19:05
if (present_info) {
for (size_t j = 0; j < present_info->paint_region->rects_count; j++) {
rects.push_back(present_info->paint_region->rects[j]);
}
Copy link
Member

@cbracken cbracken Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider pre-reserving size of rects, and using std::copy which might have better performance:

rects.reserve(present_info->paint_region->rects_count);
std::copy(present_info->paint_region->rects,
          present_info->paint_region->rects + present_info->paint_region->rects_count,
          std::back_inserter(rects));

Copy link
Member

@cbracken cbracken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM stamp from a Japanese personal seal

@knopp knopp merged commit 6280295 into flutter:main Apr 9, 2024
@knopp knopp deleted the macos_hit_testing branch April 9, 2024 10:00
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 9, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 9, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 9, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 9, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 9, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 9, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 9, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 9, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 9, 2024
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Apr 9, 2024
…146524)

flutter/engine@5a824e2...5dca50d

2024-04-09 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Delete engine v1 android embedding (#51229)" (flutter/engine#51996)
2024-04-09 [email protected] Delete engine v1 android embedding (flutter/engine#51229)
2024-04-09 [email protected] better output from engine layer unit test failures (flutter/engine#51975)
2024-04-09 [email protected] Revert "Roll Dart SDK from 78174b41ab0f to 7a5e410f982e (1 revision) (#51980)" (flutter/engine#51990)
2024-04-09 [email protected] [skwasm] Reify the SkPicture pointer as the right type. (flutter/engine#51991)
2024-04-09 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Roll Dart SDK from 7a5e410f982e to db99af14c4bc (1 revision) (#51986)" (flutter/engine#51989)
2024-04-09 [email protected] Move the Dart SDK to //flutter/third_party/dart (flutter/engine#51917)
2024-04-09 [email protected] [macOS] Implement hit testing and handle platform view cursor changes (flutter/engine#43101)
2024-04-09 [email protected] Roll Dart SDK from 7a5e410f982e to db99af14c4bc (1 revision) (flutter/engine#51986)
2024-04-09 [email protected] Roll Dart SDK from 78174b41ab0f to 7a5e410f982e (1 revision) (flutter/engine#51980)

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
knopp added a commit that referenced this pull request Apr 17, 2024
This fixes an edge case that I've overlooked in
#43101.

It is possible to configure `FlutterViewController` tracking area with
`FlutterMouseTrackingModeAlways` option, in which case the tracking area
will call `[FlutterView cursorUpdate:]` unconditionally even if the
mouse cursor is over platform view and the platform view has already
handled the mouse update.

The solution is to prevent the `FlutterView` from updating the cursor
when the cursor is over a platform view. This can be accomplished by
doing a hitTest inside `[FlutterView cursorUpdate:]`.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I added new tests to check the change I am making or feature I am
adding, or the PR is [test-exempt]. See [testing the engine] for
instructions on writing and running engine tests.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I signed the [CLA].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[C++, Objective-C, Java style guides]:
https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
[testing the engine]:
https://github.com/flutter/flutter/wiki/Testing-the-engine
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
gilnobrega pushed a commit to gilnobrega/flutter that referenced this pull request Apr 22, 2024
…lutter#146524)

flutter/engine@5a824e2...5dca50d

2024-04-09 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Delete engine v1 android embedding (flutter#51229)" (flutter/engine#51996)
2024-04-09 [email protected] Delete engine v1 android embedding (flutter/engine#51229)
2024-04-09 [email protected] better output from engine layer unit test failures (flutter/engine#51975)
2024-04-09 [email protected] Revert "Roll Dart SDK from 78174b41ab0f to 7a5e410f982e (1 revision) (flutter#51980)" (flutter/engine#51990)
2024-04-09 [email protected] [skwasm] Reify the SkPicture pointer as the right type. (flutter/engine#51991)
2024-04-09 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Roll Dart SDK from 7a5e410f982e to db99af14c4bc (1 revision) (flutter#51986)" (flutter/engine#51989)
2024-04-09 [email protected] Move the Dart SDK to //flutter/third_party/dart (flutter/engine#51917)
2024-04-09 [email protected] [macOS] Implement hit testing and handle platform view cursor changes (flutter/engine#43101)
2024-04-09 [email protected] Roll Dart SDK from 7a5e410f982e to db99af14c4bc (1 revision) (flutter/engine#51986)
2024-04-09 [email protected] Roll Dart SDK from 78174b41ab0f to 7a5e410f982e (1 revision) (flutter/engine#51980)

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
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[macOS] Platform views should support hit testing

5 participants