Flutter Engine
The Flutter Engine
FlutterPlatformViewsTest.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 <OCMock/OCMock.h>
6#import <UIKit/UIKit.h>
7#import <XCTest/XCTest.h>
8
9#import "flutter/fml/thread.h"
10#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
11#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h"
12#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
13#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
14#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTouchInterceptingView_Test.h"
15#import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
16
18
21const float kFloatCompareEpsilon = 0.001;
22
24@end
26
27- (instancetype)init {
28 self = [super init];
29 if (self) {
31 }
32 return self;
33}
34
35- (void)dealloc {
37}
38
39@end
40
42@property(nonatomic, strong) UIView* view;
43@property(nonatomic, assign) BOOL viewCreated;
44@end
45
47
48- (instancetype)init {
49 if (self = [super init]) {
50 _view = [[FlutterPlatformViewsTestMockPlatformView alloc] init];
51 _viewCreated = NO;
52 }
53 return self;
54}
55
56- (UIView*)view {
57 [self checkViewCreatedOnce];
58 return _view;
59}
60
62 if (self.viewCreated) {
63 abort();
64 }
65 self.viewCreated = YES;
66}
67
68@end
69
71 : NSObject <FlutterPlatformViewFactory>
72@end
73
75- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
76 viewIdentifier:(int64_t)viewId
77 arguments:(id _Nullable)args {
79}
80
81@end
82
83namespace flutter {
84namespace {
85class FlutterPlatformViewsTestMockPlatformViewDelegate : public PlatformView::Delegate {
86 public:
87 void OnPlatformViewCreated(std::unique_ptr<Surface> surface) override {}
88 void OnPlatformViewDestroyed() override {}
89 void OnPlatformViewScheduleFrame() override {}
90 void OnPlatformViewAddView(int64_t view_id,
91 const ViewportMetrics& viewport_metrics,
92 AddViewCallback callback) override {}
93 void OnPlatformViewRemoveView(int64_t view_id, RemoveViewCallback callback) override {}
94 void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) override {}
95 void OnPlatformViewSetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics) override {}
96 const flutter::Settings& OnPlatformViewGetSettings() const override { return settings_; }
97 void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage> message) override {}
98 void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet) override {
99 }
100 void OnPlatformViewDispatchSemanticsAction(int32_t id,
102 fml::MallocMapping args) override {}
103 void OnPlatformViewSetSemanticsEnabled(bool enabled) override {}
104 void OnPlatformViewSetAccessibilityFeatures(int32_t flags) override {}
105 void OnPlatformViewRegisterTexture(std::shared_ptr<Texture> texture) override {}
106 void OnPlatformViewUnregisterTexture(int64_t texture_id) override {}
107 void OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) override {}
108
109 void LoadDartDeferredLibrary(intptr_t loading_unit_id,
110 std::unique_ptr<const fml::Mapping> snapshot_data,
111 std::unique_ptr<const fml::Mapping> snapshot_instructions) override {
112 }
113 void LoadDartDeferredLibraryError(intptr_t loading_unit_id,
114 const std::string error_message,
115 bool transient) override {}
116 void UpdateAssetResolverByType(std::unique_ptr<flutter::AssetResolver> updated_asset_resolver,
118
120};
121
122} // namespace
123} // namespace flutter
124
125namespace {
127 auto thread = std::make_unique<fml::Thread>(name);
128 auto runner = thread->GetTaskRunner();
129 return runner;
130}
131} // namespace
132
133@interface FlutterPlatformViewsTest : XCTestCase
134@end
135
136@implementation FlutterPlatformViewsTest
137
139 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
140 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
141 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
142 /*platform=*/thread_task_runner,
143 /*raster=*/thread_task_runner,
144 /*ui=*/thread_task_runner,
145 /*io=*/thread_task_runner);
146 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
147 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
148 /*delegate=*/mock_delegate,
149 /*rendering_api=*/mock_delegate.settings_.enable_impeller
152 /*platform_views_controller=*/flutterPlatformViewsController,
153 /*task_runners=*/runners,
154 /*worker_task_runner=*/nil,
155 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
156
159 flutterPlatformViewsController->RegisterViewFactory(
160 factory, @"MockFlutterPlatformView",
162 FlutterResult result = ^(id result) {
163 };
164 flutterPlatformViewsController->OnMethodCall(
166 methodCallWithMethodName:@"create"
167 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
168 result);
169 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
170 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
171 // Create embedded view params
173 // Layer tree always pushes a screen scale factor to the stack
174 SkMatrix screenScaleMatrix =
175 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
176 stack.PushTransform(screenScaleMatrix);
177 // Push a translate matrix
178 SkMatrix translateMatrix = SkMatrix::Translate(100, 100);
179 stack.PushTransform(translateMatrix);
180 SkMatrix finalMatrix;
181 finalMatrix.setConcat(screenScaleMatrix, translateMatrix);
182
183 auto embeddedViewParams =
184 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
185
186 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
187 flutterPlatformViewsController->CompositeEmbeddedView(2);
188
189 flutterPlatformViewsController->GetPlatformViewRect(2);
190
191 XCTAssertNotNil(gMockPlatformView);
192
193 flutterPlatformViewsController->Reset();
194}
195
197 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
198 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
199 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
200 /*platform=*/thread_task_runner,
201 /*raster=*/thread_task_runner,
202 /*ui=*/thread_task_runner,
203 /*io=*/thread_task_runner);
204 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
205 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
206 /*delegate=*/mock_delegate,
207 /*rendering_api=*/mock_delegate.settings_.enable_impeller
210 /*platform_views_controller=*/flutterPlatformViewsController,
211 /*task_runners=*/runners,
212 /*worker_task_runner=*/nil,
213 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
214
217 flutterPlatformViewsController->RegisterViewFactory(
218 factory, @"MockFlutterPlatformView",
220 FlutterResult result = ^(id result) {
221 };
222 flutterPlatformViewsController->OnMethodCall(
224 methodCallWithMethodName:@"create"
225 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
226 result);
227
228 XCTAssertNotNil(gMockPlatformView);
229}
230
232 ChildClippingView* childClippingView =
233 [[ChildClippingView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
234 UIView* childView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
235 [childClippingView addSubview:childView];
236
237 XCTAssertFalse([childClippingView pointInside:CGPointMake(50, 50) withEvent:nil]);
238 XCTAssertFalse([childClippingView pointInside:CGPointMake(99, 100) withEvent:nil]);
239 XCTAssertFalse([childClippingView pointInside:CGPointMake(100, 99) withEvent:nil]);
240 XCTAssertFalse([childClippingView pointInside:CGPointMake(201, 200) withEvent:nil]);
241 XCTAssertFalse([childClippingView pointInside:CGPointMake(200, 201) withEvent:nil]);
242 XCTAssertFalse([childClippingView pointInside:CGPointMake(99, 200) withEvent:nil]);
243 XCTAssertFalse([childClippingView pointInside:CGPointMake(200, 299) withEvent:nil]);
244
245 XCTAssertTrue([childClippingView pointInside:CGPointMake(150, 150) withEvent:nil]);
246 XCTAssertTrue([childClippingView pointInside:CGPointMake(100, 100) withEvent:nil]);
247 XCTAssertTrue([childClippingView pointInside:CGPointMake(199, 100) withEvent:nil]);
248 XCTAssertTrue([childClippingView pointInside:CGPointMake(100, 199) withEvent:nil]);
249 XCTAssertTrue([childClippingView pointInside:CGPointMake(199, 199) withEvent:nil]);
250}
251
253 __weak NSMutableArray<UIVisualEffectView*>* weakBackdropFilterSubviews = nil;
254 __weak UIVisualEffectView* weakVisualEffectView1 = nil;
255 __weak UIVisualEffectView* weakVisualEffectView2 = nil;
256
257 @autoreleasepool {
258 ChildClippingView* clippingView = [[ChildClippingView alloc] initWithFrame:CGRectZero];
259 UIVisualEffectView* visualEffectView1 = [[UIVisualEffectView alloc]
260 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
261 weakVisualEffectView1 = visualEffectView1;
262 PlatformViewFilter* platformViewFilter1 =
263 [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
264 blurRadius:5
265 visualEffectView:visualEffectView1];
266
267 [clippingView applyBlurBackdropFilters:@[ platformViewFilter1 ]];
268
269 // Replace the blur filter to validate the original and new UIVisualEffectView are released.
270 UIVisualEffectView* visualEffectView2 = [[UIVisualEffectView alloc]
271 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
272 weakVisualEffectView2 = visualEffectView2;
273 PlatformViewFilter* platformViewFilter2 =
274 [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
275 blurRadius:5
276 visualEffectView:visualEffectView2];
277 [clippingView applyBlurBackdropFilters:@[ platformViewFilter2 ]];
278
279 weakBackdropFilterSubviews = clippingView.backdropFilterSubviews;
280 XCTAssertNotNil(weakBackdropFilterSubviews);
281 clippingView = nil;
282 }
283 XCTAssertNil(weakBackdropFilterSubviews);
284 XCTAssertNil(weakVisualEffectView1);
285 XCTAssertNil(weakVisualEffectView2);
286}
287
289 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
290 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
291 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
292 /*platform=*/thread_task_runner,
293 /*raster=*/thread_task_runner,
294 /*ui=*/thread_task_runner,
295 /*io=*/thread_task_runner);
296 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
297 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
298 /*delegate=*/mock_delegate,
299 /*rendering_api=*/mock_delegate.settings_.enable_impeller
302 /*platform_views_controller=*/flutterPlatformViewsController,
303 /*task_runners=*/runners,
304 /*worker_task_runner=*/nil,
305 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
306
309 flutterPlatformViewsController->RegisterViewFactory(
310 factory, @"MockFlutterPlatformView",
312 FlutterResult result = ^(id result) {
313 };
314 flutterPlatformViewsController->OnMethodCall(
316 methodCallWithMethodName:@"create"
317 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
318 result);
319
320 XCTAssertNotNil(gMockPlatformView);
321
322 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
323 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
324 // Create embedded view params
326 // Layer tree always pushes a screen scale factor to the stack
327 CGFloat screenScale = [UIScreen mainScreen].scale;
328 SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale);
329 stack.PushTransform(screenScaleMatrix);
330 // Push a backdrop filter
331 auto filter = std::make_shared<flutter::DlBlurImageFilter>(5, 2, flutter::DlTileMode::kClamp);
332 stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
333
334 auto embeddedViewParams =
335 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
336
337 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
338 flutterPlatformViewsController->CompositeEmbeddedView(2);
339 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]);
340 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
341 [mockFlutterView addSubview:childClippingView];
342
343 [mockFlutterView setNeedsLayout];
344 [mockFlutterView layoutIfNeeded];
345
346 // childClippingView has visual effect view with the correct configurations.
347 NSUInteger numberOfExpectedVisualEffectView = 0;
348 for (UIView* subview in childClippingView.subviews) {
349 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
350 continue;
351 }
352 XCTAssertLessThan(numberOfExpectedVisualEffectView, 1u);
353 if ([self validateOneVisualEffectView:subview
354 expectedFrame:CGRectMake(0, 0, 10, 10)
355 inputRadius:5]) {
356 numberOfExpectedVisualEffectView++;
357 }
358 }
359 XCTAssertEqual(numberOfExpectedVisualEffectView, 1u);
360}
361
363 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
364 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
365 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
366 /*platform=*/thread_task_runner,
367 /*raster=*/thread_task_runner,
368 /*ui=*/thread_task_runner,
369 /*io=*/thread_task_runner);
370 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
371 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
372 /*delegate=*/mock_delegate,
373 /*rendering_api=*/mock_delegate.settings_.enable_impeller
376 /*platform_views_controller=*/flutterPlatformViewsController,
377 /*task_runners=*/runners,
378 /*worker_task_runner=*/nil,
379 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
380
383 flutterPlatformViewsController->RegisterViewFactory(
384 factory, @"MockFlutterPlatformView",
386 FlutterResult result = ^(id result) {
387 };
388 flutterPlatformViewsController->OnMethodCall(
390 methodCallWithMethodName:@"create"
391 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
392 result);
393
394 XCTAssertNotNil(gMockPlatformView);
395
396 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
397 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
398 // Create embedded view params
400 // Layer tree always pushes a screen scale factor to the stack
401 CGFloat screenScale = [UIScreen mainScreen].scale;
402 SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale);
403 stack.PushTransform(screenScaleMatrix);
404 // Push a backdrop filter
405 auto filter = std::make_shared<flutter::DlBlurImageFilter>(5, 2, flutter::DlTileMode::kClamp);
406 stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 8, screenScale * 8));
407
408 auto embeddedViewParams =
409 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(5, 10), stack);
410
411 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
412 flutterPlatformViewsController->CompositeEmbeddedView(2);
413 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]);
414 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
415 [mockFlutterView addSubview:childClippingView];
416
417 [mockFlutterView setNeedsLayout];
418 [mockFlutterView layoutIfNeeded];
419
420 // childClippingView has visual effect view with the correct configurations.
421 NSUInteger numberOfExpectedVisualEffectView = 0;
422 for (UIView* subview in childClippingView.subviews) {
423 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
424 continue;
425 }
426 XCTAssertLessThan(numberOfExpectedVisualEffectView, 1u);
427 if ([self validateOneVisualEffectView:subview
428 expectedFrame:CGRectMake(0, 0, 5, 8)
429 inputRadius:5]) {
430 numberOfExpectedVisualEffectView++;
431 }
432 }
433 XCTAssertEqual(numberOfExpectedVisualEffectView, 1u);
434}
435
437 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
438 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
439 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
440 /*platform=*/thread_task_runner,
441 /*raster=*/thread_task_runner,
442 /*ui=*/thread_task_runner,
443 /*io=*/thread_task_runner);
444 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
445 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
446 /*delegate=*/mock_delegate,
447 /*rendering_api=*/mock_delegate.settings_.enable_impeller
450 /*platform_views_controller=*/flutterPlatformViewsController,
451 /*task_runners=*/runners,
452 /*worker_task_runner=*/nil,
453 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
454
457 flutterPlatformViewsController->RegisterViewFactory(
458 factory, @"MockFlutterPlatformView",
460 FlutterResult result = ^(id result) {
461 };
462 flutterPlatformViewsController->OnMethodCall(
464 methodCallWithMethodName:@"create"
465 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
466 result);
467
468 XCTAssertNotNil(gMockPlatformView);
469
470 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
471 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
472 // Create embedded view params
474 // Layer tree always pushes a screen scale factor to the stack
475 CGFloat screenScale = [UIScreen mainScreen].scale;
476 SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale);
477 stack.PushTransform(screenScaleMatrix);
478 // Push backdrop filters
479 for (int i = 0; i < 50; i++) {
480 auto filter = std::make_shared<flutter::DlBlurImageFilter>(i, 2, flutter::DlTileMode::kClamp);
481 stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
482 }
483
484 auto embeddedViewParams =
485 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(20, 20), stack);
486
487 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
488 flutterPlatformViewsController->CompositeEmbeddedView(2);
489 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
490 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
491 [mockFlutterView addSubview:childClippingView];
492
493 [mockFlutterView setNeedsLayout];
494 [mockFlutterView layoutIfNeeded];
495
496 NSUInteger numberOfExpectedVisualEffectView = 0;
497 for (UIView* subview in childClippingView.subviews) {
498 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
499 continue;
500 }
501 XCTAssertLessThan(numberOfExpectedVisualEffectView, 50u);
502 if ([self validateOneVisualEffectView:subview
503 expectedFrame:CGRectMake(0, 0, 10, 10)
504 inputRadius:(CGFloat)numberOfExpectedVisualEffectView]) {
505 numberOfExpectedVisualEffectView++;
506 }
507 }
508 XCTAssertEqual(numberOfExpectedVisualEffectView, (NSUInteger)numberOfExpectedVisualEffectView);
509}
510
512 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
513 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
514 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
515 /*platform=*/thread_task_runner,
516 /*raster=*/thread_task_runner,
517 /*ui=*/thread_task_runner,
518 /*io=*/thread_task_runner);
519 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
520 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
521 /*delegate=*/mock_delegate,
522 /*rendering_api=*/mock_delegate.settings_.enable_impeller
525 /*platform_views_controller=*/flutterPlatformViewsController,
526 /*task_runners=*/runners,
527 /*worker_task_runner=*/nil,
528 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
529
532 flutterPlatformViewsController->RegisterViewFactory(
533 factory, @"MockFlutterPlatformView",
535 FlutterResult result = ^(id result) {
536 };
537 flutterPlatformViewsController->OnMethodCall(
539 methodCallWithMethodName:@"create"
540 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
541 result);
542
543 XCTAssertNotNil(gMockPlatformView);
544
545 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
546 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
547 // Create embedded view params
549 // Layer tree always pushes a screen scale factor to the stack
550 CGFloat screenScale = [UIScreen mainScreen].scale;
551 SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale);
552 stack.PushTransform(screenScaleMatrix);
553 // Push a backdrop filter
554 auto filter = std::make_shared<flutter::DlBlurImageFilter>(5, 2, flutter::DlTileMode::kClamp);
555 stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
556
557 auto embeddedViewParams =
558 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
559
560 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
561 flutterPlatformViewsController->CompositeEmbeddedView(2);
562 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]);
563 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
564 [mockFlutterView addSubview:childClippingView];
565
566 [mockFlutterView setNeedsLayout];
567 [mockFlutterView layoutIfNeeded];
568
569 NSMutableArray* originalVisualEffectViews = [[NSMutableArray alloc] init];
570 for (UIView* subview in childClippingView.subviews) {
571 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
572 continue;
573 }
574 XCTAssertLessThan(originalVisualEffectViews.count, 1u);
575 if ([self validateOneVisualEffectView:subview
576 expectedFrame:CGRectMake(0, 0, 10, 10)
577 inputRadius:(CGFloat)5]) {
578 [originalVisualEffectViews addObject:subview];
579 }
580 }
581 XCTAssertEqual(originalVisualEffectViews.count, 1u);
582
583 //
584 // Simulate adding 1 backdrop filter (create a new mutators stack)
585 // Create embedded view params
587 // Layer tree always pushes a screen scale factor to the stack
588 stack2.PushTransform(screenScaleMatrix);
589 // Push backdrop filters
590 for (int i = 0; i < 2; i++) {
591 stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
592 }
593
594 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
595 SkSize::Make(10, 10), stack2);
596
597 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
598 flutterPlatformViewsController->CompositeEmbeddedView(2);
599 [mockFlutterView setNeedsLayout];
600 [mockFlutterView layoutIfNeeded];
601
602 NSMutableArray* newVisualEffectViews = [[NSMutableArray alloc] init];
603 for (UIView* subview in childClippingView.subviews) {
604 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
605 continue;
606 }
607 XCTAssertLessThan(newVisualEffectViews.count, 2u);
608
609 if ([self validateOneVisualEffectView:subview
610 expectedFrame:CGRectMake(0, 0, 10, 10)
611 inputRadius:(CGFloat)5]) {
612 [newVisualEffectViews addObject:subview];
613 }
614 }
615 XCTAssertEqual(newVisualEffectViews.count, 2u);
616 for (NSUInteger i = 0; i < originalVisualEffectViews.count; i++) {
617 UIView* originalView = originalVisualEffectViews[i];
618 UIView* newView = newVisualEffectViews[i];
619 // Compare reference.
620 XCTAssertEqual(originalView, newView);
621 id mockOrignalView = OCMPartialMock(originalView);
622 OCMReject([mockOrignalView removeFromSuperview]);
623 [mockOrignalView stopMocking];
624 }
625}
626
628 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
629 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
630 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
631 /*platform=*/thread_task_runner,
632 /*raster=*/thread_task_runner,
633 /*ui=*/thread_task_runner,
634 /*io=*/thread_task_runner);
635 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
636 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
637 /*delegate=*/mock_delegate,
638 /*rendering_api=*/mock_delegate.settings_.enable_impeller
641 /*platform_views_controller=*/flutterPlatformViewsController,
642 /*task_runners=*/runners,
643 /*worker_task_runner=*/nil,
644 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
645
648 flutterPlatformViewsController->RegisterViewFactory(
649 factory, @"MockFlutterPlatformView",
651 FlutterResult result = ^(id result) {
652 };
653 flutterPlatformViewsController->OnMethodCall(
655 methodCallWithMethodName:@"create"
656 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
657 result);
658
659 XCTAssertNotNil(gMockPlatformView);
660
661 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
662 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
663 // Create embedded view params
665 // Layer tree always pushes a screen scale factor to the stack
666 CGFloat screenScale = [UIScreen mainScreen].scale;
667 SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale);
668 stack.PushTransform(screenScaleMatrix);
669 // Push backdrop filters
670 auto filter = std::make_shared<flutter::DlBlurImageFilter>(5, 2, flutter::DlTileMode::kClamp);
671 for (int i = 0; i < 5; i++) {
672 stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
673 }
674
675 auto embeddedViewParams =
676 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
677
678 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
679 flutterPlatformViewsController->CompositeEmbeddedView(2);
680 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
681 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
682 [mockFlutterView addSubview:childClippingView];
683
684 [mockFlutterView setNeedsLayout];
685 [mockFlutterView layoutIfNeeded];
686
687 NSMutableArray* originalVisualEffectViews = [[NSMutableArray alloc] init];
688 for (UIView* subview in childClippingView.subviews) {
689 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
690 continue;
691 }
692 XCTAssertLessThan(originalVisualEffectViews.count, 5u);
693 if ([self validateOneVisualEffectView:subview
694 expectedFrame:CGRectMake(0, 0, 10, 10)
695 inputRadius:(CGFloat)5]) {
696 [originalVisualEffectViews addObject:subview];
697 }
698 }
699
700 // Simulate removing 1 backdrop filter (create a new mutators stack)
701 // Create embedded view params
703 // Layer tree always pushes a screen scale factor to the stack
704 stack2.PushTransform(screenScaleMatrix);
705 // Push backdrop filters
706 for (int i = 0; i < 4; i++) {
707 stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
708 }
709
710 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
711 SkSize::Make(10, 10), stack2);
712
713 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
714 flutterPlatformViewsController->CompositeEmbeddedView(2);
715 [mockFlutterView setNeedsLayout];
716 [mockFlutterView layoutIfNeeded];
717
718 NSMutableArray* newVisualEffectViews = [[NSMutableArray alloc] init];
719 for (UIView* subview in childClippingView.subviews) {
720 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
721 continue;
722 }
723 XCTAssertLessThan(newVisualEffectViews.count, 4u);
724 if ([self validateOneVisualEffectView:subview
725 expectedFrame:CGRectMake(0, 0, 10, 10)
726 inputRadius:(CGFloat)5]) {
727 [newVisualEffectViews addObject:subview];
728 }
729 }
730 XCTAssertEqual(newVisualEffectViews.count, 4u);
731
732 for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
733 UIView* newView = newVisualEffectViews[i];
734 id mockNewView = OCMPartialMock(newView);
735 UIView* originalView = originalVisualEffectViews[i];
736 // Compare reference.
737 XCTAssertEqual(originalView, newView);
738 OCMReject([mockNewView removeFromSuperview]);
739 [mockNewView stopMocking];
740 }
741
742 // Simulate removing all backdrop filters (replace the mutators stack)
743 // Update embedded view params, delete except screenScaleMatrix
744 for (int i = 0; i < 5; i++) {
745 stack2.Pop();
746 }
747 // No backdrop filters in the stack, so no nothing to push
748
749 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
750 SkSize::Make(10, 10), stack2);
751
752 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
753 flutterPlatformViewsController->CompositeEmbeddedView(2);
754 [mockFlutterView setNeedsLayout];
755 [mockFlutterView layoutIfNeeded];
756
757 NSUInteger numberOfExpectedVisualEffectView = 0u;
758 for (UIView* subview in childClippingView.subviews) {
759 if ([subview isKindOfClass:[UIVisualEffectView class]]) {
760 numberOfExpectedVisualEffectView++;
761 }
762 }
763 XCTAssertEqual(numberOfExpectedVisualEffectView, 0u);
764}
765
767 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
768 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
769 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
770 /*platform=*/thread_task_runner,
771 /*raster=*/thread_task_runner,
772 /*ui=*/thread_task_runner,
773 /*io=*/thread_task_runner);
774 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
775 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
776 /*delegate=*/mock_delegate,
777 /*rendering_api=*/mock_delegate.settings_.enable_impeller
780 /*platform_views_controller=*/flutterPlatformViewsController,
781 /*task_runners=*/runners,
782 /*worker_task_runner=*/nil,
783 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
784
787 flutterPlatformViewsController->RegisterViewFactory(
788 factory, @"MockFlutterPlatformView",
790 FlutterResult result = ^(id result) {
791 };
792 flutterPlatformViewsController->OnMethodCall(
794 methodCallWithMethodName:@"create"
795 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
796 result);
797
798 XCTAssertNotNil(gMockPlatformView);
799
800 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
801 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
802 // Create embedded view params
804 // Layer tree always pushes a screen scale factor to the stack
805 CGFloat screenScale = [UIScreen mainScreen].scale;
806 SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale);
807 stack.PushTransform(screenScaleMatrix);
808 // Push backdrop filters
809 auto filter = std::make_shared<flutter::DlBlurImageFilter>(5, 2, flutter::DlTileMode::kClamp);
810 for (int i = 0; i < 5; i++) {
811 stack.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
812 }
813
814 auto embeddedViewParams =
815 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
816
817 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
818 flutterPlatformViewsController->CompositeEmbeddedView(2);
819 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
820 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
821 [mockFlutterView addSubview:childClippingView];
822
823 [mockFlutterView setNeedsLayout];
824 [mockFlutterView layoutIfNeeded];
825
826 NSMutableArray* originalVisualEffectViews = [[NSMutableArray alloc] init];
827 for (UIView* subview in childClippingView.subviews) {
828 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
829 continue;
830 }
831 XCTAssertLessThan(originalVisualEffectViews.count, 5u);
832 if ([self validateOneVisualEffectView:subview
833 expectedFrame:CGRectMake(0, 0, 10, 10)
834 inputRadius:(CGFloat)5]) {
835 [originalVisualEffectViews addObject:subview];
836 }
837 }
838
839 // Simulate editing 1 backdrop filter in the middle of the stack (create a new mutators stack)
840 // Create embedded view params
842 // Layer tree always pushes a screen scale factor to the stack
843 stack2.PushTransform(screenScaleMatrix);
844 // Push backdrop filters
845 for (int i = 0; i < 5; i++) {
846 if (i == 3) {
847 auto filter2 =
848 std::make_shared<flutter::DlBlurImageFilter>(2, 5, flutter::DlTileMode::kClamp);
849
850 stack2.PushBackdropFilter(filter2,
851 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
852 continue;
853 }
854
855 stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
856 }
857
858 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
859 SkSize::Make(10, 10), stack2);
860
861 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
862 flutterPlatformViewsController->CompositeEmbeddedView(2);
863 [mockFlutterView setNeedsLayout];
864 [mockFlutterView layoutIfNeeded];
865
866 NSMutableArray* newVisualEffectViews = [[NSMutableArray alloc] init];
867 for (UIView* subview in childClippingView.subviews) {
868 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
869 continue;
870 }
871 XCTAssertLessThan(newVisualEffectViews.count, 5u);
872 CGFloat expectInputRadius = 5;
873 if (newVisualEffectViews.count == 3) {
874 expectInputRadius = 2;
875 }
876 if ([self validateOneVisualEffectView:subview
877 expectedFrame:CGRectMake(0, 0, 10, 10)
878 inputRadius:(CGFloat)expectInputRadius]) {
879 [newVisualEffectViews addObject:subview];
880 }
881 }
882 XCTAssertEqual(newVisualEffectViews.count, 5u);
883 for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
884 UIView* newView = newVisualEffectViews[i];
885 id mockNewView = OCMPartialMock(newView);
886 UIView* originalView = originalVisualEffectViews[i];
887 // Compare reference.
888 XCTAssertEqual(originalView, newView);
889 OCMReject([mockNewView removeFromSuperview]);
890 [mockNewView stopMocking];
891 }
892 [newVisualEffectViews removeAllObjects];
893
894 // Simulate editing 1 backdrop filter in the beginning of the stack (replace the mutators stack)
895 // Update embedded view params, delete except screenScaleMatrix
896 for (int i = 0; i < 5; i++) {
897 stack2.Pop();
898 }
899 // Push backdrop filters
900 for (int i = 0; i < 5; i++) {
901 if (i == 0) {
902 auto filter2 =
903 std::make_shared<flutter::DlBlurImageFilter>(2, 5, flutter::DlTileMode::kClamp);
904 stack2.PushBackdropFilter(filter2,
905 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
906 continue;
907 }
908
909 stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
910 }
911
912 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
913 SkSize::Make(10, 10), stack2);
914
915 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
916 flutterPlatformViewsController->CompositeEmbeddedView(2);
917 [mockFlutterView setNeedsLayout];
918 [mockFlutterView layoutIfNeeded];
919
920 for (UIView* subview in childClippingView.subviews) {
921 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
922 continue;
923 }
924 XCTAssertLessThan(newVisualEffectViews.count, 5u);
925 CGFloat expectInputRadius = 5;
926 if (newVisualEffectViews.count == 0) {
927 expectInputRadius = 2;
928 }
929 if ([self validateOneVisualEffectView:subview
930 expectedFrame:CGRectMake(0, 0, 10, 10)
931 inputRadius:(CGFloat)expectInputRadius]) {
932 [newVisualEffectViews addObject:subview];
933 }
934 }
935 for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
936 UIView* newView = newVisualEffectViews[i];
937 id mockNewView = OCMPartialMock(newView);
938 UIView* originalView = originalVisualEffectViews[i];
939 // Compare reference.
940 XCTAssertEqual(originalView, newView);
941 OCMReject([mockNewView removeFromSuperview]);
942 [mockNewView stopMocking];
943 }
944 [newVisualEffectViews removeAllObjects];
945
946 // Simulate editing 1 backdrop filter in the end of the stack (replace the mutators stack)
947 // Update embedded view params, delete except screenScaleMatrix
948 for (int i = 0; i < 5; i++) {
949 stack2.Pop();
950 }
951 // Push backdrop filters
952 for (int i = 0; i < 5; i++) {
953 if (i == 4) {
954 auto filter2 =
955 std::make_shared<flutter::DlBlurImageFilter>(2, 5, flutter::DlTileMode::kClamp);
956 stack2.PushBackdropFilter(filter2,
957 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
958 continue;
959 }
960
961 stack2.PushBackdropFilter(filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
962 }
963
964 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
965 SkSize::Make(10, 10), stack2);
966
967 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
968 flutterPlatformViewsController->CompositeEmbeddedView(2);
969 [mockFlutterView setNeedsLayout];
970 [mockFlutterView layoutIfNeeded];
971
972 for (UIView* subview in childClippingView.subviews) {
973 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
974 continue;
975 }
976 XCTAssertLessThan(newVisualEffectViews.count, 5u);
977 CGFloat expectInputRadius = 5;
978 if (newVisualEffectViews.count == 4) {
979 expectInputRadius = 2;
980 }
981 if ([self validateOneVisualEffectView:subview
982 expectedFrame:CGRectMake(0, 0, 10, 10)
983 inputRadius:(CGFloat)expectInputRadius]) {
984 [newVisualEffectViews addObject:subview];
985 }
986 }
987 XCTAssertEqual(newVisualEffectViews.count, 5u);
988
989 for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
990 UIView* newView = newVisualEffectViews[i];
991 id mockNewView = OCMPartialMock(newView);
992 UIView* originalView = originalVisualEffectViews[i];
993 // Compare reference.
994 XCTAssertEqual(originalView, newView);
995 OCMReject([mockNewView removeFromSuperview]);
996 [mockNewView stopMocking];
997 }
998 [newVisualEffectViews removeAllObjects];
999
1000 // Simulate editing all backdrop filters in the stack (replace the mutators stack)
1001 // Update embedded view params, delete except screenScaleMatrix
1002 for (int i = 0; i < 5; i++) {
1003 stack2.Pop();
1004 }
1005 // Push backdrop filters
1006 for (int i = 0; i < 5; i++) {
1007 auto filter2 = std::make_shared<flutter::DlBlurImageFilter>(i, 2, flutter::DlTileMode::kClamp);
1008
1009 stack2.PushBackdropFilter(filter2, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
1010 }
1011
1012 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
1013 SkSize::Make(10, 10), stack2);
1014
1015 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1016 flutterPlatformViewsController->CompositeEmbeddedView(2);
1017 [mockFlutterView setNeedsLayout];
1018 [mockFlutterView layoutIfNeeded];
1019
1020 for (UIView* subview in childClippingView.subviews) {
1021 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
1022 continue;
1023 }
1024 XCTAssertLessThan(newVisualEffectViews.count, 5u);
1025 if ([self validateOneVisualEffectView:subview
1026 expectedFrame:CGRectMake(0, 0, 10, 10)
1027 inputRadius:(CGFloat)newVisualEffectViews.count]) {
1028 [newVisualEffectViews addObject:subview];
1029 }
1030 }
1031 XCTAssertEqual(newVisualEffectViews.count, 5u);
1032
1033 for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
1034 UIView* newView = newVisualEffectViews[i];
1035 id mockNewView = OCMPartialMock(newView);
1036 UIView* originalView = originalVisualEffectViews[i];
1037 // Compare reference.
1038 XCTAssertEqual(originalView, newView);
1039 OCMReject([mockNewView removeFromSuperview]);
1040 [mockNewView stopMocking];
1041 }
1042 [newVisualEffectViews removeAllObjects];
1043}
1044
1046 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1047 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1048 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1049 /*platform=*/thread_task_runner,
1050 /*raster=*/thread_task_runner,
1051 /*ui=*/thread_task_runner,
1052 /*io=*/thread_task_runner);
1053 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
1054 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1055 /*delegate=*/mock_delegate,
1056 /*rendering_api=*/mock_delegate.settings_.enable_impeller
1059 /*platform_views_controller=*/flutterPlatformViewsController,
1060 /*task_runners=*/runners,
1061 /*worker_task_runner=*/nil,
1062 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
1063
1066 flutterPlatformViewsController->RegisterViewFactory(
1067 factory, @"MockFlutterPlatformView",
1069 FlutterResult result = ^(id result) {
1070 };
1071 flutterPlatformViewsController->OnMethodCall(
1073 methodCallWithMethodName:@"create"
1074 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
1075 result);
1076
1077 XCTAssertNotNil(gMockPlatformView);
1078
1079 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
1080 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
1081 // Create embedded view params
1083 // Layer tree always pushes a screen scale factor to the stack
1084 CGFloat screenScale = [UIScreen mainScreen].scale;
1085 SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale);
1086 stack.PushTransform(screenScaleMatrix);
1087 // Push a dilate backdrop filter
1088 auto dilateFilter = std::make_shared<flutter::DlDilateImageFilter>(5, 2);
1089 stack.PushBackdropFilter(dilateFilter, SkRect::MakeEmpty());
1090
1091 auto embeddedViewParams =
1092 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
1093
1094 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1095 flutterPlatformViewsController->CompositeEmbeddedView(2);
1096 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]);
1097 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
1098
1099 [mockFlutterView addSubview:childClippingView];
1100
1101 [mockFlutterView setNeedsLayout];
1102 [mockFlutterView layoutIfNeeded];
1103
1104 NSUInteger numberOfExpectedVisualEffectView = 0;
1105 for (UIView* subview in childClippingView.subviews) {
1106 if ([subview isKindOfClass:[UIVisualEffectView class]]) {
1107 numberOfExpectedVisualEffectView++;
1108 }
1109 }
1110 XCTAssertEqual(numberOfExpectedVisualEffectView, 0u);
1111
1112 // Simulate adding a non-DlBlurImageFilter in the middle of the stack (create a new mutators
1113 // stack) Create embedded view params
1115 // Layer tree always pushes a screen scale factor to the stack
1116 stack2.PushTransform(screenScaleMatrix);
1117 // Push backdrop filters and dilate filter
1118 auto blurFilter = std::make_shared<flutter::DlBlurImageFilter>(5, 2, flutter::DlTileMode::kClamp);
1119
1120 for (int i = 0; i < 5; i++) {
1121 if (i == 2) {
1122 stack2.PushBackdropFilter(dilateFilter,
1123 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
1124 continue;
1125 }
1126
1127 stack2.PushBackdropFilter(blurFilter,
1128 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
1129 }
1130
1131 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
1132 SkSize::Make(10, 10), stack2);
1133
1134 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1135 flutterPlatformViewsController->CompositeEmbeddedView(2);
1136 [mockFlutterView setNeedsLayout];
1137 [mockFlutterView layoutIfNeeded];
1138
1139 numberOfExpectedVisualEffectView = 0;
1140 for (UIView* subview in childClippingView.subviews) {
1141 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
1142 continue;
1143 }
1144 XCTAssertLessThan(numberOfExpectedVisualEffectView, 4u);
1145 if ([self validateOneVisualEffectView:subview
1146 expectedFrame:CGRectMake(0, 0, 10, 10)
1147 inputRadius:(CGFloat)5]) {
1148 numberOfExpectedVisualEffectView++;
1149 }
1150 }
1151 XCTAssertEqual(numberOfExpectedVisualEffectView, 4u);
1152
1153 // Simulate adding a non-DlBlurImageFilter to the beginning of the stack (replace the mutators
1154 // stack) Update embedded view params, delete except screenScaleMatrix
1155 for (int i = 0; i < 5; i++) {
1156 stack2.Pop();
1157 }
1158 // Push backdrop filters and dilate filter
1159 for (int i = 0; i < 5; i++) {
1160 if (i == 0) {
1161 stack2.PushBackdropFilter(dilateFilter,
1162 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
1163 continue;
1164 }
1165
1166 stack2.PushBackdropFilter(blurFilter,
1167 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
1168 }
1169
1170 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
1171 SkSize::Make(10, 10), stack2);
1172
1173 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1174 flutterPlatformViewsController->CompositeEmbeddedView(2);
1175 [mockFlutterView setNeedsLayout];
1176 [mockFlutterView layoutIfNeeded];
1177
1178 numberOfExpectedVisualEffectView = 0;
1179 for (UIView* subview in childClippingView.subviews) {
1180 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
1181 continue;
1182 }
1183 XCTAssertLessThan(numberOfExpectedVisualEffectView, 4u);
1184 if ([self validateOneVisualEffectView:subview
1185 expectedFrame:CGRectMake(0, 0, 10, 10)
1186 inputRadius:(CGFloat)5]) {
1187 numberOfExpectedVisualEffectView++;
1188 }
1189 }
1190 XCTAssertEqual(numberOfExpectedVisualEffectView, 4u);
1191
1192 // Simulate adding a non-DlBlurImageFilter to the end of the stack (replace the mutators stack)
1193 // Update embedded view params, delete except screenScaleMatrix
1194 for (int i = 0; i < 5; i++) {
1195 stack2.Pop();
1196 }
1197 // Push backdrop filters and dilate filter
1198 for (int i = 0; i < 5; i++) {
1199 if (i == 4) {
1200 stack2.PushBackdropFilter(dilateFilter,
1201 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
1202 continue;
1203 }
1204
1205 stack2.PushBackdropFilter(blurFilter,
1206 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
1207 }
1208
1209 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
1210 SkSize::Make(10, 10), stack2);
1211
1212 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1213 flutterPlatformViewsController->CompositeEmbeddedView(2);
1214 [mockFlutterView setNeedsLayout];
1215 [mockFlutterView layoutIfNeeded];
1216
1217 numberOfExpectedVisualEffectView = 0;
1218 for (UIView* subview in childClippingView.subviews) {
1219 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
1220 continue;
1221 }
1222 XCTAssertLessThan(numberOfExpectedVisualEffectView, 4u);
1223 if ([self validateOneVisualEffectView:subview
1224 expectedFrame:CGRectMake(0, 0, 10, 10)
1225 inputRadius:(CGFloat)5]) {
1226 numberOfExpectedVisualEffectView++;
1227 }
1228 }
1229 XCTAssertEqual(numberOfExpectedVisualEffectView, 4u);
1230
1231 // Simulate adding only non-DlBlurImageFilter to the stack (replace the mutators stack)
1232 // Update embedded view params, delete except screenScaleMatrix
1233 for (int i = 0; i < 5; i++) {
1234 stack2.Pop();
1235 }
1236 // Push dilate filters
1237 for (int i = 0; i < 5; i++) {
1238 stack2.PushBackdropFilter(dilateFilter,
1239 SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
1240 }
1241
1242 embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix,
1243 SkSize::Make(10, 10), stack2);
1244
1245 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1246 flutterPlatformViewsController->CompositeEmbeddedView(2);
1247 [mockFlutterView setNeedsLayout];
1248 [mockFlutterView layoutIfNeeded];
1249
1250 numberOfExpectedVisualEffectView = 0;
1251 for (UIView* subview in childClippingView.subviews) {
1252 if ([subview isKindOfClass:[UIVisualEffectView class]]) {
1253 numberOfExpectedVisualEffectView++;
1254 }
1255 }
1256 XCTAssertEqual(numberOfExpectedVisualEffectView, 0u);
1257}
1258
1261 // The gaussianBlur filter is extracted from UIVisualEffectView.
1262 // Each test requires a new PlatformViewFilter
1263 // Valid UIVisualEffectView API
1264 UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc]
1265 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
1266 PlatformViewFilter* platformViewFilter =
1267 [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
1268 blurRadius:5
1269 visualEffectView:visualEffectView];
1270 XCTAssertNotNil(platformViewFilter);
1271}
1272
1275 UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc] init];
1276 PlatformViewFilter* platformViewFilter =
1277 [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
1278 blurRadius:5
1279 visualEffectView:visualEffectView];
1280 XCTAssertNil(platformViewFilter);
1281}
1282
1285 UIVisualEffectView* editedUIVisualEffectView = [[UIVisualEffectView alloc]
1286 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
1287 NSArray* subviews = editedUIVisualEffectView.subviews;
1288 for (UIView* view in subviews) {
1289 if ([NSStringFromClass([view class]) hasSuffix:@"BackdropView"]) {
1290 for (CIFilter* filter in view.layer.filters) {
1291 if ([[filter valueForKey:@"name"] isEqual:@"gaussianBlur"]) {
1292 [filter setValue:@"notGaussianBlur" forKey:@"name"];
1293 break;
1294 }
1295 }
1296 break;
1297 }
1298 }
1299 PlatformViewFilter* platformViewFilter =
1300 [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
1301 blurRadius:5
1302 visualEffectView:editedUIVisualEffectView];
1303 XCTAssertNil(platformViewFilter);
1304}
1305
1308 UIVisualEffectView* editedUIVisualEffectView = [[UIVisualEffectView alloc]
1309 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
1310 NSArray* subviews = editedUIVisualEffectView.subviews;
1311 for (UIView* view in subviews) {
1312 if ([NSStringFromClass([view class]) hasSuffix:@"BackdropView"]) {
1313 for (CIFilter* filter in view.layer.filters) {
1314 if ([[filter valueForKey:@"name"] isEqual:@"gaussianBlur"]) {
1315 [filter setValue:@"invalidInputRadius" forKey:@"inputRadius"];
1316 break;
1317 }
1318 }
1319 break;
1320 }
1321 }
1322
1323 PlatformViewFilter* platformViewFilter =
1324 [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
1325 blurRadius:5
1326 visualEffectView:editedUIVisualEffectView];
1327 XCTAssertNil(platformViewFilter);
1328}
1329
1331 __weak UIVisualEffectView* weakVisualEffectView;
1332
1333 @autoreleasepool {
1334 UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc]
1335 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
1336 weakVisualEffectView = visualEffectView;
1337 PlatformViewFilter* platformViewFilter =
1338 [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
1339 blurRadius:5
1340 visualEffectView:visualEffectView];
1341 CGColorRef visualEffectSubviewBackgroundColor = nil;
1342 for (UIView* view in [platformViewFilter backdropFilterView].subviews) {
1343 if ([NSStringFromClass([view class]) hasSuffix:@"VisualEffectSubview"]) {
1344 visualEffectSubviewBackgroundColor = view.layer.backgroundColor;
1345 }
1346 }
1347 XCTAssertTrue(
1348 CGColorEqualToColor(visualEffectSubviewBackgroundColor, UIColor.clearColor.CGColor));
1349 }
1350 XCTAssertNil(weakVisualEffectView);
1351}
1352
1354 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1355 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1356 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1357 /*platform=*/thread_task_runner,
1358 /*raster=*/thread_task_runner,
1359 /*ui=*/thread_task_runner,
1360 /*io=*/thread_task_runner);
1361 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
1362 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1363 /*delegate=*/mock_delegate,
1364 /*rendering_api=*/mock_delegate.settings_.enable_impeller
1367 /*platform_views_controller=*/flutterPlatformViewsController,
1368 /*task_runners=*/runners,
1369 /*worker_task_runner=*/nil,
1370 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
1371
1374 flutterPlatformViewsController->RegisterViewFactory(
1375 factory, @"MockFlutterPlatformView",
1377 FlutterResult result = ^(id result) {
1378 };
1379 flutterPlatformViewsController->OnMethodCall(
1381 methodCallWithMethodName:@"create"
1382 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
1383 result);
1384
1385 XCTAssertNotNil(gMockPlatformView);
1386
1387 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
1388 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
1389 // Create embedded view params
1391 // Layer tree always pushes a screen scale factor to the stack
1392 SkMatrix screenScaleMatrix =
1393 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
1394 stack.PushTransform(screenScaleMatrix);
1395 // Push a translate matrix
1396 SkMatrix translateMatrix = SkMatrix::Translate(100, 100);
1397 stack.PushTransform(translateMatrix);
1398 SkMatrix finalMatrix;
1399 finalMatrix.setConcat(screenScaleMatrix, translateMatrix);
1400
1401 auto embeddedViewParams =
1402 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
1403
1404 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1405 flutterPlatformViewsController->CompositeEmbeddedView(2);
1406 CGRect platformViewRectInFlutterView = [gMockPlatformView convertRect:gMockPlatformView.bounds
1407 toView:mockFlutterView];
1408 XCTAssertTrue(CGRectEqualToRect(platformViewRectInFlutterView, CGRectMake(100, 100, 300, 300)));
1409}
1410
1412 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1413 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1414 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1415 /*platform=*/thread_task_runner,
1416 /*raster=*/thread_task_runner,
1417 /*ui=*/thread_task_runner,
1418 /*io=*/thread_task_runner);
1419 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
1420 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1421 /*delegate=*/mock_delegate,
1422 /*rendering_api=*/mock_delegate.settings_.enable_impeller
1425 /*platform_views_controller=*/flutterPlatformViewsController,
1426 /*task_runners=*/runners,
1427 /*worker_task_runner=*/nil,
1428 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
1429
1432 flutterPlatformViewsController->RegisterViewFactory(
1433 factory, @"MockFlutterPlatformView",
1435 FlutterResult result = ^(id result) {
1436 };
1437 flutterPlatformViewsController->OnMethodCall(
1439 methodCallWithMethodName:@"create"
1440 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
1441 result);
1442
1443 XCTAssertNotNil(gMockPlatformView);
1444
1445 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
1446 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
1447 // Create embedded view params
1449 // Layer tree always pushes a screen scale factor to the stack
1450 CGFloat screenScale = [UIScreen mainScreen].scale;
1451 SkMatrix screenScaleMatrix = SkMatrix::Scale(screenScale, screenScale);
1452 stack.PushTransform(screenScaleMatrix);
1453
1454 auto embeddedViewParams =
1455 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
1456
1457 flutterPlatformViewsController->BeginFrame(SkISize::Make(0, 0));
1458 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1459 flutterPlatformViewsController->PushVisitedPlatformView(2);
1460 auto filter = std::make_shared<flutter::DlBlurImageFilter>(5, 2, flutter::DlTileMode::kClamp);
1461 flutterPlatformViewsController->PushFilterToVisitedPlatformViews(
1462 filter, SkRect::MakeXYWH(0, 0, screenScale * 10, screenScale * 10));
1463 flutterPlatformViewsController->CompositeEmbeddedView(2);
1464 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]);
1465 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
1466 [mockFlutterView addSubview:childClippingView];
1467
1468 [mockFlutterView setNeedsLayout];
1469 [mockFlutterView layoutIfNeeded];
1470
1471 // childClippingView has visual effect view with the correct configurations.
1472 NSUInteger numberOfExpectedVisualEffectView = 0;
1473 for (UIView* subview in childClippingView.subviews) {
1474 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
1475 continue;
1476 }
1477 XCTAssertLessThan(numberOfExpectedVisualEffectView, 1u);
1478 if ([self validateOneVisualEffectView:subview
1479 expectedFrame:CGRectMake(0, 0, 10, 10)
1480 inputRadius:5]) {
1481 numberOfExpectedVisualEffectView++;
1482 }
1483 }
1484 XCTAssertEqual(numberOfExpectedVisualEffectView, 1u);
1485
1486 // New frame, with no filter pushed.
1487 auto embeddedViewParams2 =
1488 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
1489 flutterPlatformViewsController->BeginFrame(SkISize::Make(0, 0));
1490 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams2));
1491 flutterPlatformViewsController->CompositeEmbeddedView(2);
1492 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:[ChildClippingView class]]);
1493
1494 [mockFlutterView setNeedsLayout];
1495 [mockFlutterView layoutIfNeeded];
1496
1497 numberOfExpectedVisualEffectView = 0;
1498 for (UIView* subview in childClippingView.subviews) {
1499 if (![subview isKindOfClass:[UIVisualEffectView class]]) {
1500 continue;
1501 }
1502 numberOfExpectedVisualEffectView++;
1503 }
1504 XCTAssertEqual(numberOfExpectedVisualEffectView, 0u);
1505}
1506
1508 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1509 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1510 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1511 /*platform=*/thread_task_runner,
1512 /*raster=*/thread_task_runner,
1513 /*ui=*/thread_task_runner,
1514 /*io=*/thread_task_runner);
1515 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
1516 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1517 /*delegate=*/mock_delegate,
1518 /*rendering_api=*/mock_delegate.settings_.enable_impeller
1521 /*platform_views_controller=*/flutterPlatformViewsController,
1522 /*task_runners=*/runners,
1523 /*worker_task_runner=*/nil,
1524 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
1525
1528 flutterPlatformViewsController->RegisterViewFactory(
1529 factory, @"MockFlutterPlatformView",
1531 FlutterResult result = ^(id result) {
1532 };
1533 flutterPlatformViewsController->OnMethodCall(
1535 methodCallWithMethodName:@"create"
1536 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
1537 result);
1538
1539 XCTAssertNotNil(gMockPlatformView);
1540
1541 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
1542 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
1543 // Create embedded view params
1545 // Layer tree always pushes a screen scale factor to the stack
1546 SkMatrix screenScaleMatrix =
1547 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
1548 stack.PushTransform(screenScaleMatrix);
1549 // Push a rotate matrix
1550 SkMatrix rotateMatrix;
1551 rotateMatrix.setRotate(10);
1552 stack.PushTransform(rotateMatrix);
1553 SkMatrix finalMatrix;
1554 finalMatrix.setConcat(screenScaleMatrix, rotateMatrix);
1555
1556 auto embeddedViewParams =
1557 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
1558
1559 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1560 flutterPlatformViewsController->CompositeEmbeddedView(2);
1561 CGRect platformViewRectInFlutterView = [gMockPlatformView convertRect:gMockPlatformView.bounds
1562 toView:mockFlutterView];
1563 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
1564 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
1565 // The childclippingview's frame is set based on flow, but the platform view's frame is set based
1566 // on quartz. Although they should be the same, but we should tolerate small floating point
1567 // errors.
1568 XCTAssertLessThan(fabs(platformViewRectInFlutterView.origin.x - childClippingView.frame.origin.x),
1570 XCTAssertLessThan(fabs(platformViewRectInFlutterView.origin.y - childClippingView.frame.origin.y),
1572 XCTAssertLessThan(
1573 fabs(platformViewRectInFlutterView.size.width - childClippingView.frame.size.width),
1575 XCTAssertLessThan(
1576 fabs(platformViewRectInFlutterView.size.height - childClippingView.frame.size.height),
1578}
1579
1581 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1582 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1583 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1584 /*platform=*/thread_task_runner,
1585 /*raster=*/thread_task_runner,
1586 /*ui=*/thread_task_runner,
1587 /*io=*/thread_task_runner);
1588 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
1589 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1590 /*delegate=*/mock_delegate,
1591 /*rendering_api=*/mock_delegate.settings_.enable_impeller
1594 /*platform_views_controller=*/flutterPlatformViewsController,
1595 /*task_runners=*/runners,
1596 /*worker_task_runner=*/nil,
1597 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
1598
1601 flutterPlatformViewsController->RegisterViewFactory(
1602 factory, @"MockFlutterPlatformView",
1604 FlutterResult result = ^(id result) {
1605 };
1606 flutterPlatformViewsController->OnMethodCall(
1608 methodCallWithMethodName:@"create"
1609 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
1610 result);
1611
1612 XCTAssertNotNil(gMockPlatformView);
1613
1614 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
1615 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
1616 // Create embedded view params.
1618 // Layer tree always pushes a screen scale factor to the stack.
1619 SkMatrix screenScaleMatrix =
1620 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
1621 stack.PushTransform(screenScaleMatrix);
1622 SkMatrix translateMatrix = SkMatrix::Translate(5, 5);
1623 // The platform view's rect for this test will be (5, 5, 10, 10).
1624 stack.PushTransform(translateMatrix);
1625 // Push a clip rect, big enough to contain the entire platform view bound.
1626 SkRect rect = SkRect::MakeXYWH(0, 0, 25, 25);
1627 stack.PushClipRect(rect);
1628 // Push a clip rrect, big enough to contain the entire platform view bound without clipping it.
1629 // Make the origin (-1, -1) so that the top left rounded corner isn't clipping the PlatformView.
1630 SkRect rect_for_rrect = SkRect::MakeXYWH(-1, -1, 25, 25);
1631 SkRRect rrect = SkRRect::MakeRectXY(rect_for_rrect, 1, 1);
1632 stack.PushClipRRect(rrect);
1633
1634 auto embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(
1635 SkMatrix::Concat(screenScaleMatrix, translateMatrix), SkSize::Make(5, 5), stack);
1636
1637 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1638 flutterPlatformViewsController->CompositeEmbeddedView(2);
1639 gMockPlatformView.backgroundColor = UIColor.redColor;
1640 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
1641 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
1642 [mockFlutterView addSubview:childClippingView];
1643
1644 [mockFlutterView setNeedsLayout];
1645 [mockFlutterView layoutIfNeeded];
1646 XCTAssertNil(childClippingView.maskView);
1647}
1648
1650 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1651 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1652 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1653 /*platform=*/thread_task_runner,
1654 /*raster=*/thread_task_runner,
1655 /*ui=*/thread_task_runner,
1656 /*io=*/thread_task_runner);
1657 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
1658 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1659 /*delegate=*/mock_delegate,
1660 /*rendering_api=*/mock_delegate.settings_.enable_impeller
1663 /*platform_views_controller=*/flutterPlatformViewsController,
1664 /*task_runners=*/runners,
1665 /*worker_task_runner=*/nil,
1666 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
1667
1670 flutterPlatformViewsController->RegisterViewFactory(
1671 factory, @"MockFlutterPlatformView",
1673 FlutterResult result = ^(id result) {
1674 };
1675 flutterPlatformViewsController->OnMethodCall(
1677 methodCallWithMethodName:@"create"
1678 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
1679 result);
1680
1681 XCTAssertNotNil(gMockPlatformView);
1682
1683 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
1684 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
1685 // Create embedded view params
1687 // Layer tree always pushes a screen scale factor to the stack.
1688 SkMatrix screenScaleMatrix =
1689 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
1690 stack.PushTransform(screenScaleMatrix);
1691 SkMatrix translateMatrix = SkMatrix::Translate(5, 5);
1692 // The platform view's rect for this test will be (5, 5, 10, 10).
1693 stack.PushTransform(translateMatrix);
1694
1695 // Push a clip rrect, the rect of the rrect is the same as the PlatformView of the corner should.
1696 // clip the PlatformView.
1697 SkRect rect_for_rrect = SkRect::MakeXYWH(0, 0, 10, 10);
1698 SkRRect rrect = SkRRect::MakeRectXY(rect_for_rrect, 1, 1);
1699 stack.PushClipRRect(rrect);
1700
1701 auto embeddedViewParams = std::make_unique<flutter::EmbeddedViewParams>(
1702 SkMatrix::Concat(screenScaleMatrix, translateMatrix), SkSize::Make(5, 5), stack);
1703
1704 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1705 flutterPlatformViewsController->CompositeEmbeddedView(2);
1706 gMockPlatformView.backgroundColor = UIColor.redColor;
1707 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
1708 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
1709 [mockFlutterView addSubview:childClippingView];
1710
1711 [mockFlutterView setNeedsLayout];
1712 [mockFlutterView layoutIfNeeded];
1713
1714 XCTAssertNotNil(childClippingView.maskView);
1715}
1716
1717- (void)testClipRect {
1718 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1719 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1720 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1721 /*platform=*/thread_task_runner,
1722 /*raster=*/thread_task_runner,
1723 /*ui=*/thread_task_runner,
1724 /*io=*/thread_task_runner);
1725 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
1726 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1727 /*delegate=*/mock_delegate,
1728 /*rendering_api=*/mock_delegate.settings_.enable_impeller
1731 /*platform_views_controller=*/flutterPlatformViewsController,
1732 /*task_runners=*/runners,
1733 /*worker_task_runner=*/nil,
1734 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
1735
1738 flutterPlatformViewsController->RegisterViewFactory(
1739 factory, @"MockFlutterPlatformView",
1741 FlutterResult result = ^(id result) {
1742 };
1743 flutterPlatformViewsController->OnMethodCall(
1745 methodCallWithMethodName:@"create"
1746 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
1747 result);
1748
1749 XCTAssertNotNil(gMockPlatformView);
1750
1751 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
1752 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
1753 // Create embedded view params
1755 // Layer tree always pushes a screen scale factor to the stack
1756 SkMatrix screenScaleMatrix =
1757 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
1758 stack.PushTransform(screenScaleMatrix);
1759 // Push a clip rect
1760 SkRect rect = SkRect::MakeXYWH(2, 2, 3, 3);
1761 stack.PushClipRect(rect);
1762
1763 auto embeddedViewParams =
1764 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
1765
1766 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1767 flutterPlatformViewsController->CompositeEmbeddedView(2);
1768 gMockPlatformView.backgroundColor = UIColor.redColor;
1769 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
1770 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
1771 [mockFlutterView addSubview:childClippingView];
1772
1773 [mockFlutterView setNeedsLayout];
1774 [mockFlutterView layoutIfNeeded];
1775
1776 CGRect insideClipping = CGRectMake(2, 2, 3, 3);
1777 for (int i = 0; i < 10; i++) {
1778 for (int j = 0; j < 10; j++) {
1779 CGPoint point = CGPointMake(i, j);
1780 int alpha = [self alphaOfPoint:CGPointMake(i, j) onView:mockFlutterView];
1781 if (CGRectContainsPoint(insideClipping, point)) {
1782 XCTAssertEqual(alpha, 255);
1783 } else {
1784 XCTAssertEqual(alpha, 0);
1785 }
1786 }
1787 }
1788}
1789
1790- (void)testClipRRect {
1791 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1792 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1793 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1794 /*platform=*/thread_task_runner,
1795 /*raster=*/thread_task_runner,
1796 /*ui=*/thread_task_runner,
1797 /*io=*/thread_task_runner);
1798 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
1799 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1800 /*delegate=*/mock_delegate,
1801 /*rendering_api=*/mock_delegate.settings_.enable_impeller
1804 /*platform_views_controller=*/flutterPlatformViewsController,
1805 /*task_runners=*/runners,
1806 /*worker_task_runner=*/nil,
1807 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
1808
1811 flutterPlatformViewsController->RegisterViewFactory(
1812 factory, @"MockFlutterPlatformView",
1814 FlutterResult result = ^(id result) {
1815 };
1816 flutterPlatformViewsController->OnMethodCall(
1818 methodCallWithMethodName:@"create"
1819 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
1820 result);
1821
1822 XCTAssertNotNil(gMockPlatformView);
1823
1824 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
1825 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
1826 // Create embedded view params
1828 // Layer tree always pushes a screen scale factor to the stack
1829 SkMatrix screenScaleMatrix =
1830 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
1831 stack.PushTransform(screenScaleMatrix);
1832 // Push a clip rrect
1834 stack.PushClipRRect(rrect);
1835
1836 auto embeddedViewParams =
1837 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
1838
1839 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1840 flutterPlatformViewsController->CompositeEmbeddedView(2);
1841 gMockPlatformView.backgroundColor = UIColor.redColor;
1842 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
1843 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
1844 [mockFlutterView addSubview:childClippingView];
1845
1846 [mockFlutterView setNeedsLayout];
1847 [mockFlutterView layoutIfNeeded];
1848
1849 /*
1850 ClippingMask outterClipping
1851 2 3 4 5 6 7 2 3 4 5 6 7
1852 2 / - - - - \ 2 + - - - - +
1853 3 | | 3 | |
1854 4 | | 4 | |
1855 5 | | 5 | |
1856 6 | | 6 | |
1857 7 \ - - - - / 7 + - - - - +
1858
1859 innerClipping1 innerClipping2
1860 2 3 4 5 6 7 2 3 4 5 6 7
1861 2 + - - + 2
1862 3 | | 3 + - - - - +
1863 4 | | 4 | |
1864 5 | | 5 | |
1865 6 | | 6 + - - - - +
1866 7 + - - + 7
1867 */
1868 CGRect innerClipping1 = CGRectMake(3, 2, 4, 6);
1869 CGRect innerClipping2 = CGRectMake(2, 3, 6, 4);
1870 CGRect outterClipping = CGRectMake(2, 2, 6, 6);
1871 for (int i = 0; i < 10; i++) {
1872 for (int j = 0; j < 10; j++) {
1873 CGPoint point = CGPointMake(i, j);
1874 int alpha = [self alphaOfPoint:CGPointMake(i, j) onView:mockFlutterView];
1875 if (CGRectContainsPoint(innerClipping1, point) ||
1876 CGRectContainsPoint(innerClipping2, point)) {
1877 // Pixels inside either of the 2 inner clippings should be fully opaque.
1878 XCTAssertEqual(alpha, 255);
1879 } else if (CGRectContainsPoint(outterClipping, point)) {
1880 // Corner pixels (i.e. (2, 2), (2, 7), (7, 2) and (7, 7)) should be partially transparent.
1881 XCTAssert(0 < alpha && alpha < 255);
1882 } else {
1883 // Pixels outside outterClipping should be fully transparent.
1884 XCTAssertEqual(alpha, 0);
1885 }
1886 }
1887 }
1888}
1889
1890- (void)testClipPath {
1891 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1892 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1893 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1894 /*platform=*/thread_task_runner,
1895 /*raster=*/thread_task_runner,
1896 /*ui=*/thread_task_runner,
1897 /*io=*/thread_task_runner);
1898 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
1899 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1900 /*delegate=*/mock_delegate,
1901 /*rendering_api=*/mock_delegate.settings_.enable_impeller
1904 /*platform_views_controller=*/flutterPlatformViewsController,
1905 /*task_runners=*/runners,
1906 /*worker_task_runner=*/nil,
1907 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
1908
1911 flutterPlatformViewsController->RegisterViewFactory(
1912 factory, @"MockFlutterPlatformView",
1914 FlutterResult result = ^(id result) {
1915 };
1916 flutterPlatformViewsController->OnMethodCall(
1918 methodCallWithMethodName:@"create"
1919 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
1920 result);
1921
1922 XCTAssertNotNil(gMockPlatformView);
1923
1924 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
1925 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
1926 // Create embedded view params
1928 // Layer tree always pushes a screen scale factor to the stack
1929 SkMatrix screenScaleMatrix =
1930 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
1931 stack.PushTransform(screenScaleMatrix);
1932 // Push a clip path
1933 SkPath path;
1934 path.addRoundRect(SkRect::MakeXYWH(2, 2, 6, 6), 1, 1);
1935 stack.PushClipPath(path);
1936
1937 auto embeddedViewParams =
1938 std::make_unique<flutter::EmbeddedViewParams>(screenScaleMatrix, SkSize::Make(10, 10), stack);
1939
1940 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
1941 flutterPlatformViewsController->CompositeEmbeddedView(2);
1942 gMockPlatformView.backgroundColor = UIColor.redColor;
1943 XCTAssertTrue([gMockPlatformView.superview.superview isKindOfClass:ChildClippingView.class]);
1944 ChildClippingView* childClippingView = (ChildClippingView*)gMockPlatformView.superview.superview;
1945 [mockFlutterView addSubview:childClippingView];
1946
1947 [mockFlutterView setNeedsLayout];
1948 [mockFlutterView layoutIfNeeded];
1949
1950 /*
1951 ClippingMask outterClipping
1952 2 3 4 5 6 7 2 3 4 5 6 7
1953 2 / - - - - \ 2 + - - - - +
1954 3 | | 3 | |
1955 4 | | 4 | |
1956 5 | | 5 | |
1957 6 | | 6 | |
1958 7 \ - - - - / 7 + - - - - +
1959
1960 innerClipping1 innerClipping2
1961 2 3 4 5 6 7 2 3 4 5 6 7
1962 2 + - - + 2
1963 3 | | 3 + - - - - +
1964 4 | | 4 | |
1965 5 | | 5 | |
1966 6 | | 6 + - - - - +
1967 7 + - - + 7
1968 */
1969 CGRect innerClipping1 = CGRectMake(3, 2, 4, 6);
1970 CGRect innerClipping2 = CGRectMake(2, 3, 6, 4);
1971 CGRect outterClipping = CGRectMake(2, 2, 6, 6);
1972 for (int i = 0; i < 10; i++) {
1973 for (int j = 0; j < 10; j++) {
1974 CGPoint point = CGPointMake(i, j);
1975 int alpha = [self alphaOfPoint:CGPointMake(i, j) onView:mockFlutterView];
1976 if (CGRectContainsPoint(innerClipping1, point) ||
1977 CGRectContainsPoint(innerClipping2, point)) {
1978 // Pixels inside either of the 2 inner clippings should be fully opaque.
1979 XCTAssertEqual(alpha, 255);
1980 } else if (CGRectContainsPoint(outterClipping, point)) {
1981 // Corner pixels (i.e. (2, 2), (2, 7), (7, 2) and (7, 7)) should be partially transparent.
1982 XCTAssert(0 < alpha && alpha < 255);
1983 } else {
1984 // Pixels outside outterClipping should be fully transparent.
1985 XCTAssertEqual(alpha, 0);
1986 }
1987 }
1988 }
1989}
1990
1992 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
1993 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
1994 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
1995 /*platform=*/thread_task_runner,
1996 /*raster=*/thread_task_runner,
1997 /*ui=*/thread_task_runner,
1998 /*io=*/thread_task_runner);
1999 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2000 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2001 /*delegate=*/mock_delegate,
2002 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2005 /*platform_views_controller=*/flutterPlatformViewsController,
2006 /*task_runners=*/runners,
2007 /*worker_task_runner=*/nil,
2008 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2009
2012 flutterPlatformViewsController->RegisterViewFactory(
2013 factory, @"MockFlutterPlatformView",
2015 FlutterResult result = ^(id result) {
2016 };
2017 flutterPlatformViewsController->OnMethodCall(
2019 methodCallWithMethodName:@"create"
2020 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
2021 result);
2022
2023 XCTAssertNotNil(gMockPlatformView);
2024
2025 // Find touch inteceptor view
2026 UIView* touchInteceptorView = gMockPlatformView;
2027 while (touchInteceptorView != nil &&
2028 ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
2029 touchInteceptorView = touchInteceptorView.superview;
2030 }
2031 XCTAssertNotNil(touchInteceptorView);
2032
2033 // Find ForwardGestureRecognizer
2034 UIGestureRecognizer* forwardGectureRecognizer = nil;
2035 for (UIGestureRecognizer* gestureRecognizer in touchInteceptorView.gestureRecognizers) {
2036 if ([gestureRecognizer isKindOfClass:NSClassFromString(@"ForwardingGestureRecognizer")]) {
2037 forwardGectureRecognizer = gestureRecognizer;
2038 break;
2039 }
2040 }
2041
2042 // Before setting flutter view controller, events are not dispatched.
2043 NSSet* touches1 = [[NSSet alloc] init];
2044 id event1 = OCMClassMock([UIEvent class]);
2045 id mockFlutterViewContoller = OCMClassMock([FlutterViewController class]);
2046 [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
2047 OCMReject([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]);
2048
2049 // Set flutter view controller allows events to be dispatched.
2050 NSSet* touches2 = [[NSSet alloc] init];
2051 id event2 = OCMClassMock([UIEvent class]);
2052 flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
2053 [forwardGectureRecognizer touchesBegan:touches2 withEvent:event2];
2054 OCMVerify([mockFlutterViewContoller touchesBegan:touches2 withEvent:event2]);
2055}
2056
2058 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2059 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2060 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2061 /*platform=*/thread_task_runner,
2062 /*raster=*/thread_task_runner,
2063 /*ui=*/thread_task_runner,
2064 /*io=*/thread_task_runner);
2065 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2066 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2067 /*delegate=*/mock_delegate,
2068 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2071 /*platform_views_controller=*/flutterPlatformViewsController,
2072 /*task_runners=*/runners,
2073 /*worker_task_runner=*/nil,
2074 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2075
2078 flutterPlatformViewsController->RegisterViewFactory(
2079 factory, @"MockFlutterPlatformView",
2081 FlutterResult result = ^(id result) {
2082 };
2083 flutterPlatformViewsController->OnMethodCall(
2085 methodCallWithMethodName:@"create"
2086 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
2087 result);
2088
2089 XCTAssertNotNil(gMockPlatformView);
2090
2091 // Find touch inteceptor view
2092 UIView* touchInteceptorView = gMockPlatformView;
2093 while (touchInteceptorView != nil &&
2094 ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
2095 touchInteceptorView = touchInteceptorView.superview;
2096 }
2097 XCTAssertNotNil(touchInteceptorView);
2098
2099 // Find ForwardGestureRecognizer
2100 UIGestureRecognizer* forwardGectureRecognizer = nil;
2101 for (UIGestureRecognizer* gestureRecognizer in touchInteceptorView.gestureRecognizers) {
2102 if ([gestureRecognizer isKindOfClass:NSClassFromString(@"ForwardingGestureRecognizer")]) {
2103 forwardGectureRecognizer = gestureRecognizer;
2104 break;
2105 }
2106 }
2107 id mockFlutterViewContoller = OCMClassMock([FlutterViewController class]);
2108 {
2109 // ***** Sequence 1, finishing touch event with touchEnded ***** //
2110 flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
2111
2112 NSSet* touches1 = [[NSSet alloc] init];
2113 id event1 = OCMClassMock([UIEvent class]);
2114 [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
2115 OCMVerify([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]);
2116
2117 flutterPlatformViewsController->SetFlutterViewController(nil);
2118
2119 // Allow the touch events to finish
2120 NSSet* touches2 = [[NSSet alloc] init];
2121 id event2 = OCMClassMock([UIEvent class]);
2122 [forwardGectureRecognizer touchesMoved:touches2 withEvent:event2];
2123 OCMVerify([mockFlutterViewContoller touchesMoved:touches2 withEvent:event2]);
2124
2125 NSSet* touches3 = [[NSSet alloc] init];
2126 id event3 = OCMClassMock([UIEvent class]);
2127 [forwardGectureRecognizer touchesEnded:touches3 withEvent:event3];
2128 OCMVerify([mockFlutterViewContoller touchesEnded:touches3 withEvent:event3]);
2129
2130 // Now the 2nd touch sequence should not be allowed.
2131 NSSet* touches4 = [[NSSet alloc] init];
2132 id event4 = OCMClassMock([UIEvent class]);
2133 [forwardGectureRecognizer touchesBegan:touches4 withEvent:event4];
2134 OCMReject([mockFlutterViewContoller touchesBegan:touches4 withEvent:event4]);
2135
2136 NSSet* touches5 = [[NSSet alloc] init];
2137 id event5 = OCMClassMock([UIEvent class]);
2138 [forwardGectureRecognizer touchesEnded:touches5 withEvent:event5];
2139 OCMReject([mockFlutterViewContoller touchesEnded:touches5 withEvent:event5]);
2140 }
2141
2142 {
2143 // ***** Sequence 2, finishing touch event with touchCancelled ***** //
2144 flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
2145
2146 NSSet* touches1 = [[NSSet alloc] init];
2147 id event1 = OCMClassMock([UIEvent class]);
2148 [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
2149 OCMVerify([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]);
2150
2151 flutterPlatformViewsController->SetFlutterViewController(nil);
2152
2153 // Allow the touch events to finish
2154 NSSet* touches2 = [[NSSet alloc] init];
2155 id event2 = OCMClassMock([UIEvent class]);
2156 [forwardGectureRecognizer touchesMoved:touches2 withEvent:event2];
2157 OCMVerify([mockFlutterViewContoller touchesMoved:touches2 withEvent:event2]);
2158
2159 NSSet* touches3 = [[NSSet alloc] init];
2160 id event3 = OCMClassMock([UIEvent class]);
2161 [forwardGectureRecognizer touchesCancelled:touches3 withEvent:event3];
2162 OCMVerify([mockFlutterViewContoller forceTouchesCancelled:touches3]);
2163
2164 // Now the 2nd touch sequence should not be allowed.
2165 NSSet* touches4 = [[NSSet alloc] init];
2166 id event4 = OCMClassMock([UIEvent class]);
2167 [forwardGectureRecognizer touchesBegan:touches4 withEvent:event4];
2168 OCMReject([mockFlutterViewContoller touchesBegan:touches4 withEvent:event4]);
2169
2170 NSSet* touches5 = [[NSSet alloc] init];
2171 id event5 = OCMClassMock([UIEvent class]);
2172 [forwardGectureRecognizer touchesEnded:touches5 withEvent:event5];
2173 OCMReject([mockFlutterViewContoller touchesEnded:touches5 withEvent:event5]);
2174 }
2175
2176 flutterPlatformViewsController->Reset();
2177}
2178
2179- (void)
2181 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2182 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2183 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2184 /*platform=*/thread_task_runner,
2185 /*raster=*/thread_task_runner,
2186 /*ui=*/thread_task_runner,
2187 /*io=*/thread_task_runner);
2188 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2189 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2190 /*delegate=*/mock_delegate,
2191 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2194 /*platform_views_controller=*/flutterPlatformViewsController,
2195 /*task_runners=*/runners,
2196 /*worker_task_runner=*/nil,
2197 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2198
2201 flutterPlatformViewsController->RegisterViewFactory(
2202 factory, @"MockFlutterPlatformView",
2204 FlutterResult result = ^(id result) {
2205 };
2206 flutterPlatformViewsController->OnMethodCall(
2208 methodCallWithMethodName:@"create"
2209 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
2210 result);
2211
2212 XCTAssertNotNil(gMockPlatformView);
2213
2214 // Find touch inteceptor view
2215 UIView* touchInteceptorView = gMockPlatformView;
2216 while (touchInteceptorView != nil &&
2217 ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
2218 touchInteceptorView = touchInteceptorView.superview;
2219 }
2220 XCTAssertNotNil(touchInteceptorView);
2221
2222 // Find ForwardGestureRecognizer
2223 UIGestureRecognizer* forwardGectureRecognizer = nil;
2224 for (UIGestureRecognizer* gestureRecognizer in touchInteceptorView.gestureRecognizers) {
2225 if ([gestureRecognizer isKindOfClass:NSClassFromString(@"ForwardingGestureRecognizer")]) {
2226 forwardGectureRecognizer = gestureRecognizer;
2227 break;
2228 }
2229 }
2230 id mockFlutterViewContoller = OCMClassMock([FlutterViewController class]);
2231
2232 flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
2233
2234 // The touches in this sequence requires 1 touch object, we always create the NSSet with one item.
2235 NSSet* touches1 = [NSSet setWithObject:@1];
2236 id event1 = OCMClassMock([UIEvent class]);
2237 [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
2238 OCMVerify([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]);
2239
2240 FlutterViewController* mockFlutterViewContoller2 = OCMClassMock([FlutterViewController class]);
2241 flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller2);
2242
2243 // Touch events should still send to the old FlutterViewController if FlutterViewController
2244 // is updated in between.
2245 NSSet* touches2 = [NSSet setWithObject:@1];
2246 id event2 = OCMClassMock([UIEvent class]);
2247 [forwardGectureRecognizer touchesBegan:touches2 withEvent:event2];
2248 OCMVerify([mockFlutterViewContoller touchesBegan:touches2 withEvent:event2]);
2249 OCMReject([mockFlutterViewContoller2 touchesBegan:touches2 withEvent:event2]);
2250
2251 NSSet* touches3 = [NSSet setWithObject:@1];
2252 id event3 = OCMClassMock([UIEvent class]);
2253 [forwardGectureRecognizer touchesMoved:touches3 withEvent:event3];
2254 OCMVerify([mockFlutterViewContoller touchesMoved:touches3 withEvent:event3]);
2255 OCMReject([mockFlutterViewContoller2 touchesMoved:touches3 withEvent:event3]);
2256
2257 NSSet* touches4 = [NSSet setWithObject:@1];
2258 id event4 = OCMClassMock([UIEvent class]);
2259 [forwardGectureRecognizer touchesEnded:touches4 withEvent:event4];
2260 OCMVerify([mockFlutterViewContoller touchesEnded:touches4 withEvent:event4]);
2261 OCMReject([mockFlutterViewContoller2 touchesEnded:touches4 withEvent:event4]);
2262
2263 NSSet* touches5 = [NSSet setWithObject:@1];
2264 id event5 = OCMClassMock([UIEvent class]);
2265 [forwardGectureRecognizer touchesEnded:touches5 withEvent:event5];
2266 OCMVerify([mockFlutterViewContoller touchesEnded:touches5 withEvent:event5]);
2267 OCMReject([mockFlutterViewContoller2 touchesEnded:touches5 withEvent:event5]);
2268
2269 // Now the 2nd touch sequence should go to the new FlutterViewController
2270
2271 NSSet* touches6 = [NSSet setWithObject:@1];
2272 id event6 = OCMClassMock([UIEvent class]);
2273 [forwardGectureRecognizer touchesBegan:touches6 withEvent:event6];
2274 OCMVerify([mockFlutterViewContoller2 touchesBegan:touches6 withEvent:event6]);
2275 OCMReject([mockFlutterViewContoller touchesBegan:touches6 withEvent:event6]);
2276
2277 // Allow the touch events to finish
2278 NSSet* touches7 = [NSSet setWithObject:@1];
2279 id event7 = OCMClassMock([UIEvent class]);
2280 [forwardGectureRecognizer touchesMoved:touches7 withEvent:event7];
2281 OCMVerify([mockFlutterViewContoller2 touchesMoved:touches7 withEvent:event7]);
2282 OCMReject([mockFlutterViewContoller touchesMoved:touches7 withEvent:event7]);
2283
2284 NSSet* touches8 = [NSSet setWithObject:@1];
2285 id event8 = OCMClassMock([UIEvent class]);
2286 [forwardGectureRecognizer touchesEnded:touches8 withEvent:event8];
2287 OCMVerify([mockFlutterViewContoller2 touchesEnded:touches8 withEvent:event8]);
2288 OCMReject([mockFlutterViewContoller touchesEnded:touches8 withEvent:event8]);
2289
2290 flutterPlatformViewsController->Reset();
2291}
2292
2294 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2295 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2296 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2297 /*platform=*/thread_task_runner,
2298 /*raster=*/thread_task_runner,
2299 /*ui=*/thread_task_runner,
2300 /*io=*/thread_task_runner);
2301 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2302 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2303 /*delegate=*/mock_delegate,
2304 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2307 /*platform_views_controller=*/flutterPlatformViewsController,
2308 /*task_runners=*/runners,
2309 /*worker_task_runner=*/nil,
2310 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2311
2314 flutterPlatformViewsController->RegisterViewFactory(
2315 factory, @"MockFlutterPlatformView",
2317 FlutterResult result = ^(id result) {
2318 };
2319 flutterPlatformViewsController->OnMethodCall(
2321 methodCallWithMethodName:@"create"
2322 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
2323 result);
2324
2325 XCTAssertNotNil(gMockPlatformView);
2326
2327 // Find touch inteceptor view
2328 UIView* touchInteceptorView = gMockPlatformView;
2329 while (touchInteceptorView != nil &&
2330 ![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
2331 touchInteceptorView = touchInteceptorView.superview;
2332 }
2333 XCTAssertNotNil(touchInteceptorView);
2334
2335 // Find ForwardGestureRecognizer
2336 UIGestureRecognizer* forwardGectureRecognizer = nil;
2337 for (UIGestureRecognizer* gestureRecognizer in touchInteceptorView.gestureRecognizers) {
2338 if ([gestureRecognizer isKindOfClass:NSClassFromString(@"ForwardingGestureRecognizer")]) {
2339 forwardGectureRecognizer = gestureRecognizer;
2340 break;
2341 }
2342 }
2343 id mockFlutterViewContoller = OCMClassMock([FlutterViewController class]);
2344
2345 flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
2346
2347 NSSet* touches1 = [NSSet setWithObject:@1];
2348 id event1 = OCMClassMock([UIEvent class]);
2349 [forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
2350
2351 [forwardGectureRecognizer touchesCancelled:touches1 withEvent:event1];
2352 OCMVerify([mockFlutterViewContoller forceTouchesCancelled:touches1]);
2353
2354 flutterPlatformViewsController->Reset();
2355}
2356
2358 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2359 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2360 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2361 /*platform=*/thread_task_runner,
2362 /*raster=*/thread_task_runner,
2363 /*ui=*/thread_task_runner,
2364 /*io=*/thread_task_runner);
2365 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2366 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2367 /*delegate=*/mock_delegate,
2368 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2371 /*platform_views_controller=*/flutterPlatformViewsController,
2372 /*task_runners=*/runners,
2373 /*worker_task_runner=*/nil,
2374 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2375
2378 flutterPlatformViewsController->RegisterViewFactory(
2379 factory, @"MockFlutterPlatformView",
2381 FlutterResult result = ^(id result) {
2382 };
2383 flutterPlatformViewsController->OnMethodCall(
2385 methodCallWithMethodName:@"create"
2386 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
2387 result);
2388
2389 XCTAssertNotNil(gMockPlatformView);
2390
2391 // Create embedded view params
2393 SkMatrix finalMatrix;
2394
2395 auto embeddedViewParams_1 =
2396 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2397
2398 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams_1));
2399 flutterPlatformViewsController->CompositeEmbeddedView(2);
2401 auto mock_surface = std::make_unique<flutter::SurfaceFrame>(
2402 nullptr, framebuffer_info,
2403 [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return false; },
2404 /*frame_size=*/SkISize::Make(800, 600));
2405 XCTAssertFalse(
2406 flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)));
2407
2408 auto embeddedViewParams_2 =
2409 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2410 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams_2));
2411 flutterPlatformViewsController->CompositeEmbeddedView(2);
2412 auto mock_surface_submit_true = std::make_unique<flutter::SurfaceFrame>(
2413 nullptr, framebuffer_info,
2414 [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
2415 /*frame_size=*/SkISize::Make(800, 600));
2416 XCTAssertTrue(flutterPlatformViewsController->SubmitFrame(nullptr, nullptr,
2417 std::move(mock_surface_submit_true)));
2418}
2419
2420- (void)
2422 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2423 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2424 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2425 /*platform=*/thread_task_runner,
2426 /*raster=*/thread_task_runner,
2427 /*ui=*/thread_task_runner,
2428 /*io=*/thread_task_runner);
2429 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2430 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2431 /*delegate=*/mock_delegate,
2432 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2435 /*platform_views_controller=*/flutterPlatformViewsController,
2436 /*task_runners=*/runners,
2437 /*worker_task_runner=*/nil,
2438 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2439
2440 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
2441 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
2442
2445 flutterPlatformViewsController->RegisterViewFactory(
2446 factory, @"MockFlutterPlatformView",
2448 FlutterResult result = ^(id result) {
2449 };
2450 // autorelease pool to trigger an autorelease for all the root_views_ and touch_interceptors_.
2451 @autoreleasepool {
2452 flutterPlatformViewsController->OnMethodCall(
2454 methodCallWithMethodName:@"create"
2455 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
2456 result);
2457
2459 SkMatrix finalMatrix;
2460 auto embeddedViewParams =
2461 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2462 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
2463 flutterPlatformViewsController->CompositeEmbeddedView(2);
2464 // Not calling |flutterPlatformViewsController::SubmitFrame| so that the platform views are not
2465 // added to flutter_view_.
2466
2467 XCTAssertNotNil(gMockPlatformView);
2468 flutterPlatformViewsController->Reset();
2469 }
2470 XCTAssertNil(gMockPlatformView);
2471}
2472
2474 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2475 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2476 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2477 /*platform=*/thread_task_runner,
2478 /*raster=*/thread_task_runner,
2479 /*ui=*/thread_task_runner,
2480 /*io=*/thread_task_runner);
2481 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2482 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2483 /*delegate=*/mock_delegate,
2484 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2487 /*platform_views_controller=*/flutterPlatformViewsController,
2488 /*task_runners=*/runners,
2489 /*worker_task_runner=*/nil,
2490 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2491
2492 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
2493 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
2494
2497 flutterPlatformViewsController->RegisterViewFactory(
2498 factory, @"MockFlutterPlatformView",
2500 FlutterResult result = ^(id result) {
2501 };
2502
2503 flutterPlatformViewsController->OnMethodCall(
2505 methodCallWithMethodName:@"create"
2506 arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}],
2507 result);
2508
2509 // First frame, |EmbeddedViewCount| is not empty after composite.
2510 flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
2512 SkMatrix finalMatrix;
2513 auto embeddedViewParams1 =
2514 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2515 flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1));
2516 flutterPlatformViewsController->CompositeEmbeddedView(0);
2517 XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 1UL);
2518
2519 // Second frame, |EmbeddedViewCount| should be empty at the start
2520 flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
2521 XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 0UL);
2522
2523 auto embeddedViewParams2 =
2524 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2525 flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams2));
2526 flutterPlatformViewsController->CompositeEmbeddedView(0);
2527 XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 1UL);
2528}
2529
2530- (void)
2532 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2533 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2534 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2535 /*platform=*/thread_task_runner,
2536 /*raster=*/thread_task_runner,
2537 /*ui=*/thread_task_runner,
2538 /*io=*/thread_task_runner);
2539 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2540 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2541 /*delegate=*/mock_delegate,
2542 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2545 /*platform_views_controller=*/flutterPlatformViewsController,
2546 /*task_runners=*/runners,
2547 /*worker_task_runner=*/nil,
2548 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2549
2550 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
2551 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
2552
2555 flutterPlatformViewsController->RegisterViewFactory(
2556 factory, @"MockFlutterPlatformView",
2558 FlutterResult result = ^(id result) {
2559 };
2560 flutterPlatformViewsController->OnMethodCall(
2562 methodCallWithMethodName:@"create"
2563 arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}],
2564 result);
2565 UIView* view1 = gMockPlatformView;
2566
2567 // This overwrites `gMockPlatformView` to another view.
2568 flutterPlatformViewsController->OnMethodCall(
2570 methodCallWithMethodName:@"create"
2571 arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}],
2572 result);
2573 UIView* view2 = gMockPlatformView;
2574
2575 flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
2577 SkMatrix finalMatrix;
2578 auto embeddedViewParams1 =
2579 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2580 flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1));
2581 flutterPlatformViewsController->CompositeEmbeddedView(0);
2582 auto embeddedViewParams2 =
2583 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(500, 500), stack);
2584 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2));
2585 flutterPlatformViewsController->CompositeEmbeddedView(1);
2586
2587 // SKSurface is required if the root FlutterView is present.
2588 const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000);
2589 sk_sp<SkSurface> mock_sk_surface = SkSurfaces::Raster(image_info);
2591 auto mock_surface = std::make_unique<flutter::SurfaceFrame>(
2592 std::move(mock_sk_surface), framebuffer_info,
2593 [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
2594 /*frame_size=*/SkISize::Make(800, 600));
2595
2596 XCTAssertTrue(
2597 flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)));
2598 // platform view is wrapped by touch interceptor, which itself is wrapped by clipping view.
2599 UIView* clippingView1 = view1.superview.superview;
2600 UIView* clippingView2 = view2.superview.superview;
2601 UIView* flutterView = clippingView1.superview;
2602 XCTAssertTrue([flutterView.subviews indexOfObject:clippingView1] <
2603 [flutterView.subviews indexOfObject:clippingView2],
2604 @"The first clipping view should be added before the second clipping view.");
2605
2606 // Need to recreate these params since they are `std::move`ed.
2607 flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
2608 // Process the second frame in the opposite order.
2609 embeddedViewParams2 =
2610 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(500, 500), stack);
2611 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2));
2612 flutterPlatformViewsController->CompositeEmbeddedView(1);
2613 embeddedViewParams1 =
2614 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2615 flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1));
2616 flutterPlatformViewsController->CompositeEmbeddedView(0);
2617
2618 mock_sk_surface = SkSurfaces::Raster(image_info);
2619 mock_surface = std::make_unique<flutter::SurfaceFrame>(
2620 std::move(mock_sk_surface), framebuffer_info,
2621 [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
2622 /*frame_size=*/SkISize::Make(800, 600));
2623 XCTAssertTrue(
2624 flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)));
2625 XCTAssertTrue([flutterView.subviews indexOfObject:clippingView1] >
2626 [flutterView.subviews indexOfObject:clippingView2],
2627 @"The first clipping view should be added after the second clipping view.");
2628}
2629
2630- (void)
2632 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2633 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2634 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2635 /*platform=*/thread_task_runner,
2636 /*raster=*/thread_task_runner,
2637 /*ui=*/thread_task_runner,
2638 /*io=*/thread_task_runner);
2639 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2640 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2641 /*delegate=*/mock_delegate,
2642 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2645 /*platform_views_controller=*/flutterPlatformViewsController,
2646 /*task_runners=*/runners,
2647 /*worker_task_runner=*/nil,
2648 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2649
2650 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
2651 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
2652
2655 flutterPlatformViewsController->RegisterViewFactory(
2656 factory, @"MockFlutterPlatformView",
2658 FlutterResult result = ^(id result) {
2659 };
2660 flutterPlatformViewsController->OnMethodCall(
2662 methodCallWithMethodName:@"create"
2663 arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}],
2664 result);
2665 UIView* view1 = gMockPlatformView;
2666
2667 // This overwrites `gMockPlatformView` to another view.
2668 flutterPlatformViewsController->OnMethodCall(
2670 methodCallWithMethodName:@"create"
2671 arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}],
2672 result);
2673 UIView* view2 = gMockPlatformView;
2674
2675 flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
2677 SkMatrix finalMatrix;
2678 auto embeddedViewParams1 =
2679 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2680 flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1));
2681 flutterPlatformViewsController->CompositeEmbeddedView(0);
2682 auto embeddedViewParams2 =
2683 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(500, 500), stack);
2684 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2));
2685 flutterPlatformViewsController->CompositeEmbeddedView(1);
2686
2687 // SKSurface is required if the root FlutterView is present.
2688 const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000);
2689 sk_sp<SkSurface> mock_sk_surface = SkSurfaces::Raster(image_info);
2691 auto mock_surface = std::make_unique<flutter::SurfaceFrame>(
2692 std::move(mock_sk_surface), framebuffer_info,
2693 [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
2694 /*frame_size=*/SkISize::Make(800, 600));
2695
2696 XCTAssertTrue(
2697 flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)));
2698 // platform view is wrapped by touch interceptor, which itself is wrapped by clipping view.
2699 UIView* clippingView1 = view1.superview.superview;
2700 UIView* clippingView2 = view2.superview.superview;
2701 UIView* flutterView = clippingView1.superview;
2702 XCTAssertTrue([flutterView.subviews indexOfObject:clippingView1] <
2703 [flutterView.subviews indexOfObject:clippingView2],
2704 @"The first clipping view should be added before the second clipping view.");
2705
2706 // Need to recreate these params since they are `std::move`ed.
2707 flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
2708 // Process the second frame in the same order.
2709 embeddedViewParams1 =
2710 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2711 flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1));
2712 flutterPlatformViewsController->CompositeEmbeddedView(0);
2713 embeddedViewParams2 =
2714 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(500, 500), stack);
2715 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2));
2716 flutterPlatformViewsController->CompositeEmbeddedView(1);
2717
2718 mock_sk_surface = SkSurfaces::Raster(image_info);
2719 mock_surface = std::make_unique<flutter::SurfaceFrame>(
2720 std::move(mock_sk_surface), framebuffer_info,
2721 [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
2722 /*frame_size=*/SkISize::Make(800, 600));
2723 XCTAssertTrue(
2724 flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)));
2725 XCTAssertTrue([flutterView.subviews indexOfObject:clippingView1] <
2726 [flutterView.subviews indexOfObject:clippingView2],
2727 @"The first clipping view should be added before the second clipping view.");
2728}
2729
2731 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2732 auto thread_task_runner_platform = CreateNewThread("FlutterPlatformViewsTest1");
2733 auto thread_task_runner_other = CreateNewThread("FlutterPlatformViewsTest2");
2734 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2735 /*platform=*/thread_task_runner_platform,
2736 /*raster=*/thread_task_runner_other,
2737 /*ui=*/thread_task_runner_other,
2738 /*io=*/thread_task_runner_other);
2739 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2740 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2741 /*delegate=*/mock_delegate,
2742 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2745 /*platform_views_controller=*/flutterPlatformViewsController,
2746 /*task_runners=*/runners,
2747 /*worker_task_runner=*/nil,
2748 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2749
2750 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
2751 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
2752
2755 flutterPlatformViewsController->RegisterViewFactory(
2756 factory, @"MockFlutterPlatformView",
2758 XCTestExpectation* waitForPlatformView =
2759 [self expectationWithDescription:@"wait for platform view to be created"];
2760 FlutterResult result = ^(id result) {
2761 [waitForPlatformView fulfill];
2762 };
2763
2764 flutterPlatformViewsController->OnMethodCall(
2766 methodCallWithMethodName:@"create"
2767 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
2768 result);
2769 [self waitForExpectations:@[ waitForPlatformView ] timeout:30];
2770 XCTAssertNotNil(gMockPlatformView);
2771
2772 flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
2773 SkMatrix finalMatrix;
2775 auto embeddedViewParams =
2776 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
2777 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
2778
2779 fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger =
2780 fml::MakeRefCounted<fml::RasterThreadMerger>(thread_task_runner_platform->GetTaskQueueId(),
2781 thread_task_runner_other->GetTaskQueueId());
2782 XCTAssertEqual(flutterPlatformViewsController->PostPrerollAction(raster_thread_merger),
2784 XCTAssertFalse(raster_thread_merger->IsMerged());
2785
2786 flutterPlatformViewsController->EndFrame(true, raster_thread_merger);
2787 XCTAssertTrue(raster_thread_merger->IsMerged());
2788
2789 // Unmerge threads before the end of the test
2790 // TaskRunners are required to be unmerged before destruction.
2791 while (raster_thread_merger->DecrementLease() != fml::RasterThreadStatus::kUnmergedNow) {
2792 }
2793}
2794
2795- (int)alphaOfPoint:(CGPoint)point onView:(UIView*)view {
2796 unsigned char pixel[4] = {0};
2797
2798 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
2799
2800 // Draw the pixel on `point` in the context.
2801 CGContextRef context = CGBitmapContextCreate(
2802 pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);
2803 CGContextTranslateCTM(context, -point.x, -point.y);
2804 [view.layer renderInContext:context];
2805
2806 CGContextRelease(context);
2807 CGColorSpaceRelease(colorSpace);
2808 // Get the alpha from the pixel that we just rendered.
2809 return pixel[3];
2810}
2811
2813 // For view to become the first responder, it must be a descendant of a UIWindow
2814 UIWindow* window = [[UIWindow alloc] init];
2815 UITextField* textField = [[UITextField alloc] init];
2816 [window addSubview:textField];
2817
2818 [textField becomeFirstResponder];
2819 XCTAssertTrue(textField.isFirstResponder);
2820 XCTAssertTrue(textField.flt_hasFirstResponderInViewHierarchySubtree);
2821 [textField resignFirstResponder];
2822 XCTAssertFalse(textField.isFirstResponder);
2823 XCTAssertFalse(textField.flt_hasFirstResponderInViewHierarchySubtree);
2824}
2825
2827 // For view to become the first responder, it must be a descendant of a UIWindow
2828 UIWindow* window = [[UIWindow alloc] init];
2829 UIView* view = [[UIView alloc] init];
2830 UIView* childView = [[UIView alloc] init];
2831 UITextField* textField = [[UITextField alloc] init];
2832 [window addSubview:view];
2833 [view addSubview:childView];
2834 [childView addSubview:textField];
2835
2836 [textField becomeFirstResponder];
2837 XCTAssertTrue(textField.isFirstResponder);
2838 XCTAssertTrue(view.flt_hasFirstResponderInViewHierarchySubtree);
2839 [textField resignFirstResponder];
2840 XCTAssertFalse(textField.isFirstResponder);
2841 XCTAssertFalse(view.flt_hasFirstResponderInViewHierarchySubtree);
2842}
2843
2845 FlutterClippingMaskViewPool* pool = [[FlutterClippingMaskViewPool alloc] initWithCapacity:2];
2846 FlutterClippingMaskView* view1 = [pool getMaskViewWithFrame:CGRectZero];
2847 FlutterClippingMaskView* view2 = [pool getMaskViewWithFrame:CGRectZero];
2848 [pool insertViewToPoolIfNeeded:view1];
2849 [pool insertViewToPoolIfNeeded:view2];
2850 CGRect newRect = CGRectMake(0, 0, 10, 10);
2851 FlutterClippingMaskView* view3 = [pool getMaskViewWithFrame:newRect];
2852 FlutterClippingMaskView* view4 = [pool getMaskViewWithFrame:newRect];
2853 // view3 and view4 should randomly get either of view1 and view2.
2854 NSSet* set1 = [NSSet setWithObjects:view1, view2, nil];
2855 NSSet* set2 = [NSSet setWithObjects:view3, view4, nil];
2856 XCTAssertEqualObjects(set1, set2);
2857 XCTAssertTrue(CGRectEqualToRect(view3.frame, newRect));
2858 XCTAssertTrue(CGRectEqualToRect(view4.frame, newRect));
2859}
2860
2862 FlutterClippingMaskViewPool* pool = [[FlutterClippingMaskViewPool alloc] initWithCapacity:2];
2863 FlutterClippingMaskView* view1 = [pool getMaskViewWithFrame:CGRectZero];
2864 FlutterClippingMaskView* view2 = [pool getMaskViewWithFrame:CGRectZero];
2865 FlutterClippingMaskView* view3 = [pool getMaskViewWithFrame:CGRectZero];
2866 XCTAssertNotEqual(view1, view3);
2867 XCTAssertNotEqual(view2, view3);
2868}
2869
2871 __weak UIView* weakView;
2872 @autoreleasepool {
2873 FlutterClippingMaskViewPool* pool = [[FlutterClippingMaskViewPool alloc] initWithCapacity:2];
2874 FlutterClippingMaskView* view = [pool getMaskViewWithFrame:CGRectZero];
2875 weakView = view;
2876 XCTAssertNotNil(weakView);
2877 }
2878 XCTAssertNil(weakView);
2879}
2880
2882 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2883 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2884 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2885 /*platform=*/thread_task_runner,
2886 /*raster=*/thread_task_runner,
2887 /*ui=*/thread_task_runner,
2888 /*io=*/thread_task_runner);
2889 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2890 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2891 /*delegate=*/mock_delegate,
2892 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2895 /*platform_views_controller=*/flutterPlatformViewsController,
2896 /*task_runners=*/runners,
2897 /*worker_task_runner=*/nil,
2898 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2899
2902 flutterPlatformViewsController->RegisterViewFactory(
2903 factory, @"MockFlutterPlatformView",
2905 FlutterResult result = ^(id result) {
2906 };
2907 flutterPlatformViewsController->OnMethodCall(
2909 methodCallWithMethodName:@"create"
2910 arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}],
2911 result);
2912
2913 XCTAssertNotNil(gMockPlatformView);
2914 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
2915 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
2916 // Create embedded view params
2918 // Layer tree always pushes a screen scale factor to the stack
2919 SkMatrix screenScaleMatrix =
2920 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
2921 stack1.PushTransform(screenScaleMatrix);
2922 // Push a clip rect
2923 SkRect rect = SkRect::MakeXYWH(2, 2, 3, 3);
2924 stack1.PushClipRect(rect);
2925
2926 auto embeddedViewParams1 = std::make_unique<flutter::EmbeddedViewParams>(
2927 screenScaleMatrix, SkSize::Make(10, 10), stack1);
2928
2929 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1));
2930 flutterPlatformViewsController->CompositeEmbeddedView(1);
2931 UIView* childClippingView1 = gMockPlatformView.superview.superview;
2932 UIView* maskView1 = childClippingView1.maskView;
2933 XCTAssertNotNil(maskView1);
2934
2935 // Composite a new frame.
2936 flutterPlatformViewsController->BeginFrame(SkISize::Make(100, 100));
2938 auto embeddedViewParams2 = std::make_unique<flutter::EmbeddedViewParams>(
2939 screenScaleMatrix, SkSize::Make(10, 10), stack2);
2940 auto embeddedViewParams3 = std::make_unique<flutter::EmbeddedViewParams>(
2941 screenScaleMatrix, SkSize::Make(10, 10), stack2);
2942 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams3));
2943 flutterPlatformViewsController->CompositeEmbeddedView(1);
2944 childClippingView1 = gMockPlatformView.superview.superview;
2945
2946 // This overrides gMockPlatformView to point to the newly created platform view.
2947 flutterPlatformViewsController->OnMethodCall(
2949 methodCallWithMethodName:@"create"
2950 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
2951 result);
2952
2953 auto embeddedViewParams4 = std::make_unique<flutter::EmbeddedViewParams>(
2954 screenScaleMatrix, SkSize::Make(10, 10), stack1);
2955 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams4));
2956 flutterPlatformViewsController->CompositeEmbeddedView(2);
2957 UIView* childClippingView2 = gMockPlatformView.superview.superview;
2958
2959 UIView* maskView2 = childClippingView2.maskView;
2960 XCTAssertEqual(maskView1, maskView2);
2961 XCTAssertNotNil(childClippingView2.maskView);
2962 XCTAssertNil(childClippingView1.maskView);
2963}
2964
2966 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
2967 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
2968 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
2969 /*platform=*/thread_task_runner,
2970 /*raster=*/thread_task_runner,
2971 /*ui=*/thread_task_runner,
2972 /*io=*/thread_task_runner);
2973 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
2974 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2975 /*delegate=*/mock_delegate,
2976 /*rendering_api=*/mock_delegate.settings_.enable_impeller
2979 /*platform_views_controller=*/flutterPlatformViewsController,
2980 /*task_runners=*/runners,
2981 /*worker_task_runner=*/nil,
2982 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
2983
2986 flutterPlatformViewsController->RegisterViewFactory(
2987 factory, @"MockFlutterPlatformView",
2989 FlutterResult result = ^(id result) {
2990 };
2991
2992 flutterPlatformViewsController->OnMethodCall(
2994 methodCallWithMethodName:@"create"
2995 arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}],
2996 result);
2997 UIView* view1 = gMockPlatformView;
2998
2999 // This overwrites `gMockPlatformView` to another view.
3000 flutterPlatformViewsController->OnMethodCall(
3002 methodCallWithMethodName:@"create"
3003 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
3004 result);
3005 UIView* view2 = gMockPlatformView;
3006
3007 XCTAssertNotNil(gMockPlatformView);
3008 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
3009 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
3010 // Create embedded view params
3012 // Layer tree always pushes a screen scale factor to the stack
3013 SkMatrix screenScaleMatrix =
3014 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
3015 stack1.PushTransform(screenScaleMatrix);
3016 // Push a clip rect
3017 SkRect rect = SkRect::MakeXYWH(2, 2, 3, 3);
3018 stack1.PushClipRect(rect);
3019
3020 auto embeddedViewParams1 = std::make_unique<flutter::EmbeddedViewParams>(
3021 screenScaleMatrix, SkSize::Make(10, 10), stack1);
3022
3024 stack2.PushClipRect(rect);
3025 auto embeddedViewParams2 = std::make_unique<flutter::EmbeddedViewParams>(
3026 screenScaleMatrix, SkSize::Make(10, 10), stack2);
3027
3028 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1));
3029 flutterPlatformViewsController->CompositeEmbeddedView(1);
3030 UIView* childClippingView1 = view1.superview.superview;
3031
3032 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams2));
3033 flutterPlatformViewsController->CompositeEmbeddedView(2);
3034 UIView* childClippingView2 = view2.superview.superview;
3035 UIView* maskView1 = childClippingView1.maskView;
3036 UIView* maskView2 = childClippingView2.maskView;
3037 XCTAssertNotEqual(maskView1, maskView2);
3038}
3039
3041 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
3042 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
3043 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
3044 /*platform=*/thread_task_runner,
3045 /*raster=*/thread_task_runner,
3046 /*ui=*/thread_task_runner,
3047 /*io=*/thread_task_runner);
3048 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
3049 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
3050 /*delegate=*/mock_delegate,
3051 /*rendering_api=*/mock_delegate.settings_.enable_impeller
3054 /*platform_views_controller=*/flutterPlatformViewsController,
3055 /*task_runners=*/runners,
3056 /*worker_task_runner=*/nil,
3057 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
3058
3061 flutterPlatformViewsController->RegisterViewFactory(
3062 factory, @"MockFlutterPlatformView",
3064 FlutterResult result = ^(id result) {
3065 };
3066
3067 flutterPlatformViewsController->OnMethodCall(
3069 methodCallWithMethodName:@"create"
3070 arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}],
3071 result);
3072
3073 XCTAssertNotNil(gMockPlatformView);
3074 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
3075 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
3076 // Create embedded view params
3078 // Layer tree always pushes a screen scale factor to the stack
3079 SkMatrix screenScaleMatrix =
3080 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
3081 stack1.PushTransform(screenScaleMatrix);
3082 // Push a clip rect
3083 SkRect rect = SkRect::MakeXYWH(2, 2, 3, 3);
3084 stack1.PushClipRect(rect);
3085
3086 auto embeddedViewParams1 = std::make_unique<flutter::EmbeddedViewParams>(
3087 screenScaleMatrix, SkSize::Make(10, 10), stack1);
3088
3090 stack2.PushClipRect(rect);
3091 auto embeddedViewParams2 = std::make_unique<flutter::EmbeddedViewParams>(
3092 screenScaleMatrix, SkSize::Make(10, 10), stack2);
3093
3094 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1));
3095 flutterPlatformViewsController->CompositeEmbeddedView(1);
3096 UIView* childClippingView = gMockPlatformView.superview.superview;
3097
3098 UIView* maskView = childClippingView.maskView;
3099 XCTAssert([maskView.layer isKindOfClass:[CAShapeLayer class]],
3100 @"Mask view must use CAShapeLayer as its backing layer.");
3101}
3102
3103// Return true if a correct visual effect view is found. It also implies all the validation in this
3104// method passes.
3105//
3106// There are two fail states for this method. 1. One of the XCTAssert method failed; or 2. No
3107// correct visual effect view found.
3108- (BOOL)validateOneVisualEffectView:(UIView*)visualEffectView
3109 expectedFrame:(CGRect)frame
3110 inputRadius:(CGFloat)inputRadius {
3111 XCTAssertTrue(CGRectEqualToRect(visualEffectView.frame, frame));
3112 for (UIView* view in visualEffectView.subviews) {
3113 if (![NSStringFromClass([view class]) hasSuffix:@"BackdropView"]) {
3114 continue;
3115 }
3116 XCTAssertEqual(view.layer.filters.count, 1u);
3117 NSObject* filter = view.layer.filters.firstObject;
3118
3119 XCTAssertEqualObjects([filter valueForKey:@"name"], @"gaussianBlur");
3120
3121 NSObject* inputRadiusInFilter = [filter valueForKey:@"inputRadius"];
3122 XCTAssertTrue([inputRadiusInFilter isKindOfClass:[NSNumber class]] &&
3123 flutter::BlurRadiusEqualToBlurRadius(((NSNumber*)inputRadiusInFilter).floatValue,
3124 inputRadius));
3125 return YES;
3126 }
3127 return NO;
3128}
3129
3131 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
3132 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
3133 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
3134 /*platform=*/thread_task_runner,
3135 /*raster=*/thread_task_runner,
3136 /*ui=*/thread_task_runner,
3137 /*io=*/thread_task_runner);
3138 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
3139 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
3140 /*delegate=*/mock_delegate,
3141 /*rendering_api=*/mock_delegate.settings_.enable_impeller
3144 /*platform_views_controller=*/flutterPlatformViewsController,
3145 /*task_runners=*/runners,
3146 /*worker_task_runner=*/nil,
3147 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
3148
3149 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
3150 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
3151
3154 flutterPlatformViewsController->RegisterViewFactory(
3155 factory, @"MockFlutterPlatformView",
3157 FlutterResult result = ^(id result) {
3158 };
3159
3160 flutterPlatformViewsController->OnMethodCall(
3162 methodCallWithMethodName:@"create"
3163 arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}],
3164 result);
3165 flutterPlatformViewsController->OnMethodCall(
3167 methodCallWithMethodName:@"create"
3168 arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}],
3169 result);
3170
3171 {
3172 // **** First frame, view id 0, 1 in the composition_order_, disposing view 0 is called. **** //
3173 // No view should be disposed, or removed from the composition order.
3174 flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
3176 SkMatrix finalMatrix;
3177 auto embeddedViewParams0 =
3178 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
3179 flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams0));
3180 flutterPlatformViewsController->CompositeEmbeddedView(0);
3181
3182 auto embeddedViewParams1 =
3183 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
3184 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1));
3185 flutterPlatformViewsController->CompositeEmbeddedView(1);
3186 XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 2UL);
3187
3188 XCTestExpectation* expectation = [self expectationWithDescription:@"dispose call ended."];
3189 FlutterResult disposeResult = ^(id result) {
3190 [expectation fulfill];
3191 };
3192
3193 flutterPlatformViewsController->OnMethodCall(
3194 [FlutterMethodCall methodCallWithMethodName:@"dispose" arguments:@0], disposeResult);
3195 [self waitForExpectationsWithTimeout:30 handler:nil];
3196
3197 const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000);
3198 sk_sp<SkSurface> mock_sk_surface = SkSurfaces::Raster(image_info);
3200 auto mock_surface = std::make_unique<flutter::SurfaceFrame>(
3201 std::move(mock_sk_surface), framebuffer_info,
3202 [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
3203 /*frame_size=*/SkISize::Make(800, 600));
3204 XCTAssertTrue(
3205 flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)));
3206
3207 // Disposing won't remove embedded views until the view is removed from the composition_order_
3208 XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 2UL);
3209 XCTAssertNotNil(flutterPlatformViewsController->GetPlatformViewByID(0));
3210 XCTAssertNotNil(flutterPlatformViewsController->GetPlatformViewByID(1));
3211 }
3212
3213 {
3214 // **** Second frame, view id 1 in the composition_order_, no disposing view is called, **** //
3215 // View 0 is removed from the composition order in this frame, hence also disposed.
3216 flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
3218 SkMatrix finalMatrix;
3219 auto embeddedViewParams1 =
3220 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
3221 flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams1));
3222 flutterPlatformViewsController->CompositeEmbeddedView(1);
3223
3224 const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000);
3225 sk_sp<SkSurface> mock_sk_surface = SkSurfaces::Raster(image_info);
3227 auto mock_surface = std::make_unique<flutter::SurfaceFrame>(
3228 std::move(mock_sk_surface), framebuffer_info,
3229 [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
3230 /*frame_size=*/SkISize::Make(800, 600));
3231 XCTAssertTrue(
3232 flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)));
3233
3234 // Disposing won't remove embedded views until the view is removed from the composition_order_
3235 XCTAssertEqual(flutterPlatformViewsController->EmbeddedViewCount(), 1UL);
3236 XCTAssertNil(flutterPlatformViewsController->GetPlatformViewByID(0));
3237 XCTAssertNotNil(flutterPlatformViewsController->GetPlatformViewByID(1));
3238 }
3239}
3241 flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
3242 auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
3243 flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
3244 /*platform=*/thread_task_runner,
3245 /*raster=*/thread_task_runner,
3246 /*ui=*/thread_task_runner,
3247 /*io=*/thread_task_runner);
3248 auto flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
3249 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
3250 /*delegate=*/mock_delegate,
3251 /*rendering_api=*/mock_delegate.settings_.enable_impeller
3254 /*platform_views_controller=*/flutterPlatformViewsController,
3255 /*task_runners=*/runners,
3256 /*worker_task_runner=*/nil,
3257 /*is_gpu_disabled_jsync_switch=*/std::make_shared<fml::SyncSwitch>());
3258
3261 flutterPlatformViewsController->RegisterViewFactory(
3262 factory, @"MockFlutterPlatformView",
3264 FlutterResult result = ^(id result) {
3265 };
3266 flutterPlatformViewsController->OnMethodCall(
3268 methodCallWithMethodName:@"create"
3269 arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
3270 result);
3271 UIView* mockFlutterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
3272 flutterPlatformViewsController->SetFlutterView(mockFlutterView);
3273 // Create embedded view params
3275 // Layer tree always pushes a screen scale factor to the stack
3276 SkMatrix screenScaleMatrix =
3277 SkMatrix::Scale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale);
3278 stack.PushTransform(screenScaleMatrix);
3279 // Push a translate matrix
3280 SkMatrix translateMatrix = SkMatrix::Translate(100, 100);
3281 stack.PushTransform(translateMatrix);
3282 SkMatrix finalMatrix;
3283 finalMatrix.setConcat(screenScaleMatrix, translateMatrix);
3284
3285 auto embeddedViewParams =
3286 std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
3287
3288 flutterPlatformViewsController->PrerollCompositeEmbeddedView(2, std::move(embeddedViewParams));
3289 flutterPlatformViewsController->CompositeEmbeddedView(2);
3290
3291 // SKSurface is required if the root FlutterView is present.
3292 const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000);
3293 sk_sp<SkSurface> mock_sk_surface = SkSurfaces::Raster(image_info);
3295 auto mock_surface = std::make_unique<flutter::SurfaceFrame>(
3296 std::move(mock_sk_surface), framebuffer_info,
3297 [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
3298 /*frame_size=*/SkISize::Make(800, 600));
3299
3300 flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface));
3301
3302 UIView* someView = [[UIView alloc] init];
3303 [mockFlutterView addSubview:someView];
3304
3305 flutterPlatformViewsController->Reset();
3306 XCTAssertEqual(mockFlutterView.subviews.count, 1u);
3307 XCTAssertEqual(mockFlutterView.subviews.firstObject, someView);
3308}
3309
3311 FlutterTouchInterceptingView* touchInteceptorView = [[FlutterTouchInterceptingView alloc] init];
3312 NSObject* container = [[NSObject alloc] init];
3313 [touchInteceptorView setFlutterAccessibilityContainer:container];
3314 XCTAssertEqualObjects([touchInteceptorView accessibilityContainer], container);
3315}
3316
3317@end
AutoreleasePool pool
void(^ FlutterResult)(id _Nullable result)
std::unique_ptr< flutter::PlatformViewIOS > platform_view
static __weak FlutterPlatformViewsTestMockPlatformView * gMockPlatformView
const float kFloatCompareEpsilon
@ FlutterPlatformViewGestureRecognizersBlockingPolicyEager
for(const auto glyph :glyphs)
Definition: FontMgrTest.cpp:52
BOOL _viewCreated
GLenum type
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.h:1775
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:452
SkMatrix & setConcat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.cpp:603
Definition: SkPath.h:59
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.h:180
AssetResolverType
Identifies the type of AssetResolver an instance is.
Developer-facing API for rendering anything within the engine.
Definition: dl_canvas.h:38
void PushClipPath(const SkPath &path)
void PushBackdropFilter(const std::shared_ptr< const DlImageFilter > &filter, const SkRect &filter_rect)
void PushClipRect(const SkRect &rect)
void PushTransform(const SkMatrix &matrix)
void PushClipRRect(const SkRRect &rrect)
A Mapping like NonOwnedMapping, but uses Free as its release proc.
Definition: mapping.h:144
RasterThreadStatus DecrementLease()
Settings settings_
GLFWwindow * window
Definition: main.cc:45
VkSurfaceKHR surface
Definition: main.cc:49
double frame
Definition: examples.cpp:31
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
GAsyncResult * result
NSMutableArray * backdropFilterSubviews()
void applyBlurBackdropFilters:(NSArray< PlatformViewFilter * > *filters)
FlutterClippingMaskView * getMaskViewWithFrame:(CGRect frame)
void insertViewToPoolIfNeeded:(FlutterClippingMaskView *maskView)
void testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents()
void testHasFirstResponderInViewHierarchySubtree_descendantViewBecomesFirstResponder()
void testFlutterPlatformViewControllerSubmitFrameShouldOrderSubviewsCorrectlyWithDifferentViewHierarchy()
int alphaOfPoint:onView:(CGPoint point, [onView] UIView *view)
void testFlutterPlatformViewControllerSubmitFrameShouldOrderSubviewsCorrectlyWithSameViewHierarchy()
void testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing()
void testFlutterClippingMaskViewPoolAllocsNewMaskViewsAfterReachingCapacity()
void testFlutterPlatformViewControllerResetDeallocsPlatformViewWhenRootViewsNotBindedToFlutterView()
void testHasFirstResponderInViewHierarchySubtree_viewItselfBecomesFirstResponder()
void testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder()
void testSetFlutterViewControllerInTheMiddleOfTouchEventShouldStillAllowGesturesToBeHandled()
void testFlutterPlatformViewTouchesCancelledEventAreForcedToBeCancelled()
void testSetFlutterViewControllerInTheMiddleOfTouchEventAllowsTheNewControllerToHandleSecondTouchSequence()
void testClipRRectOnlyHasCornersInterceptWithPlatformViewShouldAddMaskView()
Win32Message message
static MockSurface mock_surface
Definition: mock_epoxy.cc:52
FlTexture * texture
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
SkRRect rrect
Definition: SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
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
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
static void LoadDartDeferredLibrary(JNIEnv *env, jobject obj, jlong shell_holder, jint jLoadingUnitId, jobjectArray jSearchPaths)
std::function< void()> closure
Definition: closure.h:14
const Scalar scale
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition: SkSize.h:56
int64_t texture_id
int BOOL
Definition: windows_types.h:37