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