Skip to content

Add debug check for platform view filter layer conflict - #188542

Closed
laishere wants to merge 2 commits into
flutter:masterfrom
laishere:detect_platform_view_filter_conflict
Closed

laishere wants to merge 2 commits into
flutter:masterfrom
laishere:detect_platform_view_filter_conflict

Conversation

@laishere

Copy link
Copy Markdown

PR split from #182935

Adds a debug check to detect PlatformViewLayers embedded within filter-based layers. This issue was discovered while investigating the cupertino sheet scaling bug and the check helps surface similar issues earlier during development.

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools.
  • 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.

@github-actions github-actions Bot added the framework flutter/packages/flutter repository. See also f: labels. label Jun 25, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a debug-time check to ensure that a PlatformViewLayer is not nested under filter-based layers (ImageFilterLayer, ColorFilterLayer, or ShaderMaskLayer), which can cause rasterization conflicts. It also adjusts the order of layer pushing and debug assertions in RenderTransform.paint and adds corresponding unit tests. Feedback on these changes suggests calling super.redepthChildren() to satisfy the @mustCallSuper annotation and optimizing the conflict check to avoid allocating the path list on the happy path.

Comment thread packages/flutter/lib/src/rendering/layer.dart
Comment thread packages/flutter/lib/src/rendering/layer.dart

@dkwingsmt dkwingsmt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Thank you!

void _debugCheckForRasterizationConflict() {
Layer? ancestor = parent;
while (ancestor != null) {
if (ancestor is ImageFilterLayer ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These if-checks feel brittle. My understanding is PlatformViewLayer should not have filter/blend layer ancestors, Is it better to add a signal in the Layer interface which is set for filter/blend layers and can be checked here instead?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yeah, that could be a way. When I was implementing this, I thought this would be a focused touch considering that it only affects the platform view and the kind of filter layer is stable. But if new filter layer could be added in the future, adding a common interface would indeed be helpful as a reminder.

Comment thread packages/flutter/lib/src/rendering/layer.dart
@override
void redepthChildren() {
assert(() {
_debugCheckForRasterizationConflict();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this debug check live here? What if a PlatformViewLayer with a high enough cached depth is grafted onto a filter layer's subtree, so redepthChildren is never called?

@laishere laishere Jul 22, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yeah, this is a valid concern. I just checked that redepthChildren will only be called whenever a child's depth <= its parent's depth.
And I also noticed a potential bug, if a subtree can be moved to another layer, and if the depth of the subtree root is already greater than the new parent's, then the depth of the whole subtree won't be updated. It means depth can be discontinuous in a layer path? Is this by design?

And I think this is best place I can think of. It covers all the cases except moving a subtree containing platform view to a layer with lower depth via global key?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I agree this isn't the right place. Does the assert work in addToScene where the layer tree should be stable?

Is this by design?

Yes. depth represents a partial order so it's exact value doesn't matter.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Just tested addToScene, not working.
It's only called during the very early stage and the platform view layer doesn't have the full ancestors list.

@override
void redepthChildren() {
assert(() {
_debugCheckForRasterizationConflict();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I agree this isn't the right place. Does the assert work in addToScene where the layer tree should be stable?

Is this by design?

Yes. depth represents a partial order so it's exact value doesn't matter.

void _debugCheckForRasterizationConflict() {
Layer? ancestor = parent;
while (ancestor != null) {
if (ancestor is ImageFilterLayer ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are there existing documentation supporting this assertion? Different embedders implement platform views differently so I'm not sure this is a problem for all embedders.

@laishere laishere Jul 23, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

In the PlatformViewLayer docs:

/// A layer that shows an embedded [UIView](https://developer.apple.com/documentation/uikit/uiview)
/// on iOS.

And https://docs.flutter.dev/platform-integration/ios/platform-views#composition-limitations

Composition limitations
There are some limitations when composing iOS Platform Views.

The [ShaderMask](https://api.flutter.dev/flutter/foundation/ShaderMask.html) and [ColorFiltered](https://api.flutter.dev/flutter/foundation/ColorFiltered.html) widgets are not supported.
The [BackdropFilter](https://api.flutter.dev/flutter/foundation/BackdropFilter.html) widget is supported, but there are some limitations on how it can be used. For more details, check out the [iOS Platform View Backdrop Filter Blur design doc](https://flutter.dev/go/ios-platformview-backdrop-filter-blur).

And for ImageFilter, I think it has the same limitation.

I think PlatformViewLayer is only for iOS (and macOS?) based on these docs and https://docs.flutter.dev/platform-integration/android/platform-views#choosing-an-implementation. So, adding this assertion should not affect the texture rendering native views that will work with these filters.

However I think I need to update the cupertino bottom sheet PR. Because hasPlatformView=true should not disable the animation optimization for Android which uses texture for platform views.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Also, PlatformViewLayer is the ONLY layer that always returns

  @override
  bool supportsRasterization() {
    return false;
  }

Even if the other embedders could use it, it's for the content that doesn't support raterization and cannot be sent to the filter shaders.

@justinmc
justinmc requested a review from LongCatIsLooong July 28, 2026 22:26
@Renzo-Olivares

Copy link
Copy Markdown
Contributor

Hi @laishere, is this something you were still interested in working on? If not then we should probably close this PR to clear up the review queue.

@Renzo-Olivares Renzo-Olivares added the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label Sep 8, 2026
@laishere

laishere commented Sep 9, 2026

Copy link
Copy Markdown
Author

I will close it.

@laishere laishere closed this Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

framework flutter/packages/flutter repository. See also f: labels. waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants