Skip to content

Conversation

@flar
Copy link
Contributor

@flar flar commented Mar 7, 2025

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

@github-actions github-actions bot added engine flutter/engine related. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels Mar 7, 2025
@flar flar marked this pull request as ready for review March 7, 2025 07:40
@flar flar requested a review from jonahwilliams March 7, 2025 07:40
@flar
Copy link
Contributor Author

flar commented Mar 7, 2025

I still have to change all of the path conversion methods sprinkled here and there to use the new mechanism.

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.

@github-actions github-actions bot added platform-android Android applications specifically platform-ios iOS applications specifically team-ios Owned by iOS platform team labels Mar 7, 2025
Copy link
Member

@gaaclarke gaaclarke left a 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?

@flar
Copy link
Contributor Author

flar commented Mar 8, 2025

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.

@flar
Copy link
Contributor Author

flar commented Mar 8, 2025

Unit tests now added

@flar
Copy link
Contributor Author

flar commented Mar 8, 2025

This PR should be in its final state now.

Copy link
Member

@gaaclarke gaaclarke left a 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();
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

@gaaclarke gaaclarke Mar 10, 2025

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.

Copy link
Contributor Author

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?

Copy link
Contributor Author

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)?

Copy link
Member

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.

Copy link
Contributor Author

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 {
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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:

This is asserting that AcquireFrame with arguments that equal frame_size.

Copy link
Contributor Author

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.

Copy link
Member

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:

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.

Copy link
Contributor Author

@flar flar Mar 10, 2025

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See also #165336

engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 27, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 27, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 28, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 28, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 28, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 28, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 29, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 29, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 30, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 30, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Mar 31, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Apr 1, 2025
github-merge-queue bot pushed a commit that referenced this pull request Apr 2, 2025
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
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 20, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 20, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 21, 2025
zhangyuang pushed a commit to zhangyuang/flutter-fork that referenced this pull request Jun 9, 2025
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
romanejaquez pushed a commit to romanejaquez/flutter that referenced this pull request Aug 14, 2025
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
romanejaquez pushed a commit to romanejaquez/flutter that referenced this pull request Aug 14, 2025
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels. platform-android Android applications specifically platform-ios iOS applications specifically team-ios Owned by iOS platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants