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 
6 
7 #include "third_party/googletest/googletest/include/gtest/gtest.h"
8 
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)