Flutter iOS Embedder
FlutterPlatformViews_Internal.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include "flutter/display_list/effects/dl_image_filter.h"
8 #include "flutter/fml/platform/darwin/cf_utils.h"
10 
11 static constexpr int kMaxPointsInVerb = 4;
12 static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity = 5;
13 
14 namespace flutter {
15 
17  const fml::scoped_nsobject<UIView>& overlay_view,
18  const fml::scoped_nsobject<UIView>& overlay_view_wrapper,
19  std::unique_ptr<IOSSurface> ios_surface,
20  std::unique_ptr<Surface> surface)
21  : overlay_view(overlay_view),
22  overlay_view_wrapper(overlay_view_wrapper),
23  ios_surface(std::move(ios_surface)),
24  surface(std::move(surface)){};
25 
27 
29  : layer_pool_(std::make_unique<FlutterPlatformViewLayerPool>()),
30  weak_factory_(std::make_unique<fml::WeakPtrFactory<FlutterPlatformViewsController>>(this)) {
31  mask_view_pool_.reset(
33 };
34 
36 
37 fml::WeakPtr<flutter::FlutterPlatformViewsController> FlutterPlatformViewsController::GetWeakPtr() {
38  return weak_factory_->GetWeakPtr();
39 }
40 
41 CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix) {
42  // Skia only supports 2D transform so we don't map z.
43  CATransform3D transform = CATransform3DIdentity;
44  transform.m11 = matrix.getScaleX();
45  transform.m21 = matrix.getSkewX();
46  transform.m41 = matrix.getTranslateX();
47  transform.m14 = matrix.getPerspX();
48 
49  transform.m12 = matrix.getSkewY();
50  transform.m22 = matrix.getScaleY();
51  transform.m42 = matrix.getTranslateY();
52  transform.m24 = matrix.getPerspY();
53  return transform;
54 }
55 
56 void ResetAnchor(CALayer* layer) {
57  // Flow uses (0, 0) to apply transform matrix so we need to match that in Quartz.
58  layer.anchorPoint = CGPointZero;
59  layer.position = CGPointZero;
60 }
61 
62 CGRect GetCGRectFromSkRect(const SkRect& clipSkRect) {
63  return CGRectMake(clipSkRect.fLeft, clipSkRect.fTop, clipSkRect.fRight - clipSkRect.fLeft,
64  clipSkRect.fBottom - clipSkRect.fTop);
65 }
66 
67 BOOL BlurRadiusEqualToBlurRadius(CGFloat radius1, CGFloat radius2) {
68  const CGFloat epsilon = 0.01;
69  return radius1 - radius2 < epsilon;
70 }
71 
72 } // namespace flutter
73 
74 @interface PlatformViewFilter ()
75 
76 // `YES` if the backdropFilterView has been configured at least once.
77 @property(nonatomic) BOOL backdropFilterViewConfigured;
78 @property(nonatomic, retain) UIVisualEffectView* backdropFilterView;
79 
80 // Updates the `visualEffectView` with the current filter parameters.
81 // Also sets `self.backdropFilterView` to the updated visualEffectView.
82 - (void)updateVisualEffectView:(UIVisualEffectView*)visualEffectView;
83 
84 @end
85 
86 @implementation PlatformViewFilter
87 
88 static NSObject* _gaussianBlurFilter = nil;
89 // The index of "_UIVisualEffectBackdropView" in UIVisualEffectView's subViews.
90 static NSInteger _indexOfBackdropView = -1;
91 // The index of "_UIVisualEffectSubview" in UIVisualEffectView's subViews.
92 static NSInteger _indexOfVisualEffectSubview = -1;
93 static BOOL _preparedOnce = NO;
94 
95 - (instancetype)initWithFrame:(CGRect)frame
96  blurRadius:(CGFloat)blurRadius
97  visualEffectView:(UIVisualEffectView*)visualEffectView {
98  if (self = [super init]) {
99  _frame = frame;
100  _blurRadius = blurRadius;
101  [PlatformViewFilter prepareOnce:visualEffectView];
102  if (![PlatformViewFilter isUIVisualEffectViewImplementationValid]) {
103  FML_DLOG(ERROR) << "Apple's API for UIVisualEffectView changed. Update the implementation to "
104  "access the gaussianBlur CAFilter.";
105  [self release];
106  return nil;
107  }
108  _backdropFilterView = [visualEffectView retain];
109  _backdropFilterViewConfigured = NO;
110  }
111  return self;
112 }
113 
115  _preparedOnce = NO;
116  [_gaussianBlurFilter release];
117  _gaussianBlurFilter = nil;
120 }
121 
122 + (void)prepareOnce:(UIVisualEffectView*)visualEffectView {
123  if (_preparedOnce) {
124  return;
125  }
126  for (NSUInteger i = 0; i < visualEffectView.subviews.count; i++) {
127  UIView* view = visualEffectView.subviews[i];
128  if ([NSStringFromClass([view class]) hasSuffix:@"BackdropView"]) {
130  for (NSObject* filter in view.layer.filters) {
131  if ([[filter valueForKey:@"name"] isEqual:@"gaussianBlur"] &&
132  [[filter valueForKey:@"inputRadius"] isKindOfClass:[NSNumber class]]) {
133  _gaussianBlurFilter = [filter retain];
134  break;
135  }
136  }
137  } else if ([NSStringFromClass([view class]) hasSuffix:@"VisualEffectSubview"]) {
139  }
140  }
141  _preparedOnce = YES;
142 }
143 
144 + (BOOL)isUIVisualEffectViewImplementationValid {
146 }
147 
148 - (void)dealloc {
149  [_backdropFilterView release];
150  _backdropFilterView = nil;
151 
152  [super dealloc];
153 }
154 
155 - (UIVisualEffectView*)backdropFilterView {
156  FML_DCHECK(_backdropFilterView);
157  if (!self.backdropFilterViewConfigured) {
158  [self updateVisualEffectView:_backdropFilterView];
159  self.backdropFilterViewConfigured = YES;
160  }
161  return _backdropFilterView;
162 }
163 
164 - (void)updateVisualEffectView:(UIVisualEffectView*)visualEffectView {
165  NSObject* gaussianBlurFilter = [[_gaussianBlurFilter copy] autorelease];
166  FML_DCHECK(gaussianBlurFilter);
167  UIView* backdropView = visualEffectView.subviews[_indexOfBackdropView];
168  [gaussianBlurFilter setValue:@(_blurRadius) forKey:@"inputRadius"];
169  backdropView.layer.filters = @[ gaussianBlurFilter ];
170 
171  UIView* visualEffectSubview = visualEffectView.subviews[_indexOfVisualEffectSubview];
172  visualEffectSubview.layer.backgroundColor = UIColor.clearColor.CGColor;
173  visualEffectView.frame = _frame;
174 
175  if (_backdropFilterView != visualEffectView) {
176  _backdropFilterView = [visualEffectView retain];
177  }
178 }
179 
180 @end
181 
182 @interface ChildClippingView ()
183 
184 @property(retain, nonatomic) NSArray<PlatformViewFilter*>* filters;
185 @property(retain, nonatomic) NSMutableArray<UIVisualEffectView*>* backdropFilterSubviews;
186 
187 @end
188 
189 @implementation ChildClippingView
190 
191 // The ChildClippingView's frame is the bounding rect of the platform view. we only want touches to
192 // be hit tested and consumed by this view if they are inside the embedded platform view which could
193 // be smaller the embedded platform view is rotated.
194 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {
195  for (UIView* view in self.subviews) {
196  if ([view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
197  return YES;
198  }
199  }
200  return NO;
201 }
202 
203 - (void)applyBlurBackdropFilters:(NSArray<PlatformViewFilter*>*)filters {
204  FML_DCHECK(self.filters.count == self.backdropFilterSubviews.count);
205  if (self.filters.count == 0 && filters.count == 0) {
206  return;
207  }
208  self.filters = filters;
209  NSUInteger index = 0;
210  for (index = 0; index < self.filters.count; index++) {
211  UIVisualEffectView* backdropFilterView;
212  PlatformViewFilter* filter = self.filters[index];
213  if (self.backdropFilterSubviews.count <= index) {
214  backdropFilterView = filter.backdropFilterView;
215  [self addSubview:backdropFilterView];
216  [self.backdropFilterSubviews addObject:backdropFilterView];
217  } else {
218  [filter updateVisualEffectView:self.backdropFilterSubviews[index]];
219  }
220  }
221  for (NSUInteger i = self.backdropFilterSubviews.count; i > index; i--) {
222  [self.backdropFilterSubviews[i - 1] removeFromSuperview];
223  [self.backdropFilterSubviews removeLastObject];
224  }
225 }
226 
227 - (void)dealloc {
228  [_filters release];
229  _filters = nil;
230 
231  [_backdropFilterSubviews release];
232  _backdropFilterSubviews = nil;
233 
234  [super dealloc];
235 }
236 
237 - (NSMutableArray*)backdropFilterSubviews {
238  if (!_backdropFilterSubviews) {
239  _backdropFilterSubviews = [[NSMutableArray alloc] init];
240  }
241  return _backdropFilterSubviews;
242 }
243 
244 @end
245 
247 
248 // A `CATransform3D` matrix represnts a scale transform that revese UIScreen.scale.
249 //
250 // The transform matrix passed in clipRect/clipRRect/clipPath methods are in device coordinate
251 // space. The transfrom matrix concats `reverseScreenScale` to create a transform matrix in the iOS
252 // logical coordinates (points).
253 //
254 // See https://developer.apple.com/documentation/uikit/uiscreen/1617836-scale?language=objc for
255 // information about screen scale.
256 @property(nonatomic) CATransform3D reverseScreenScale;
257 
258 - (fml::CFRef<CGPathRef>)getTransformedPath:(CGPathRef)path matrix:(CATransform3D)matrix;
259 
260 @end
261 
262 @implementation FlutterClippingMaskView {
263  std::vector<fml::CFRef<CGPathRef>> paths_;
264 }
265 
266 - (instancetype)initWithFrame:(CGRect)frame {
267  return [self initWithFrame:frame screenScale:[UIScreen mainScreen].scale];
268 }
269 
270 - (instancetype)initWithFrame:(CGRect)frame screenScale:(CGFloat)screenScale {
271  if (self = [super initWithFrame:frame]) {
272  self.backgroundColor = UIColor.clearColor;
273  _reverseScreenScale = CATransform3DMakeScale(1 / screenScale, 1 / screenScale, 1);
274  }
275  return self;
276 }
277 
278 - (void)reset {
279  paths_.clear();
280  [self setNeedsDisplay];
281 }
282 
283 // In some scenarios, when we add this view as a maskView of the ChildClippingView, iOS added
284 // this view as a subview of the ChildClippingView.
285 // This results this view blocking touch events on the ChildClippingView.
286 // So we should always ignore any touch events sent to this view.
287 // See https://github.com/flutter/flutter/issues/66044
288 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event {
289  return NO;
290 }
291 
292 - (void)drawRect:(CGRect)rect {
293  CGContextRef context = UIGraphicsGetCurrentContext();
294  CGContextSaveGState(context);
295 
296  // For mask view, only the alpha channel is used.
297  CGContextSetAlpha(context, 1);
298 
299  for (size_t i = 0; i < paths_.size(); i++) {
300  CGContextAddPath(context, paths_.at(i));
301  CGContextClip(context);
302  }
303  CGContextFillRect(context, rect);
304  CGContextRestoreGState(context);
305 }
306 
307 - (void)clipRect:(const SkRect&)clipSkRect matrix:(const SkMatrix&)matrix {
308  CGRect clipRect = flutter::GetCGRectFromSkRect(clipSkRect);
309  CGPathRef path = CGPathCreateWithRect(clipRect, nil);
310  // The `matrix` is based on the physical pixels, convert it to UIKit points.
311  CATransform3D matrixInPoints =
312  CATransform3DConcat(flutter::GetCATransform3DFromSkMatrix(matrix), _reverseScreenScale);
313  paths_.push_back([self getTransformedPath:path matrix:matrixInPoints]);
314 }
315 
316 - (void)clipRRect:(const SkRRect&)clipSkRRect matrix:(const SkMatrix&)matrix {
317  CGPathRef pathRef = nullptr;
318  switch (clipSkRRect.getType()) {
319  case SkRRect::kEmpty_Type: {
320  break;
321  }
322  case SkRRect::kRect_Type: {
323  [self clipRect:clipSkRRect.rect() matrix:matrix];
324  return;
325  }
326  case SkRRect::kOval_Type:
327  case SkRRect::kSimple_Type: {
328  CGRect clipRect = flutter::GetCGRectFromSkRect(clipSkRRect.rect());
329  pathRef = CGPathCreateWithRoundedRect(clipRect, clipSkRRect.getSimpleRadii().x(),
330  clipSkRRect.getSimpleRadii().y(), nil);
331  break;
332  }
333  case SkRRect::kNinePatch_Type:
334  case SkRRect::kComplex_Type: {
335  CGMutablePathRef mutablePathRef = CGPathCreateMutable();
336  // Complex types, we manually add each corner.
337  SkRect clipSkRect = clipSkRRect.rect();
338  SkVector topLeftRadii = clipSkRRect.radii(SkRRect::kUpperLeft_Corner);
339  SkVector topRightRadii = clipSkRRect.radii(SkRRect::kUpperRight_Corner);
340  SkVector bottomRightRadii = clipSkRRect.radii(SkRRect::kLowerRight_Corner);
341  SkVector bottomLeftRadii = clipSkRRect.radii(SkRRect::kLowerLeft_Corner);
342 
343  // Start drawing RRect
344  // Move point to the top left corner adding the top left radii's x.
345  CGPathMoveToPoint(mutablePathRef, nil, clipSkRect.fLeft + topLeftRadii.x(), clipSkRect.fTop);
346  // Move point horizontally right to the top right corner and add the top right curve.
347  CGPathAddLineToPoint(mutablePathRef, nil, clipSkRect.fRight - topRightRadii.x(),
348  clipSkRect.fTop);
349  CGPathAddCurveToPoint(mutablePathRef, nil, clipSkRect.fRight, clipSkRect.fTop,
350  clipSkRect.fRight, clipSkRect.fTop + topRightRadii.y(),
351  clipSkRect.fRight, clipSkRect.fTop + topRightRadii.y());
352  // Move point vertically down to the bottom right corner and add the bottom right curve.
353  CGPathAddLineToPoint(mutablePathRef, nil, clipSkRect.fRight,
354  clipSkRect.fBottom - bottomRightRadii.y());
355  CGPathAddCurveToPoint(mutablePathRef, nil, clipSkRect.fRight, clipSkRect.fBottom,
356  clipSkRect.fRight - bottomRightRadii.x(), clipSkRect.fBottom,
357  clipSkRect.fRight - bottomRightRadii.x(), clipSkRect.fBottom);
358  // Move point horizontally left to the bottom left corner and add the bottom left curve.
359  CGPathAddLineToPoint(mutablePathRef, nil, clipSkRect.fLeft + bottomLeftRadii.x(),
360  clipSkRect.fBottom);
361  CGPathAddCurveToPoint(mutablePathRef, nil, clipSkRect.fLeft, clipSkRect.fBottom,
362  clipSkRect.fLeft, clipSkRect.fBottom - bottomLeftRadii.y(),
363  clipSkRect.fLeft, clipSkRect.fBottom - bottomLeftRadii.y());
364  // Move point vertically up to the top left corner and add the top left curve.
365  CGPathAddLineToPoint(mutablePathRef, nil, clipSkRect.fLeft,
366  clipSkRect.fTop + topLeftRadii.y());
367  CGPathAddCurveToPoint(mutablePathRef, nil, clipSkRect.fLeft, clipSkRect.fTop,
368  clipSkRect.fLeft + topLeftRadii.x(), clipSkRect.fTop,
369  clipSkRect.fLeft + topLeftRadii.x(), clipSkRect.fTop);
370  CGPathCloseSubpath(mutablePathRef);
371 
372  pathRef = mutablePathRef;
373  break;
374  }
375  }
376  // The `matrix` is based on the physical pixels, convert it to UIKit points.
377  CATransform3D matrixInPoints =
378  CATransform3DConcat(flutter::GetCATransform3DFromSkMatrix(matrix), _reverseScreenScale);
379  // TODO(cyanglaz): iOS does not seem to support hard edge on CAShapeLayer. It clearly stated that
380  // the CAShaperLayer will be drawn antialiased. Need to figure out a way to do the hard edge
381  // clipping on iOS.
382  paths_.push_back([self getTransformedPath:pathRef matrix:matrixInPoints]);
383 }
384 
385 - (void)clipPath:(const SkPath&)path matrix:(const SkMatrix&)matrix {
386  if (!path.isValid()) {
387  return;
388  }
389  if (path.isEmpty()) {
390  return;
391  }
392  CGMutablePathRef pathRef = CGPathCreateMutable();
393 
394  // Loop through all verbs and translate them into CGPath
395  SkPath::Iter iter(path, true);
396  SkPoint pts[kMaxPointsInVerb];
397  SkPath::Verb verb = iter.next(pts);
398  SkPoint last_pt_from_last_verb = SkPoint::Make(0, 0);
399  while (verb != SkPath::kDone_Verb) {
400  if (verb == SkPath::kLine_Verb || verb == SkPath::kQuad_Verb || verb == SkPath::kConic_Verb ||
401  verb == SkPath::kCubic_Verb) {
402  FML_DCHECK(last_pt_from_last_verb == pts[0]);
403  }
404  switch (verb) {
405  case SkPath::kMove_Verb: {
406  CGPathMoveToPoint(pathRef, nil, pts[0].x(), pts[0].y());
407  last_pt_from_last_verb = pts[0];
408  break;
409  }
410  case SkPath::kLine_Verb: {
411  CGPathAddLineToPoint(pathRef, nil, pts[1].x(), pts[1].y());
412  last_pt_from_last_verb = pts[1];
413  break;
414  }
415  case SkPath::kQuad_Verb: {
416  CGPathAddQuadCurveToPoint(pathRef, nil, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
417  last_pt_from_last_verb = pts[2];
418  break;
419  }
420  case SkPath::kConic_Verb: {
421  // Conic is not available in quartz, we use quad to approximate.
422  // TODO(cyanglaz): Better approximate the conic path.
423  // https://github.com/flutter/flutter/issues/35062
424  CGPathAddQuadCurveToPoint(pathRef, nil, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
425  last_pt_from_last_verb = pts[2];
426  break;
427  }
428  case SkPath::kCubic_Verb: {
429  CGPathAddCurveToPoint(pathRef, nil, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(),
430  pts[3].x(), pts[3].y());
431  last_pt_from_last_verb = pts[3];
432  break;
433  }
434  case SkPath::kClose_Verb: {
435  CGPathCloseSubpath(pathRef);
436  break;
437  }
438  case SkPath::kDone_Verb: {
439  break;
440  }
441  }
442  verb = iter.next(pts);
443  }
444  // The `matrix` is based on the physical pixels, convert it to UIKit points.
445  CATransform3D matrixInPoints =
446  CATransform3DConcat(flutter::GetCATransform3DFromSkMatrix(matrix), _reverseScreenScale);
447  paths_.push_back([self getTransformedPath:pathRef matrix:matrixInPoints]);
448 }
449 
450 - (fml::CFRef<CGPathRef>)getTransformedPath:(CGPathRef)path matrix:(CATransform3D)matrix {
451  CGAffineTransform affine =
452  CGAffineTransformMake(matrix.m11, matrix.m12, matrix.m21, matrix.m22, matrix.m41, matrix.m42);
453  CGPathRef transformedPath = CGPathCreateCopyByTransformingPath(path, &affine);
454  CGPathRelease(path);
455  return fml::CFRef<CGPathRef>(transformedPath);
456 }
457 
458 @end
459 
461 
462 // The maximum number of `FlutterClippingMaskView` the pool can contain.
463 // This prevents the pool to grow infinately and limits the maximum memory a pool can use.
464 @property(assign, nonatomic) NSUInteger capacity;
465 
466 // The pool contains the views that are available to use.
467 // The number of items in the pool must not excceds `capacity`.
468 @property(retain, nonatomic) NSMutableSet<FlutterClippingMaskView*>* pool;
469 
470 @end
471 
472 @implementation FlutterClippingMaskViewPool : NSObject
473 
474 - (instancetype)initWithCapacity:(NSInteger)capacity {
475  if (self = [super init]) {
476  // Most of cases, there are only one PlatformView in the scene.
477  // Thus init with the capacity of 1.
478  _pool = [[NSMutableSet alloc] initWithCapacity:1];
479  _capacity = capacity;
480  }
481  return self;
482 }
483 
484 - (FlutterClippingMaskView*)getMaskViewWithFrame:(CGRect)frame {
485  FML_DCHECK(self.pool.count <= self.capacity);
486  if (self.pool.count == 0) {
487  // The pool is empty, alloc a new one.
488  return
489  [[[FlutterClippingMaskView alloc] initWithFrame:frame
490  screenScale:[UIScreen mainScreen].scale] autorelease];
491  }
492  FlutterClippingMaskView* maskView = [[[self.pool anyObject] retain] autorelease];
493  maskView.frame = frame;
494  [maskView reset];
495  [self.pool removeObject:maskView];
496  return maskView;
497 }
498 
499 - (void)insertViewToPoolIfNeeded:(FlutterClippingMaskView*)maskView {
500  FML_DCHECK(![self.pool containsObject:maskView]);
501  FML_DCHECK(self.pool.count <= self.capacity);
502  if (self.pool.count == self.capacity) {
503  return;
504  }
505  [self.pool addObject:maskView];
506 }
507 
508 - (void)dealloc {
509  [_pool release];
510 
511  [super dealloc];
512 }
513 
514 @end
kMaxPointsInVerb
static constexpr int kMaxPointsInVerb
Definition: FlutterPlatformViews_Internal.mm:11
-[flutter::FlutterPlatformViewsController FlutterPlatformViewsController]
FlutterPlatformViewsController()
Definition: FlutterPlatformViews_Internal.mm:28
-[flutter::FlutterPlatformViewLayer ~FlutterPlatformViewLayer]
~FlutterPlatformViewLayer()
-[flutter::FlutterPlatformViewsController GetWeakPtr]
fml::WeakPtr< flutter::FlutterPlatformViewsController > GetWeakPtr()
Definition: FlutterPlatformViews_Internal.mm:37
_gaussianBlurFilter
static NSObject * _gaussianBlurFilter
Definition: FlutterPlatformViews_Internal.mm:88
PlatformViewFilter::frame
CGRect frame
Definition: FlutterPlatformViews_Internal.h:82
flutter::BlurRadiusEqualToBlurRadius
BOOL BlurRadiusEqualToBlurRadius(CGFloat radius1, CGFloat radius2)
Definition: FlutterPlatformViews_Internal.mm:67
_indexOfVisualEffectSubview
static NSInteger _indexOfVisualEffectSubview
Definition: FlutterPlatformViews_Internal.mm:92
_preparedOnce
static BOOL _preparedOnce
Definition: FlutterPlatformViews_Internal.mm:93
-[FlutterClippingMaskView clipRect:matrix:]
void clipRect:matrix:(const SkRect &clipSkRect,[matrix] const SkMatrix &matrix)
Definition: FlutterPlatformViews_Internal.mm:307
initWithFrame
instancetype initWithFrame
Definition: FlutterTextInputPlugin.h:167
flutter::ResetAnchor
void ResetAnchor(CALayer *layer)
Definition: FlutterPlatformViews_Internal.mm:56
-[ChildClippingView backdropFilterSubviews]
NSMutableArray * backdropFilterSubviews()
Definition: FlutterPlatformViews_Internal.mm:237
kFlutterClippingMaskViewPoolCapacity
static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity
Definition: FlutterPlatformViews_Internal.mm:12
PlatformViewFilter::blurRadius
CGFloat blurRadius
Definition: FlutterPlatformViews_Internal.h:87
ios_surface.h
flutter::FlutterPlatformViewLayerPool
Definition: FlutterPlatformViews_Internal.h:165
-[FlutterClippingMaskView reset]
void reset()
Definition: FlutterPlatformViews_Internal.mm:278
PlatformViewFilter::backdropFilterView
UIVisualEffectView * backdropFilterView
Definition: FlutterPlatformViews_Internal.h:93
flutter
Definition: accessibility_bridge.h:28
FlutterPlatformViews_Internal.h
_indexOfBackdropView
static NSInteger _indexOfBackdropView
Definition: FlutterPlatformViews_Internal.mm:90
-[flutter::FlutterPlatformViewsController ~FlutterPlatformViewsController]
~FlutterPlatformViewsController()
FlutterClippingMaskViewPool
Definition: FlutterPlatformViews_Internal.h:60
-[flutter::FlutterPlatformViewLayer FlutterPlatformViewLayer]
FlutterPlatformViewLayer(const fml::scoped_nsobject< UIView > &overlay_view, const fml::scoped_nsobject< UIView > &overlay_view_wrapper, std::unique_ptr< IOSSurface > ios_surface, std::unique_ptr< Surface > surface)
Definition: FlutterPlatformViews_Internal.mm:16
ChildClippingView
Definition: FlutterPlatformViews_Internal.h:117
+[PlatformViewFilter resetPreparation]
void resetPreparation()
Definition: FlutterPlatformViews_Internal.mm:114
flutter::GetCATransform3DFromSkMatrix
CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix &matrix)
Definition: FlutterPlatformViews_Internal.mm:41
flutter::GetCGRectFromSkRect
CGRect GetCGRectFromSkRect(const SkRect &clipSkRect)
Definition: FlutterPlatformViews_Internal.mm:62
PlatformViewFilter
Definition: FlutterPlatformViews_Internal.h:78
flutter::FlutterPlatformViewsController
Definition: FlutterPlatformViews_Internal.h:203
FlutterClippingMaskView
Definition: FlutterPlatformViews_Internal.h:29