Skip to content
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

Use a single mask view to clip platform view #20050

Merged
merged 17 commits into from
Aug 3, 2020

Conversation

cyanglaz
Copy link
Contributor

@cyanglaz cyanglaz commented Jul 27, 2020

Description

We used to use a logic that stacking ChildClippingView to achieve clippings for the iOS platform view. (Introduced in aa9b3a1)
This approach has a drawback that the ChildClippingView needs to be detached and re-attached to the flutter view whenever there is a change to the mutator stack.
This can cause a serious bug. (explained in the issue below)

This PR uses a single mask view to do the clipping. So we always only have one ChildClippingView.
In drawRect: of the mask view, it fills the final clipping area with an opaque color. And the ChildClippingView replaces its alpha channel with the mask view's alpha channel by setting the maskView property.
https://developer.apple.com/documentation/uikit/uiview/1622557-maskview?language=objc

Related Issues

Fixes flutter/flutter#46167

Tests

There is no behavior change, but we need to make sure the scenario app passes the tests so we know the mutations still works.
I'm not sure how do we test the behavior of flutter/flutter#46167. I have manually tested to make sure it works now.

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the contributor guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the C++, Objective-C, Java style guides for the engine.
  • I read the tree hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation.
  • All existing and new tests are passing.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read handling breaking changes.

@cyanglaz cyanglaz force-pushed the platform_view_mutation_single_view branch from 5e49efb to db33eae Compare July 27, 2020 05:17
@cyanglaz cyanglaz requested a review from blasten July 27, 2020 05:17
@cyanglaz cyanglaz marked this pull request as ready for review July 27, 2020 18:09
@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@auto-assign auto-assign bot requested a review from liyuqian July 27, 2020 18:12
@cyanglaz cyanglaz requested a review from chinmaygarde July 27, 2020 18:17
@@ -16,6 +16,32 @@
#include "flutter/shell/platform/darwin/ios/ios_context.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"

// A UIView acts as a clipping mask for the |ChildClippingView|.
//
// On |DrawRect:|, this view performs a series of clipping operations and sets the alpha channel
Copy link

Choose a reason for hiding this comment

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

should this interface contain the virtual drawRect method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This View is an OBJC class, drawRect is inherited from the UIView. So I don't think any virtual keyword is necessary here.

Copy link

Choose a reason for hiding this comment

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

sg. do you where I can read about the doc format? I'm not sure what |DrawRect:| means, but I can see it means what you described.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link

Choose a reason for hiding this comment

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

I mean the notation. It reads like a class to me, but I’m not sure what the colon symbol is used for.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah you are right, let me fix that

@blasten
Copy link

blasten commented Jul 28, 2020

@gaaclarke Chris mentioned that this PR is causing the scenario app UI test to fail even though there's not difference in pixels. (as reported by external image comparison tools). Would you mind taking a look?

@cyanglaz
Copy link
Contributor Author

@gaaclarke I update committed the new screenshot into this PR. You should see that their pixels are identical. Maybe we should make the thread holder bigger?

return NO;
- (CGRect)getCGRectFromSkRect:(const SkRect&)clipSkRect {
return CGRectMake(clipSkRect.fLeft, clipSkRect.fTop, clipSkRect.fRight - clipSkRect.fLeft,
clipSkRect.fBottom - clipSkRect.fTop);
}

@end

Choose a reason for hiding this comment

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

gpus_ReturnNotPermittedKillClient crash on iOS 62403 Can you help us have a look,please?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The issue doesn't seem to related to this PR?

@cyanglaz
Copy link
Contributor Author

cyanglaz commented Jul 29, 2020

@blasten @gaaclarke The new screenshots are identical with the old golden images. I think our image diff logic is just more strict than regular image diff tools. Let's update the golden images here?

@gaaclarke
Copy link
Member

I'm fine updating the golden images if they are acceptable. I talked to @cyanglaz offline and I suspect this has to do with different handling of transparent / semi-transparent pixels.

@blasten
Copy link

blasten commented Jul 30, 2020

As discussed offline, @cyanglaz will add unit tests

// Create embedded view params
flutter::MutatorsStack stack;
// Layer tree always pushes a screen scale factor to the stack
SkMatrix screenScaleMatrix = SkMatrix::MakeScale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
Copy link

Choose a reason for hiding this comment

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

I'm not sure what [UIScreen mainScreen].scale would be when executed on LUCI. Maybe pick a constant value?

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 has to be screenScale because the CompositeEmbeddedView uses screenScale to add a reverse scale matrix to the final transform matrix.

// Create embedded view params
flutter::MutatorsStack stack;
// Layer tree always pushes a screen scale factor to the stack
SkMatrix screenScaleMatrix = SkMatrix::MakeScale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
Copy link

Choose a reason for hiding this comment

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

ditto

