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

Add Platform View Manager to Windows shell #50598

Merged
merged 29 commits into from
Feb 26, 2024

Conversation

yaakovschectman
Copy link
Contributor

Create a manager for platform views accessible to the compositor, handle the methods that the framework will send.

Addresses flutter/flutter#143375

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 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.

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.

Thanks for sending this out! A few initial comments, mostly just on the docs side of things; I haven't given the implementation a pass other than one test.


namespace flutter {

enum class FocusChangeDirection { kProgrammatic, kForward, kBackward };
Copy link
Member

Choose a reason for hiding this comment

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

Add doc comments to document the enum and each value.

virtual ~PlatformViewManager();

virtual void QueuePlatformViewCreation(std::string_view type_name,
int64_t id);
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 a using PlatformViewId = int64_t; for clarity in both the API and any local variable declarations.

@@ -203,6 +203,28 @@ FLUTTER_EXPORT void FlutterDesktopEngineSetNextFrameCallback(
VoidCallback callback,
void* user_data);

typedef struct {
size_t cb_size;
Copy link
Member

Choose a reason for hiding this comment

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

Here and below, use struct_size for consistency with existing code.

@@ -203,6 +203,28 @@ FLUTTER_EXPORT void FlutterDesktopEngineSetNextFrameCallback(
VoidCallback callback,
void* user_data);

typedef struct {
Copy link
Member

Choose a reason for hiding this comment

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

Document this struct and its fields.

For the user_data field in particular, we always state that it's arbitrary user data that is opaque to the embedder, but it's often worth documenting what we typically expect the user to pass, where there is a reasonable "typical" value.

HWND parent_window;
const char* platform_view_type;
void* user_data;
int64_t platform_view_id;
Copy link
Member

Choose a reason for hiding this comment

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

I know we don't do it on other platforms (yet), but I think we should consider extracting a typedef for PlatformView IDs for the same reason as mentioned for our internal APIs.

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.

A few more minor notes.

@@ -32,6 +35,9 @@ class Compositor {

// Present Flutter content and platform views onto the view.
virtual bool Present(const FlutterLayer** layers, size_t layers_count) = 0;

protected:
PlatformViewManager* platform_view_manager_;
Copy link
Member

Choose a reason for hiding this comment

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

Consider documenting that this is a weak pointer, and that the PlatformViewManager is owned by FlutterEngine.

Copy link
Member

@loic-sharma loic-sharma Feb 13, 2024

Choose a reason for hiding this comment

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

Should we make this be a std::shared_ptr to avoid raw pointers? We're not creating tons of these objects so the performance impact should be acceptable.

FocusChangeDirection direction,
bool focus);

std::optional<HWND> GetNativeHandleForId(int64_t id) const;
Copy link
Member

Choose a reason for hiding this comment

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

What are we gaining by using a std::optional here over just returning nullptr, since HWND is already a pointer type? In both cases, the caller is left with:

auto platform_view = GetNativeHandleForId(pvid);
if (platform_view) {
  ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just an indicator that this may return null when the id is bad. We can return just HWND and state this in a comment instead.

private:
std::unique_ptr<MethodChannel<EncodableValue>> channel_;

std::map<std::string, FlutterPlatformViewTypeEntry> platform_view_types_;
Copy link
Member

Choose a reason for hiding this comment

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

Here and below, unless ordering is required, prefer std::unordered_map. I realise we're pretty inconsistent in existing code about this.


std::map<int64_t, std::function<HWND()>> pending_platform_views_;

TaskRunner* task_runner_;
Copy link
Member

Choose a reason for hiding this comment

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

Add a comment on ownership.

@@ -19,6 +21,7 @@ namespace flutter {
// Platform views are not yet supported.
class Compositor {
public:
Compositor(PlatformViewManager* manager) : platform_view_manager_(manager) {}
Copy link
Member

@loic-sharma loic-sharma Feb 13, 2024

Choose a reason for hiding this comment

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

Compositor is just an interface that knows nothing about the implementation. I'd remove the platform_view_manager_ field from this type and move it to the software & opengl compositors.

... but since these compositors don't use this platform view manager yet, I wouldn't update them to accept this platform view manager yet.

// for the implementation of the encoding and magic number identifiers.
final List<int> data = <int>[
// Method name
7, 'create'.length, ...utf8.encode('create'),
Copy link
Member

Choose a reason for hiding this comment

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

For readability, could we create constants for these? Something like:

const int valueNull = 0;
const int valueInt32 = 3;
const int valueString = 7;
const int valueMap = 13;

Copy link
Member

@cbracken cbracken Feb 14, 2024

Choose a reason for hiding this comment

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

I like it. Even better:

enum class ValueType {
  kNull = 0,
  kInt32 = 3,
  ...
};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cbracken I think this appears applicable only for C++ code. For the dart file, the const ints may be the best we can do.

Copy link
Member

Choose a reason for hiding this comment

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

Agh yes, not sure where my mind was at there. Dart enhanced enums do provide a mechanism for this, but it's entirely up to you.

yaakovschectman and others added 2 commits February 16, 2024 16:53
Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com>
@@ -1169,5 +1170,30 @@ TEST_F(FlutterWindowsEngineTest, ChannelListenedTo) {
}
}

TEST_F(FlutterWindowsEngineTest, ReceivePlatformViewMessage) {
Copy link
Member

Choose a reason for hiding this comment

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

From my understanding, this file is more for engine unit tests. Since this launches & runs a full app, should we move this to the integration tests in flutter_windows_unittests.cc?

I don't feel strongly about this, feel free to keep as is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems to me that this test is quite similar in most regards to the handful of unit tests immediately preceding it in this file. Would you disagree?

Copy link
Member

Choose a reason for hiding this comment

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

I think it's probably fine to land as-is, but I do think we should probably do a followup evaluation of which tests belong where. We're definitely not super consistent and to be honest, I'm not sure we've ever drawn a really clear line (not just in the Windows embedder but also on macOS).

@loic-sharma
Copy link
Member

This is looking really close to landing! I left a few nitpicks, but the only one I really care about is this one: #50598 (comment). Let me know if you'd want to chat about that!

yaakovschectman and others added 7 commits February 21, 2024 14:51
Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com>
Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com>
Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com>
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.

This lgtm -- nice work! I also really like that we now have a mechanism for staging future changes to the API we expose to the runner on Windows.

LGTM stamp from a Japanese personal seal

Copy link
Member

@loic-sharma loic-sharma left a comment

Choose a reason for hiding this comment

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

Excellent work!!! 🎉

@pragma('vm:entry-point')
void sendCreatePlatformViewMethod() async {
// The platform view method channel uses the standard method codec.
// See https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/services/message_codecs.dart#L262
Copy link
Member

Choose a reason for hiding this comment

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

I would use a permalink here. The line number will be wrong as the code continues to evolve

@yaakovschectman yaakovschectman merged commit 34a8b9b into flutter:main Feb 26, 2024
@yaakovschectman yaakovschectman deleted the win_pv_i branch February 26, 2024 15:13
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 26, 2024
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Feb 26, 2024
…144147)

flutter/engine@7a573c2...34a8b9b

2024-02-26 109111084+yaakovschectman@users.noreply.github.com Add Platform View Manager to Windows shell (flutter/engine#50598)

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 jimgraham@google.com,rmistry@google.com,zra@google.com 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
auto-submit bot pushed a commit that referenced this pull request Feb 27, 2024
_This is the same pull request as #50898. GitHub broke on the previous pull request so I re-created it_

This moves the logic to handle `flutter/accessibility` messages to a new type, `AccessibilityPlugin`. 

Notable changes:

1. Windows app no longer crashes if it receives accessibility events it does not support
2. Windows app no longer crashes if it receives accessibility events while in headless mode

@yaakovschectman After playing around with this, I ended up using a different pattern than what what I suggested on #50598 (comment). This message handler is simple enough that splitting into a child/base types felt like unnecessary boilerplate. The key thing is separating messaging and implementation logic, which was achieved through the `SetUp` method. Let me know what you think, and sorry for all my flip-flopping on this topic! �

This is preparation for: flutter/flutter#143765

Sample app for manual testing: flutter/flutter#113059

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants