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