| Flutter iOS Embedder |

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