| Flutter macOS Embedder |

FlutterMutatorViewTest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMutatorView.h"
6
7 #include "third_party/googletest/googletest/include/gtest/gtest.h"
8
9 @interface FlutterMutatorView (Private)
10
11 @property(readonly, nonatomic, nonnull) NSMutableArray<NSView*>* pathClipViews;
12 @property(readonly, nonatomic, nullable) NSView* platformViewContainer;
13
14 @end
15
16 static constexpr float kMaxErr = 1e-10;
17
18 namespace {
19 void ApplyFlutterLayer(FlutterMutatorView* view,
20 FlutterSize size,
21 const std::vector<FlutterPlatformViewMutation>& mutations) {
22 FlutterLayer layer;
23 layer.struct_size = sizeof(FlutterLayer);
24 layer.type = kFlutterLayerContentTypePlatformView;
25 // Offset is ignored by mutator view, the bounding rect is determined by
26 // width and transform.
27 layer.offset = FlutterPoint{0, 0};
28 layer.size = size;
29
30 FlutterPlatformView flutterPlatformView;
31 flutterPlatformView.struct_size = sizeof(FlutterPlatformView);
32 flutterPlatformView.identifier = 0;
33
34 std::vector<const FlutterPlatformViewMutation*> mutationPointers;
35 for (auto& mutation : mutations) {
36 mutationPointers.push_back(&mutation);
37 }
38 flutterPlatformView.mutations = mutationPointers.data();
39 flutterPlatformView.mutations_count = mutationPointers.size();
40 layer.platform_view = &flutterPlatformView;
41
42 [view applyFlutterLayer:&layer];
43 }
44
45 // Expect that each element within two CATransform3Ds is within an error bound.
46 //
47 // In order to avoid architecture-specific floating point differences we don't check for exact
48 // equality using, for example, CATransform3DEqualToTransform.
49 void ExpectTransform3DEqual(const CATransform3D& t, const CATransform3D& u) {
50 EXPECT_NEAR(t.m11, u.m11, kMaxErr);
51 EXPECT_NEAR(t.m12, u.m12, kMaxErr);
52 EXPECT_NEAR(t.m13, u.m13, kMaxErr);
53 EXPECT_NEAR(t.m14, u.m14, kMaxErr);
54
55 EXPECT_NEAR(t.m21, u.m21, kMaxErr);
56 EXPECT_NEAR(t.m22, u.m22, kMaxErr);
57 EXPECT_NEAR(t.m23, u.m23, kMaxErr);
58 EXPECT_NEAR(t.m24, u.m24, kMaxErr);
59
60 EXPECT_NEAR(t.m31, u.m31, kMaxErr);
61 EXPECT_NEAR(t.m32, u.m32, kMaxErr);
62 EXPECT_NEAR(t.m33, u.m33, kMaxErr);
63 EXPECT_NEAR(t.m34, u.m34, kMaxErr);
64
65 EXPECT_NEAR(t.m41, u.m41, kMaxErr);
66 EXPECT_NEAR(t.m42, u.m42, kMaxErr);
67 EXPECT_NEAR(t.m43, u.m43, kMaxErr);
68 EXPECT_NEAR(t.m44, u.m44, kMaxErr);
69 }
70 } // namespace
71
72 TEST(FlutterMutatorViewTest, BasicFrameIsCorrect) {
73 NSView* platformView = [[NSView alloc] init];
74 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
75
76 EXPECT_EQ(mutatorView.platformView, platformView);
77
78 std::vector<FlutterPlatformViewMutation> mutations{
79 {
80 .type = kFlutterPlatformViewMutationTypeTransformation,
81 .transformation =
82 FlutterTransformation{
83 .scaleX = 1,
84 .transX = 100,
85 .scaleY = 1,
86 .transY = 50,
87 },
88 },
89 };
90
91 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations);
92
93 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(100, 50, 30, 20)));
94 EXPECT_TRUE(CGRectEqualToRect(platformView.frame, CGRectMake(0, 0, 30, 20)));
95 EXPECT_EQ(mutatorView.pathClipViews.count, 0ull);
96 EXPECT_NE(mutatorView.platformViewContainer, nil);
97 }
98
99 TEST(FlutterMutatorViewTest, TransformedFrameIsCorrect) {
100 NSView* platformView = [[NSView alloc] init];
101 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
102 NSView* mutatorViewParent = [[NSView alloc] init];
103 mutatorViewParent.wantsLayer = YES;
104 mutatorViewParent.layer.contentsScale = 2.0;
105 [mutatorViewParent addSubview:mutatorView];
106
107 std::vector<FlutterPlatformViewMutation> mutations{
108 {
109 .type = kFlutterPlatformViewMutationTypeTransformation,
110 .transformation =
111 FlutterTransformation{
112 .scaleX = 2,
113 .scaleY = 2,
114 },
115 },
116 {
117 .type = kFlutterPlatformViewMutationTypeTransformation,
118 .transformation =
119 FlutterTransformation{
120 .scaleX = 1,
121 .transX = 100,
122 .scaleY = 1,
123 .transY = 50,
124 },
125 },
126 {
127 .type = kFlutterPlatformViewMutationTypeTransformation,
128 .transformation =
129 FlutterTransformation{
130 .scaleX = 1.5,
131 .transX = -7.5,
132 .scaleY = 1.5,
133 .transY = -5,
134 },
135 },
136 };
137
138 // PlatformView size form engine comes in physical pixels
139 ApplyFlutterLayer(mutatorView, FlutterSize{30 * 2, 20 * 2}, mutations);
140 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(92.5, 45, 45, 30)));
141 EXPECT_TRUE(CGRectEqualToRect(platformView.frame, CGRectMake(0, 0, 30, 20)));
142
143 ExpectTransform3DEqual(mutatorView.platformViewContainer.layer.sublayerTransform,
144 CATransform3DMakeScale(1.5, 1.5, 1));
145 }
146
147 TEST(FlutterMutatorViewTest, FrameWithLooseClipIsCorrect) {
148 NSView* platformView = [[NSView alloc] init];
149 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
150
151 EXPECT_EQ(mutatorView.platformView, platformView);
152
153 std::vector<FlutterPlatformViewMutation> mutations{
154 {
155 .type = kFlutterPlatformViewMutationTypeClipRect,
156 .clip_rect = FlutterRect{80, 40, 200, 100},
157 },
158 {
159 .type = kFlutterPlatformViewMutationTypeTransformation,
160 .transformation =
161 FlutterTransformation{
162 .scaleX = 1,
163 .transX = 100,
164 .scaleY = 1,
165 .transY = 50,
166 },
167 },
168 };
169
170 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations);
171
172 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(100, 50, 30, 20)));
173 EXPECT_TRUE(CGRectEqualToRect(platformView.frame, CGRectMake(0, 0, 30, 20)));
174 }
175
176 TEST(FlutterMutatorViewTest, FrameWithTightClipIsCorrect) {
177 NSView* platformView = [[NSView alloc] init];
178 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
179
180 EXPECT_EQ(mutatorView.platformView, platformView);
181
182 std::vector<FlutterPlatformViewMutation> mutations{
183 {
184 .type = kFlutterPlatformViewMutationTypeClipRect,
185 .clip_rect = FlutterRect{80, 40, 200, 100},
186 },
187 {
188 .type = kFlutterPlatformViewMutationTypeClipRect,
189 .clip_rect = FlutterRect{110, 55, 120, 65},
190 },
191 {
192 .type = kFlutterPlatformViewMutationTypeTransformation,
193 .transformation =
194 FlutterTransformation{
195 .scaleX = 1,
196 .transX = 100,
197 .scaleY = 1,
198 .transY = 50,
199 },
200 },
201 };
202
203 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations);
204
205 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(110, 55, 10, 10)));
206 EXPECT_TRUE(
207 CGRectEqualToRect(mutatorView.subviews.firstObject.frame, CGRectMake(-10, -5, 30, 20)));
208 EXPECT_TRUE(CGRectEqualToRect(platformView.frame, CGRectMake(0, 0, 30, 20)));
209 }
210
211 TEST(FlutterMutatorViewTest, FrameWithTightClipAndTransformIsCorrect) {
212 NSView* platformView = [[NSView alloc] init];
213 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
214 NSView* mutatorViewParent = [[NSView alloc] init];
215 mutatorViewParent.wantsLayer = YES;
216 mutatorViewParent.layer.contentsScale = 2.0;
217 [mutatorViewParent addSubview:mutatorView];
218
219 std::vector<FlutterPlatformViewMutation> mutations{
220 {
221 .type = kFlutterPlatformViewMutationTypeTransformation,
222 .transformation =
223 FlutterTransformation{
224 .scaleX = 2,
225 .scaleY = 2,
226 },
227 },
228 {
229 .type = kFlutterPlatformViewMutationTypeClipRect,
230 .clip_rect = FlutterRect{80, 40, 200, 100},
231 },
232 {
233 .type = kFlutterPlatformViewMutationTypeClipRect,
234 .clip_rect = FlutterRect{110, 55, 120, 65},
235 },
236 {
237 .type = kFlutterPlatformViewMutationTypeTransformation,
238 .transformation =
239 FlutterTransformation{
240 .scaleX = 1,
241 .transX = 100,
242 .scaleY = 1,
243 .transY = 50,
244 },
245 },
246 {
247 .type = kFlutterPlatformViewMutationTypeTransformation,
248 .transformation =
249 FlutterTransformation{
250 .scaleX = 1.5,
251 .transX = -7.5,
252 .scaleY = 1.5,
253 .transY = -5,
254 },
255 },
256 };
257
258 ApplyFlutterLayer(mutatorView, FlutterSize{30 * 2, 20 * 2}, mutations);
259
260 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(110, 55, 10, 10)));
261 EXPECT_TRUE(
262 CGRectEqualToRect(mutatorView.subviews.firstObject.frame, CGRectMake(-17.5, -10, 45, 30)));
263 EXPECT_TRUE(CGRectEqualToRect(platformView.frame, CGRectMake(0, 0, 30, 20)));
264 }
265
266 // Rounded rectangle without hitting the corner
267 TEST(FlutterMutatorViewTest, RoundRectClipsToSimpleRectangle) {
268 NSView* platformView = [[NSView alloc] init];
269 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
270
271 std::vector<FlutterPlatformViewMutation> mutations{
272 {
273 .type = kFlutterPlatformViewMutationTypeClipRoundedRect,
274 .clip_rounded_rect =
275 FlutterRoundedRect{
276 .rect = FlutterRect{110, 30, 120, 90},
277 .upper_left_corner_radius = FlutterSize{10, 10},
278 .upper_right_corner_radius = FlutterSize{10, 10},
279 .lower_right_corner_radius = FlutterSize{10, 10},
280 .lower_left_corner_radius = FlutterSize{10, 10},
281 },
282 },
283 {
284 .type = kFlutterPlatformViewMutationTypeTransformation,
285 .transformation =
286 FlutterTransformation{
287 .scaleX = 1,
288 .transX = 100,
289 .scaleY = 1,
290 .transY = 50,
291 },
292 },
293 };
294
295 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations);
296
297 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(110, 50, 10, 20)));
298 EXPECT_TRUE(
299 CGRectEqualToRect(mutatorView.subviews.firstObject.frame, CGRectMake(-10, 0, 30, 20)));
300 EXPECT_TRUE(CGRectEqualToRect(platformView.frame, CGRectMake(0, 0, 30, 20)));
301 EXPECT_EQ(mutatorView.pathClipViews.count, 0ul);
302 }
303
304 // Ensure that the mutator view, clip views, and container all use a flipped y axis. The transforms
305 // sent from the framework assume this, and so aside from the consistency with every other embedder,
306 // we can avoid a lot of extra math.
307 TEST(FlutterMutatorViewTest, ViewsSetIsFlipped) {
308 NSView* platformView = [[NSView alloc] init];
309 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
310
311 std::vector<FlutterPlatformViewMutation> mutations{
312 {
313 .type = kFlutterPlatformViewMutationTypeClipRoundedRect,
314 .clip_rounded_rect =
315 FlutterRoundedRect{
316 .rect = FlutterRect{110, 60, 150, 150},
317 .upper_left_corner_radius = FlutterSize{10, 10},
318 .upper_right_corner_radius = FlutterSize{10, 10},
319 .lower_right_corner_radius = FlutterSize{10, 10},
320 .lower_left_corner_radius = FlutterSize{10, 10},
321 },
322 },
323 {
324 .type = kFlutterPlatformViewMutationTypeTransformation,
325 .transformation =
326 FlutterTransformation{
327 .scaleX = 1,
328 .transX = 100,
329 .scaleY = 1,
330 .transY = 50,
331 },
332 },
333 };
334
335 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations);
336
337 EXPECT_TRUE(mutatorView.isFlipped);
338 ASSERT_EQ(mutatorView.pathClipViews.count, 1ul);
339 EXPECT_TRUE(mutatorView.pathClipViews.firstObject.isFlipped);
340 EXPECT_TRUE(mutatorView.platformViewContainer.isFlipped);
341 }
342
343 TEST(FlutterMutatorViewTest, RectsClipsToPathWhenRotated) {
344 NSView* platformView = [[NSView alloc] init];
345 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
346 std::vector<FlutterPlatformViewMutation> mutations{
347 {
348 .type = kFlutterPlatformViewMutationTypeTransformation,
349 // Roation M_PI / 8
350 .transformation =
351 FlutterTransformation{
352 .scaleX = 0.9238795325112867,
353 .skewX = -0.3826834323650898,
354 .skewY = 0.3826834323650898,
355 .scaleY = 0.9238795325112867,
356 },
357 },
358 {
359 .type = kFlutterPlatformViewMutationTypeClipRect,
360 .clip_rect = FlutterRect{110, 60, 150, 150},
361 },
362 {
363 .type = kFlutterPlatformViewMutationTypeTransformation,
364 .transformation =
365 FlutterTransformation{
366 .scaleX = 1,
367 .transX = 100,
368 .scaleY = 1,
369 .transY = 50,
370 },
371 },
372 };
373 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations);
374 EXPECT_EQ(mutatorView.pathClipViews.count, 1ul);
375 EXPECT_NEAR(mutatorView.platformViewContainer.frame.size.width, 35.370054622640396, kMaxErr);
376 EXPECT_NEAR(mutatorView.platformViewContainer.frame.size.height, 29.958093621178421, kMaxErr);
377 }
378
379 TEST(FlutterMutatorViewTest, RoundRectClipsToPath) {
380 NSView* platformView = [[NSView alloc] init];
381 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
382
383 std::vector<FlutterPlatformViewMutation> mutations{
384 {
385 .type = kFlutterPlatformViewMutationTypeClipRoundedRect,
386 .clip_rounded_rect =
387 FlutterRoundedRect{
388 .rect = FlutterRect{110, 60, 150, 150},
389 .upper_left_corner_radius = FlutterSize{10, 10},
390 .upper_right_corner_radius = FlutterSize{10, 10},
391 .lower_right_corner_radius = FlutterSize{10, 10},
392 .lower_left_corner_radius = FlutterSize{10, 10},
393 },
394 },
395 {
396 .type = kFlutterPlatformViewMutationTypeTransformation,
397 .transformation =
398 FlutterTransformation{
399 .scaleX = 1,
400 .transX = 100,
401 .scaleY = 1,
402 .transY = 50,
403 },
404 },
405 };
406
407 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations);
408
409 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(110, 60, 20, 10)));
410 EXPECT_TRUE(
411 CGRectEqualToRect(mutatorView.subviews.firstObject.frame, CGRectMake(-10, -10, 30, 20)));
412 EXPECT_TRUE(CGRectEqualToRect(platformView.frame, CGRectMake(0, 0, 30, 20)));
413 EXPECT_EQ(mutatorView.pathClipViews.count, 1ul);
414 ExpectTransform3DEqual(mutatorView.pathClipViews.firstObject.layer.mask.transform,
415 CATransform3DMakeTranslation(-100, -50, 0));
416 }
417
418 TEST(FlutterMutatorViewTest, PathClipViewsAreAddedAndRemoved) {
419 NSView* platformView = [[NSView alloc] init];
420 FlutterMutatorView* mutatorView = [[FlutterMutatorView alloc] initWithPlatformView:platformView];
421
422 std::vector<FlutterPlatformViewMutation> mutations{
423 {
424 .type = kFlutterPlatformViewMutationTypeTransformation,
425 .transformation =
426 FlutterTransformation{
427 .scaleX = 1,
428 .transX = 100,
429 .scaleY = 1,
430 .transY = 50,
431 },
432 },
433 };
434
435 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations);
436
437 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(100, 50, 30, 20)));
438 EXPECT_EQ(mutatorView.pathClipViews.count, 0ull);
439
440 std::vector<FlutterPlatformViewMutation> mutations2{
441 {
442 .type = kFlutterPlatformViewMutationTypeClipRoundedRect,
443 .clip_rounded_rect =
444 FlutterRoundedRect{
445 .rect = FlutterRect{110, 60, 150, 150},
446 .upper_left_corner_radius = FlutterSize{10, 10},
447 .upper_right_corner_radius = FlutterSize{10, 10},
448 .lower_right_corner_radius = FlutterSize{10, 10},
449 .lower_left_corner_radius = FlutterSize{10, 10},
450 },
451 },
452 {
453 .type = kFlutterPlatformViewMutationTypeTransformation,
454 .transformation =
455 FlutterTransformation{
456 .scaleX = 1,
457 .transX = 100,
458 .scaleY = 1,
459 .transY = 50,
460 },
461 },
462 };
463
464 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations2);
465
466 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(110, 60, 20, 10)));
467 EXPECT_TRUE(
468 CGRectEqualToRect(mutatorView.subviews.firstObject.frame, CGRectMake(-10, -10, 30, 20)));
469 EXPECT_TRUE(CGRectEqualToRect(platformView.frame, CGRectMake(0, 0, 30, 20)));
470 EXPECT_EQ(mutatorView.pathClipViews.count, 1ul);
471
472 EXPECT_EQ(platformView.superview, mutatorView.platformViewContainer);
473 EXPECT_EQ(mutatorView.platformViewContainer.superview, mutatorView.pathClipViews[0]);
474 EXPECT_EQ(mutatorView.pathClipViews[0].superview, mutatorView);
475
476 std::vector<FlutterPlatformViewMutation> mutations3{
477 {
478 .type = kFlutterPlatformViewMutationTypeClipRoundedRect,
479 .clip_rounded_rect =
480 FlutterRoundedRect{
481 .rect = FlutterRect{110, 55, 150, 150},
482 .upper_left_corner_radius = FlutterSize{10, 10},
483 .upper_right_corner_radius = FlutterSize{10, 10},
484 .lower_right_corner_radius = FlutterSize{10, 10},
485 .lower_left_corner_radius = FlutterSize{10, 10},
486 },
487 },
488 {
489 .type = kFlutterPlatformViewMutationTypeClipRoundedRect,
490 .clip_rounded_rect =
491 FlutterRoundedRect{
492 .rect = FlutterRect{30, 30, 120, 65},
493 .upper_left_corner_radius = FlutterSize{10, 10},
494 .upper_right_corner_radius = FlutterSize{10, 10},
495 .lower_right_corner_radius = FlutterSize{10, 10},
496 .lower_left_corner_radius = FlutterSize{10, 10},
497 },
498 },
499 {
500 .type = kFlutterPlatformViewMutationTypeTransformation,
501 .transformation =
502 FlutterTransformation{
503 .scaleX = 1,
504 .transX = 100,
505 .scaleY = 1,
506 .transY = 50,
507 },
508 },
509 };
510
511 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations3);
512
513 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(110, 55, 10, 10)));
514 EXPECT_TRUE(
515 CGRectEqualToRect(mutatorView.subviews.firstObject.frame, CGRectMake(-10, -5, 30, 20)));
516 EXPECT_EQ(mutatorView.pathClipViews.count, 2ul);
517
518 EXPECT_EQ(platformView.superview, mutatorView.platformViewContainer);
519 EXPECT_EQ(mutatorView.platformViewContainer.superview, mutatorView.pathClipViews[1]);
520 EXPECT_EQ(mutatorView.pathClipViews[1].superview, mutatorView.pathClipViews[0]);
521 EXPECT_EQ(mutatorView.pathClipViews[0].superview, mutatorView);
522
523 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations2);
524
525 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(110, 60, 20, 10)));
526 EXPECT_TRUE(
527 CGRectEqualToRect(mutatorView.subviews.firstObject.frame, CGRectMake(-10, -10, 30, 20)));
528 EXPECT_TRUE(CGRectEqualToRect(platformView.frame, CGRectMake(0, 0, 30, 20)));
529 EXPECT_EQ(mutatorView.pathClipViews.count, 1ul);
530
531 EXPECT_EQ(platformView.superview, mutatorView.platformViewContainer);
532 EXPECT_EQ(mutatorView.platformViewContainer.superview, mutatorView.pathClipViews[0]);
533 EXPECT_EQ(mutatorView.pathClipViews[0].superview, mutatorView);
534
535 ApplyFlutterLayer(mutatorView, FlutterSize{30, 20}, mutations);
536
537 EXPECT_TRUE(CGRectEqualToRect(mutatorView.frame, CGRectMake(100, 50, 30, 20)));
538 EXPECT_EQ(mutatorView.pathClipViews.count, 0ull);
539 }
FlutterMutatorView.h
FlutterMutatorView
Definition: FlutterMutatorView.h:11
FlutterMutatorView::platformView
NSView * platformView
Returns wrapped platform view.
Definition: FlutterMutatorView.h:17
FlutterMutatorView(Private)::pathClipViews
NSMutableArray< NSView * > * pathClipViews
Definition: FlutterMutatorViewTest.mm:11
kMaxErr
static constexpr float kMaxErr
Definition: FlutterMutatorViewTest.mm:16
FlutterMutatorView(Private)::platformViewContainer
NSView * platformViewContainer
Definition: FlutterMutatorViewTest.mm:12
FlutterMutatorView(Private)
Definition: FlutterMutatorViewTest.mm:9
TEST
TEST(FlutterMutatorViewTest, BasicFrameIsCorrect)
Definition: FlutterMutatorViewTest.mm:72
-[FlutterMutatorView applyFlutterLayer:]
void applyFlutterLayer:(nonnull const FlutterLayer *layer)