-
Notifications
You must be signed in to change notification settings - Fork 29.7k
[DisplayList] DlPath supports generic path dispatching #164753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Done. There were only 2 which seemed odd. I just went and looked at all of the code that handles clip mutators and noticed that most platforms either NOP a path clip or they just get the bounds and treat it like a clipRect. Well, at least now they have a simpler interface to deal with when we decide to add path support to the other platforms. |
engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc
Outdated
Show resolved
Hide resolved
engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
Outdated
Show resolved
Hide resolved
gaaclarke
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.
I looked over the dispatching stuff, LGTM. I didn't do a full review since other people were looking at it before me. There isn't a test so this is just a refactor?
Pretty much a refactor, and well covered by other tests, but it does introduce a new public method so there probably should be tests. I'll work on some. |
|
Unit tests now added |
|
This PR should be in its final state now. |
gaaclarke
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.
Okay I gave it a complete look. I have 2 suggestions which you are free to ignore and one that should get fixed, the argument comments are in the wrong format.
| FML_DCHECK(contour != nullptr); | ||
| if (subpath_needs_close) { | ||
| sk_path.close(); | ||
| receiver.Close(); |
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.
No action required: It's not in the c++ style guide but when calling virtual methods it's safer to use -> since if you accidentally get a value instead of a reference you'll get incorrect behavior.
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.
How? -> doesn't even compile.
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.
You have to switch from using references to using pointers.
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.
That would add the burden of implicitly accepting null values which must be checked. I don't understand the "value vs reference" issue and the incorrect behavior it leads to.
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.
When you have a reference in C++ it isn't guaranteed to not be null. You still technically have to consider null values, we just are ignoring that.
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.
That's a big TIL. I see so many comments here and there that references cannot ever be null, but I'm guessing you can fudge it with *pointer_that_is_null?
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.
Perhaps clang-tidy might complain (if it is run)?
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.
but I'm guessing you can fudge it with *pointer_that_is_null?
Yep, exactly and we do this in our codebase all the time. A linter that disallowed references to anything on the heap would be nice, I don't think it exists. That's how I personally use them.
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'll file this under "wishing C++ would throw if you create a reference by dereferencing a nulllptr".
| const DlScalar weight; | ||
| }; | ||
|
|
||
| class TestPathReceiver : public DlPathReceiver { |
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.
no action required: This class should just be a gmock.
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 took a quick look at gmock just now, but it seems focused on just asserting that methods are called whereas this class is checking the data they are called with.
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.
There are hundreds of examples of using gmock to check the arguments of function calls in our codebase. Here is one example:
Line 288 in b16430b
| EXPECT_CALL(*surface_mock, AcquireFrame(frame_size)) |
This is asserting that AcquireFrame with arguments that equal frame_size.
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 understand the formatting used there, it looks like it is placing expectations on return values, but my methods are all void and I'm placing expectations on the data they receive. Again, maybe that's in there, but I'd need to study gmock further - likely worth the work.
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 this one is easier to see:
flutter/engine/src/flutter/impeller/renderer/backend/gles/unique_handle_gles_unittests.cc
Line 29 in b16430b
| EXPECT_CALL(*mock_gles_impl, GenTextures(1, _)).Times(1); |
This is asserting that GenTextures is being called with 2 arguments, the first one must be 1 the second can be anything ("_" is a wildcard matcher).
I think this would be a good opportunity to learn how to use gmock. It's a very useful skill and I'm happy to help.
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.
There are so many similar classes I've written in the unit tests, time to look into that mechanism.
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.
TIL-gmock. The tests are slightly more wordy, but the intent is outlined in the test itself and the mock receiver class was 100x simpler than the tester harness class.
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.
See also #165336
This PR adds `Path.addRSuperellipse` to `dart:ui`. This is needed to implement a parity class to `RoundedRectangleBorder` as discussed [here](#164857 (comment)). <details> <summary> Obsolete description, no longer applicable </summary> I want to reuse the existing algorithm created for impeller stroking. The existing algorithm is moved from `path_builder.cc` to `round_superellipse_param.cc`, and a delegated is added so that the same algorithm can output for different path classes. I'm not 100% sure this is _the_ best way to implement this, but I've tried some methods in vain. * `DlPathReceiver` added in #164753 sounds like a similar concept as the delegate created in this PR. I tried to use that but not only are the methods private, they're neither in an accessible directory. * I also thought of converting an impeller `Path` to a skia path, but it seems that the impeller path isn't designed to be traversed. * Another possibility is that we refactor impeller stroking to be based on the triangles instead of path, a direction we agreed to eventually move toward, which allows avoiding code share at all. I've briefly read the code in `StrokePathGeometry` and have some ideas but also something uncertain, so I didn't choose this path for now. </details> ## 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], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] 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/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This PR adds `Path.addRSuperellipse` to `dart:ui`. This is needed to implement a parity class to `RoundedRectangleBorder` as discussed [here](flutter#164857 (comment)). <details> <summary> Obsolete description, no longer applicable </summary> I want to reuse the existing algorithm created for impeller stroking. The existing algorithm is moved from `path_builder.cc` to `round_superellipse_param.cc`, and a delegated is added so that the same algorithm can output for different path classes. I'm not 100% sure this is _the_ best way to implement this, but I've tried some methods in vain. * `DlPathReceiver` added in flutter#164753 sounds like a similar concept as the delegate created in this PR. I tried to use that but not only are the methods private, they're neither in an accessible directory. * I also thought of converting an impeller `Path` to a skia path, but it seems that the impeller path isn't designed to be traversed. * Another possibility is that we refactor impeller stroking to be based on the triangles instead of path, a direction we agreed to eventually move toward, which allows avoiding code share at all. I've briefly read the code in `StrokePathGeometry` and have some ideas but also something uncertain, so I didn't choose this path for now. </details> ## 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], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] 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/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
There are different ways to iterate over an SkPath or an impeller::Path and various points in the engine source tree we have boilerplate duplicates of this code to transfer the contents of the DlPath wrapper object into some platform-specific path. This PR adds a dispatch/receiver mechanism to read back the contents of a DlPath - independent of whether it is backed by an SkPath or an impeller::Path - in a simpler form that avoids potential mistakes in the various conversion methods. See DlPathReceiver and DlPath::Dispatch in the dl_path.h file
This PR adds `Path.addRSuperellipse` to `dart:ui`. This is needed to implement a parity class to `RoundedRectangleBorder` as discussed [here](flutter#164857 (comment)). <details> <summary> Obsolete description, no longer applicable </summary> I want to reuse the existing algorithm created for impeller stroking. The existing algorithm is moved from `path_builder.cc` to `round_superellipse_param.cc`, and a delegated is added so that the same algorithm can output for different path classes. I'm not 100% sure this is _the_ best way to implement this, but I've tried some methods in vain. * `DlPathReceiver` added in flutter#164753 sounds like a similar concept as the delegate created in this PR. I tried to use that but not only are the methods private, they're neither in an accessible directory. * I also thought of converting an impeller `Path` to a skia path, but it seems that the impeller path isn't designed to be traversed. * Another possibility is that we refactor impeller stroking to be based on the triangles instead of path, a direction we agreed to eventually move toward, which allows avoiding code share at all. I've briefly read the code in `StrokePathGeometry` and have some ideas but also something uncertain, so I didn't choose this path for now. </details> ## 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], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] 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/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
There are different ways to iterate over an SkPath or an impeller::Path and various points in the engine source tree we have boilerplate duplicates of this code to transfer the contents of the DlPath wrapper object into some platform-specific path. This PR adds a dispatch/receiver mechanism to read back the contents of a DlPath - independent of whether it is backed by an SkPath or an impeller::Path - in a simpler form that avoids potential mistakes in the various conversion methods.
See DlPathReceiver and DlPath::Dispatch in the dl_path.h file