Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
5#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
6
7#include "flutter/display_list/effects/dl_image_filter.h"
8#include "flutter/fml/platform/darwin/cf_utils.h"
9#import "flutter/shell/platform/darwin/ios/ios_surface.h"
10
11static constexpr int kMaxPointsInVerb = 4;
12static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity = 5;
13
14namespace 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
40
41CATransform3D 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
56void 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
62CGRect GetCGRectFromSkRect(const SkRect& clipSkRect) {
63 return CGRectMake(clipSkRect.fLeft, clipSkRect.fTop, clipSkRect.fRight - clipSkRect.fLeft,
64 clipSkRect.fBottom - clipSkRect.fTop);
65}
66
67BOOL 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
88static NSObject* _gaussianBlurFilter = nil;
89// The index of "_UIVisualEffectBackdropView" in UIVisualEffectView's subViews.
90static NSInteger _indexOfBackdropView = -1;
91// The index of "_UIVisualEffectSubview" in UIVisualEffectView's subViews.
92static NSInteger _indexOfVisualEffectSubview = -1;
93static 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];
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
114+ (void)resetPreparation {
115 _preparedOnce = NO;
116 [_gaussianBlurFilter release];
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
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
246@interface FlutterClippingMaskView ()
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()) {
320 break;
321 }
322 case SkRRect::kRect_Type: {
323 [self clipRect:clipSkRRect.rect() matrix:matrix];
324 return;
325 }
328 CGRect clipRect = flutter::GetCGRectFromSkRect(clipSkRRect.rect());
329 pathRef = CGPathCreateWithRoundedRect(clipRect, clipSkRRect.getSimpleRadii().x(),
330 clipSkRRect.getSimpleRadii().y(), nil);
331 break;
332 }
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
460@interface FlutterClippingMaskViewPool ()
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
AutoreleasePool pool
m reset()
static constexpr int kMaxPointsInVerb
static NSInteger _indexOfVisualEffectSubview
static NSInteger _indexOfBackdropView
static BOOL _preparedOnce
static NSObject * _gaussianBlurFilter
static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity
@ kClose_Verb
Definition SkPath.h:1463
@ kMove_Verb
Definition SkPath.h:1458
@ kConic_Verb
Definition SkPath.h:1461
@ kDone_Verb
Definition SkPath.h:1464
@ kCubic_Verb
Definition SkPath.h:1462
@ kQuad_Verb
Definition SkPath.h:1460
@ kLine_Verb
Definition SkPath.h:1459
SkVector getSimpleRadii() const
Definition SkRRect.h:111
Type getType() const
Definition SkRRect.h:76
const SkRect & rect() const
Definition SkRRect.h:264
SkVector radii(Corner corner) const
Definition SkRRect.h:271
@ kOval_Type
non-zero width and height filled with radii
Definition SkRRect.h:69
@ kSimple_Type
non-zero width and height with equal radii
Definition SkRRect.h:70
@ kEmpty_Type
zero width or height
Definition SkRRect.h:67
@ kNinePatch_Type
non-zero width and height with axis-aligned radii
Definition SkRRect.h:71
@ kRect_Type
non-zero width and height, and zeroed radii
Definition SkRRect.h:68
@ kComplex_Type
non-zero width and height with arbitrary radii
Definition SkRRect.h:72
@ kUpperLeft_Corner
index of top-left corner radii
Definition SkRRect.h:252
@ kLowerRight_Corner
index of bottom-right corner radii
Definition SkRRect.h:254
@ kUpperRight_Corner
index of top-right corner radii
Definition SkRRect.h:253
@ kLowerLeft_Corner
index of bottom-left corner radii
Definition SkRRect.h:255
fml::WeakPtr< flutter::FlutterPlatformViewsController > GetWeakPtr()
void reset(NST *object=Traits::InvalidValue(), scoped_policy::OwnershipPolicy policy=scoped_policy::OwnershipPolicy::kAssume)
VkSurfaceKHR surface
Definition main.cc:49
double frame
Definition examples.cpp:31
FlKeyEvent * event
#define FML_DLOG(severity)
Definition logging.h:102
#define FML_DCHECK(condition)
Definition logging.h:103
void prepareOnce:(UIVisualEffectView *visualEffectView)
UIVisualEffectView * backdropFilterView
instancetype initWithFrame
double y
double x
clipRRect(r.rrect, r.opAA.op(), r.opAA.aa())) DRAW(ClipRect
unsigned useCenter Optional< SkMatrix > matrix
Definition SkRecords.h:258
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
clipPath(r.path, r.opAA.op(), r.opAA.aa())) DRAW(ClipRRect
BOOL BlurRadiusEqualToBlurRadius(CGFloat radius1, CGFloat radius2)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
void ResetAnchor(CALayer *layer)
CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix &matrix)
CGRect GetCGRectFromSkRect(const SkRect &clipSkRect)
Definition ref_ptr.h:256
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition p3.cpp:47
static constexpr SkPoint Make(float x, float y)
constexpr float y() const
constexpr float x() const
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
SkScalar fLeft
smaller x-axis bounds
Definition extension.cpp:14
SkScalar fRight
larger x-axis bounds
Definition extension.cpp:16
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15
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)
#define ERROR(message)
int BOOL