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