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

Conversation

@cyanglaz
Copy link
Contributor

@cyanglaz cyanglaz commented Sep 8, 2022

This PR makes the PlatformView able to be partially blurred based on the cullrect.
This PR modifies the UIVisualEffectView's filters so that it uses the correct inputRadius from the backdropfilter widget.
The UIVisualEffectView is then set to the correct frame based on cullrect, added to the PlatformView as a subview.

Fixes: flutter/flutter#50183, flutter/flutter#113508

Things to do in this PR:
1. Unit Tests
2. Scenario Tests
3. Manual submission tests since some private API is accessed.
4. Design doc update.

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.

@cyanglaz cyanglaz force-pushed the platform_view_filter_view branch from b060125 to a0fc0b9 Compare October 20, 2022 16:37
Chris Yang added 2 commits October 20, 2022 10:25
@cyanglaz cyanglaz marked this pull request as ready for review October 20, 2022 17:37
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong left a comment

Choose a reason for hiding this comment

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

So behavior-wise, this only changes the Rect of the blur?

// We only support DlBlurImageFilter for BackdropFilter.
if ((*iter)->GetFilter().asBlur() && canApplyBlurBackdrop) {
// Only support DlBlurImageFilter for BackdropFilter.
if ((*iter)->GetFilterMutation().GetFilter().asBlur() && canApplyBlurBackdrop) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to stop pushing the mutation if it's not supported?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could be an optimization in the future. Pushing is done in the shared code across all platforms, to stop pushing we would have to create a way for the iOS PlatformView communicate back to the layer tree.

CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x();
CGRect filterRect =
flutter::GetCGRectFromSkRect((*iter)->GetFilterMutation().GetFilterRect());
// `filterRect` reprents the rect that shouuld be filtered inside the `flutter_view_`.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: typo, should

// The `PlatformViewFilter` needs the frame inside the `clipView` that needs to be
// filtered.
CGRect intersection = CGRectIntersection(filterRect, clipView.frame);
if (CGRectContainsRect(clipView.frame, intersection)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: CGRectIsNull(_:) instead?

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 feel like CGRectContainsRect is more readable. Also, we would have to check both [CGRectIsNull(_:)](https://developer.apple.com/documentation/coregraphics/1455471-cgrectisnull) and CGRectIsEmpty if going the other route.

Copy link
Contributor

Choose a reason for hiding this comment

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

https://developer.apple.com/documentation/coregraphics/1455346-cgrectintersection says use CGRectIsNull to check if the two rects don't overlap.


- (instancetype)initWithFrame:(CGRect)frame
blurRadius:(CGFloat)blurRadius
visualEffectView:(UIVisualEffectView*)visualEffectView {
Copy link
Contributor

Choose a reason for hiding this comment

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

you could copy an existing filter instead of instantiating a new UIVisualEffectView and finding the filter?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So we need a new UIVisualEffectView instance to blur anyway. The problem comes down to these 2 approaches:
1, We store a gaussianFilter Object after first time, and copy it later when needed. (I think this is what you meant)
2. We get the gaussianFilter for the new UIVisualEffectView instance.

Option 1 takes an addition space to store the gaussianFilter
Option 2 takes an addition loop ( for (NSObject* filter in view.layer.filters)) to find the filter, which is currently looping through 2 filters.

I feel like both are similar, maybe Option 2 is less future proof if more filters are added to the layer in some future SDK?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also you'd have to allocate space for a UIVisualEffectView and run its initializer every time. But probably not a big deal.

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 have updated the code to cache a gaussianFilter object and eliminated code to find the views, filters etc, PTAL.

const SkRect& GetFilterRect() const { return filter_rect_; }

bool operator==(const ImageFilterMutation& other) const {
return *filter_ == *other.filter_ && filter_rect_ == other.filter_rect_;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this comparing pointer equality?

Copy link
Contributor Author

@cyanglaz cyanglaz Oct 21, 2022

Choose a reason for hiding this comment

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

This is comparing the data. I added a test for it in my latest commit

// The `PlatformViewFilter` needs the frame inside the `clipView` that needs to be
// filtered.
CGRect intersection = CGRectIntersection(filterRect, clipView.frame);
if (CGRectContainsRect(clipView.frame, intersection)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

https://developer.apple.com/documentation/coregraphics/1455346-cgrectintersection says use CGRectIsNull to check if the two rects don't overlap.


- (instancetype)initWithFrame:(CGRect)frame
blurRadius:(CGFloat)blurRadius
visualEffectView:(UIVisualEffectView*)visualEffectView {
Copy link
Contributor

Choose a reason for hiding this comment

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

Also you'd have to allocate space for a UIVisualEffectView and run its initializer every time. But probably not a big deal.

if ([[filter valueForKey:@"name"] isEqual:@"gaussianBlur"] &&
[[filter valueForKey:@"inputRadius"] isKindOfClass:[NSNumber class]]) {
GaussianBlurFilter = filter;
IsUIVisualEffectViewImplementationValid = YES;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you still need this? You can check if the index < 0 I think?

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 think you were somehow looking at an old version of the code.

return;
}
NSUInteger index = 0;
for (UIView* view in visualEffectView.subviews) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: if you need the index, use for(int i; i < length; i++) instead?

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 thought fast enumeration (for x in y) is faster? Probably doesn't really matter in this case because the number of subviews won't be too big. I will take the suggestion to avoid future confusion since the performance difference will be very insignificant.

Copy link
Contributor

Choose a reason for hiding this comment

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

The enumeration is considerably more efficient than, for example, using NSEnumerator directly.

It's faster than NSEnumerator. I think with NSArray you have random access so it probably won't be slower than for(x in y).

}

+ (void)prepareIfNecessary:(UIVisualEffectView*)visualEffectView {
if (GaussianBlurFilter) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What is GaussianBlurFilter for? It's seems it's not referenced anywhere else?

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 think you were somehow looking at an old version of the code.

christopherfujino pushed a commit to flutter/flutter that referenced this pull request Oct 27, 2022
…114178)

* c33eae133 Macos re-enable TestSetMenu (flutter/engine#37058)

* abc3aabad PlatformView partial blur (flutter/engine#36015)

* 8fcf413f8 Revert "PlatformView partial blur" (flutter/engine#37085)

* 8bb0441e5 Revert "Fixes Android text field to use hint text for accessibility (#36846)" (flutter/engine#37083)
auto-submit bot pushed a commit that referenced this pull request Oct 28, 2022
schwa423 pushed a commit to schwa423/engine that referenced this pull request Nov 16, 2022
@jmagman jmagman added the blog Items that should be included in a blog label Jan 4, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

autosubmit Merge PR when tree becomes green via auto submit App blog Items that should be included in a blog platform-ios

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Alert dialog is transparent when they are drawn over platform view on iOS

3 participants