@@ -32,6 +32,22 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree {
32
32
}
33
33
@end
34
34
35
+ // Determines if the final `clipBounds` from a clipRect/clipRRect/clipPath mutator contains the
36
+ // `platformview_boundingrect`.
37
+ //
38
+ // `clip_bounds` is the bounding rect of the rect/rrect/path in the clipRect/clipRRect/clipPath
39
+ // mutator. This rect is in its own coordinate space. The rect needs to be transformed by
40
+ // `transform_matrix` to be in the coordinate space where the PlatformView is displayed.
41
+ //
42
+ // `platformview_boundingrect` is the final bounding rect of the PlatformView in the coordinate
43
+ // space where the PlatformView is displayed.
44
+ static bool ClipBoundsContainsPlatformViewBoundingRect (const SkRect& clip_bounds,
45
+ const SkRect& platformview_boundingrect,
46
+ const SkMatrix& transform_matrix) {
47
+ SkRect transforme_clip_bounds = transform_matrix.mapRect (clip_bounds);
48
+ return transforme_clip_bounds.contains (platformview_boundingrect);
49
+ }
50
+
35
51
namespace flutter {
36
52
// Becomes NO if Apple's API changes and blurred backdrop filters cannot be applied.
37
53
BOOL canApplyBlurBackdrop = YES ;
@@ -404,47 +420,62 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree {
404
420
}
405
421
406
422
void FlutterPlatformViewsController::ApplyMutators (const MutatorsStack& mutators_stack,
407
- UIView* embedded_view) {
423
+ UIView* embedded_view,
424
+ const SkRect& bounding_rect) {
408
425
if (flutter_view_ == nullptr ) {
409
426
return ;
410
427
}
411
428
FML_DCHECK (CATransform3DEqualToTransform (embedded_view.layer .transform , CATransform3DIdentity));
412
429
ResetAnchor (embedded_view.layer );
413
430
ChildClippingView* clipView = (ChildClippingView*)embedded_view.superview ;
414
431
415
- // The UIKit frame is set based on the logical resolution instead of physical.
416
- // (https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html).
417
- // However, flow is based on the physical resolution. For example, 1000 pixels in flow equals
418
- // 500 points in UIKit. And until this point, we did all the calculation based on the flow
419
- // resolution. So we need to scale down to match UIKit's logical resolution.
420
432
CGFloat screenScale = [UIScreen mainScreen ].scale ;
421
- CATransform3D finalTransform = CATransform3DMakeScale (1 / screenScale, 1 / screenScale, 1 );
422
433
423
434
UIView* flutter_view = flutter_view_.get ();
424
435
FlutterClippingMaskView* maskView = [[[FlutterClippingMaskView alloc ]
425
436
initWithFrame: CGRectMake (-clipView.frame.origin.x, -clipView.frame.origin.y,
426
437
CGRectGetWidth (flutter_view.bounds),
427
- CGRectGetHeight (flutter_view.bounds))] autorelease ];
438
+ CGRectGetHeight (flutter_view.bounds))
439
+ screenScale: screenScale] autorelease ];
428
440
441
+ SkMatrix transformMatrix;
429
442
NSMutableArray * blurFilters = [[[NSMutableArray alloc ] init ] autorelease ];
430
443
444
+ clipView.maskView = nil ;
431
445
auto iter = mutators_stack.Begin ();
432
446
while (iter != mutators_stack.End ()) {
433
447
switch ((*iter)->GetType ()) {
434
448
case kTransform : {
435
- CATransform3D transform = GetCATransform3DFromSkMatrix ((*iter)->GetMatrix ());
436
- finalTransform = CATransform3DConcat (transform, finalTransform);
449
+ transformMatrix.preConcat ((*iter)->GetMatrix ());
437
450
break ;
438
451
}
439
- case kClipRect :
440
- [maskView clipRect: (*iter)->GetRect () matrix: finalTransform];
452
+ case kClipRect : {
453
+ if (ClipBoundsContainsPlatformViewBoundingRect ((*iter)->GetRect (), bounding_rect,
454
+ transformMatrix)) {
455
+ break ;
456
+ }
457
+ [maskView clipRect: (*iter)->GetRect () matrix: transformMatrix];
458
+ clipView.maskView = maskView;
441
459
break ;
442
- case kClipRRect :
443
- [maskView clipRRect: (*iter)->GetRRect () matrix: finalTransform];
460
+ }
461
+ case kClipRRect : {
462
+ if (ClipBoundsContainsPlatformViewBoundingRect ((*iter)->GetRRect ().getBounds (),
463
+ bounding_rect, transformMatrix)) {
464
+ break ;
465
+ }
466
+ [maskView clipRRect: (*iter)->GetRRect () matrix: transformMatrix];
467
+ clipView.maskView = maskView;
444
468
break ;
445
- case kClipPath :
446
- [maskView clipPath: (*iter)->GetPath () matrix: finalTransform];
469
+ }
470
+ case kClipPath : {
471
+ if (ClipBoundsContainsPlatformViewBoundingRect ((*iter)->GetPath ().getBounds (),
472
+ bounding_rect, transformMatrix)) {
473
+ break ;
474
+ }
475
+ [maskView clipPath: (*iter)->GetPath () matrix: transformMatrix];
476
+ clipView.maskView = maskView;
447
477
break ;
478
+ }
448
479
case kOpacity :
449
480
embedded_view.alpha = (*iter)->GetAlphaFloat () * embedded_view.alpha ;
450
481
break ;
@@ -489,17 +520,23 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree {
489
520
[clipView applyBlurBackdropFilters: blurFilters];
490
521
}
491
522
523
+ // The UIKit frame is set based on the logical resolution instead of physical.
524
+ // (https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html).
525
+ // However, flow is based on the physical resolution. For example, 1000 pixels in flow equals
526
+ // 500 points in UIKit. And until this point, we did all the calculation based on the flow
527
+ // resolution. So we need to scale down to match UIKit's logical resolution.
528
+ transformMatrix.postScale (1 / screenScale, 1 / screenScale);
529
+
492
530
// Reverse the offset of the clipView.
493
531
// The clipView's frame includes the final translate of the final transform matrix.
494
532
// Thus, this translate needs to be reversed so the platform view can layout at the correct
495
533
// offset.
496
534
//
497
535
// Note that the transforms are not applied to the clipping paths because clipping paths happen on
498
536
// the mask view, whose origin is always (0,0) to the flutter_view.
499
- CATransform3D reverseTranslate =
500
- CATransform3DMakeTranslation (-clipView.frame .origin .x , -clipView.frame .origin .y , 0 );
501
- embedded_view.layer .transform = CATransform3DConcat (finalTransform, reverseTranslate);
502
- clipView.maskView = maskView;
537
+ transformMatrix.postTranslate (-clipView.frame .origin .x , -clipView.frame .origin .y );
538
+
539
+ embedded_view.layer .transform = flutter::GetCATransform3DFromSkMatrix (transformMatrix);
503
540
}
504
541
505
542
void FlutterPlatformViewsController::CompositeWithParams (int view_id,
@@ -538,7 +575,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree {
538
575
CGFloat screenScale = [UIScreen mainScreen ].scale ;
539
576
clippingView.frame = CGRectMake (rect.x () / screenScale, rect.y () / screenScale,
540
577
rect.width () / screenScale, rect.height () / screenScale);
541
- ApplyMutators (mutatorStack, touchInterceptor);
578
+ ApplyMutators (mutatorStack, touchInterceptor, rect );
542
579
}
543
580
544
581
EmbedderPaintContext FlutterPlatformViewsController::CompositeEmbeddedView (int view_id) {
0 commit comments