// Push a rotate matrix
SkMatrix rotateMatrix;
rotateMatrix.setRotate(10);
stack.PushTransform(rotateMatrix);
Copy link

Choose a reason for hiding this comment

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

This is fine, but what about PushClipPath?

void PushClipPath(const SkPath& path);

Should that be in a separate unit test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To test the clipping, we will probably have to render the view into an image, then check the pixels (sort like a screenshot). I think the scenario tests already covered all the clippings, it is kind of redundant.

Copy link

@blasten blasten left a comment

Choose a reason for hiding this comment

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

LGTM % nits

@cyanglaz
Copy link
Contributor Author

cyanglaz commented Aug 1, 2020

@blasten Added unit tests for clipping. PTAL.

Comment on lines +329 to +331
SkMatrix screenScaleMatrix =
SkMatrix::MakeScale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
stack.PushTransform(screenScaleMatrix);
Copy link

Choose a reason for hiding this comment

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

nit: does it need this to test clip specifically?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes. as the clip paths will need to get scaled as well.

if (CGRectContainsPoint(insideClipping, point)) {
XCTAssertEqual(alpha, 255);
} else {
XCTAssertLessThan(alpha, 255);
Copy link

Choose a reason for hiding this comment

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

is there an exact value for the alpha?

Copy link

@blasten blasten 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 adding the tests! LGTM

@cyanglaz cyanglaz merged commit 02d71d6 into flutter:master Aug 3, 2020
@cyanglaz cyanglaz deleted the platform_view_mutation_single_view branch August 3, 2020 17:07
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 3, 2020
blasten pushed a commit to flutter/flutter that referenced this pull request Aug 3, 2020
* 8a0e30b Roll Dart SDK from 2d98d25e71c3 to c59cdee365b9 (1 revision) (flutter/engine#20200)

* 0519052 Roll Dart SDK from c59cdee365b9 to ad9c73cb3270 (1 revision) (flutter/engine#20201)

* fc5b777 Roll Skia from 7225788b9070 to 8e77631a80f0 (8 revisions) (flutter/engine#20184)

* cb8dfdb Roll Skia from 8e77631a80f0 to a6df9da28963 (17 revisions) (flutter/engine#20202)

* ea811fc Roll Dart SDK from ad9c73cb3270 to 0f0e04ec3afa (3 revisions) (flutter/engine#20204)

* 02d71d6 Use a single mask view to clip iOS platform view (flutter/engine#20050)
Pragya007 pushed a commit to Pragya007/flutter that referenced this pull request Aug 11, 2020
* 8a0e30b Roll Dart SDK from 2d98d25e71c3 to c59cdee365b9 (1 revision) (flutter/engine#20200)

* 0519052 Roll Dart SDK from c59cdee365b9 to ad9c73cb3270 (1 revision) (flutter/engine#20201)

* fc5b777 Roll Skia from 7225788b9070 to 8e77631a80f0 (8 revisions) (flutter/engine#20184)

* cb8dfdb Roll Skia from 8e77631a80f0 to a6df9da28963 (17 revisions) (flutter/engine#20202)

* ea811fc Roll Dart SDK from ad9c73cb3270 to 0f0e04ec3afa (3 revisions) (flutter/engine#20204)

* 02d71d6 Use a single mask view to clip iOS platform view (flutter/engine#20050)
pcsosinski pushed a commit to pcsosinski/engine that referenced this pull request Aug 12, 2020
pcsosinski pushed a commit that referenced this pull request Aug 13, 2020
* Update 1.20.2 engine to use Dart 2.9.1

* Use a single mask view to clip iOS platform view (#20050)

* Moved to RMSE for image comparison to account for slight variations in golden image tests (#19658)

Moved to RMSE for image comparison to account for slight variations in golden image production.  (also fixed a flakey test)

Co-authored-by: Chris Yang <ychris@google.com>
Co-authored-by: gaaclarke <30870216+gaaclarke@users.noreply.github.com>
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
* 8a0e30b Roll Dart SDK from 2d98d25e71c3 to c59cdee365b9 (1 revision) (flutter/engine#20200)

* 0519052 Roll Dart SDK from c59cdee365b9 to ad9c73cb3270 (1 revision) (flutter/engine#20201)

* fc5b777 Roll Skia from 7225788b9070 to 8e77631a80f0 (8 revisions) (flutter/engine#20184)

* cb8dfdb Roll Skia from 8e77631a80f0 to a6df9da28963 (17 revisions) (flutter/engine#20202)

* ea811fc Roll Dart SDK from ad9c73cb3270 to 0f0e04ec3afa (3 revisions) (flutter/engine#20204)

* 02d71d6 Use a single mask view to clip iOS platform view (flutter/engine#20050)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

iOS platform view cancels gesture while a new clip layer is added during the gesture.
6 participants