| Flutter macOS Embedder |

FlutterDisplayLinkTest.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/FlutterDisplayLink.h"
6
7 #import <AppKit/AppKit.h>
8
9 #include <numeric>
10
11 #include "flutter/fml/synchronization/waitable_event.h"
12 #import "flutter/shell/platform/darwin/macos/InternalFlutterSwift/InternalFlutterSwift.h"
13 #include "flutter/testing/testing.h"
14
15 @interface TestDisplayLinkDelegate : NSObject <FlutterDisplayLinkDelegate> {
16 void (^_block)(CFTimeInterval timestamp, CFTimeInterval targetTimestamp);
17 }
18
19 - (instancetype)initWithBlock:(void (^)(CFTimeInterval timestamp,
20 CFTimeInterval targetTimestamp))block;
21
22 @end
23
24 @implementation TestDisplayLinkDelegate
25 - (instancetype)initWithBlock:(void (^__strong)(CFTimeInterval, CFTimeInterval))block {
26 if (self = [super init]) {
27 _block = block;
28 }
29 return self;
30 }
31
32 - (void)onDisplayLink:(CFTimeInterval)timestamp targetTimestamp:(CFTimeInterval)targetTimestamp {
33 _block(timestamp, targetTimestamp);
34 }
35
36 @end
37
38 class FlutterDisplayLinkTest : public testing::Test {
39 public:
40 void SetUp() override { [FlutterRunLoop ensureMainLoopInitialized]; }
41 };
42
43 TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowFirst) {
44 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
45 styleMask:NSWindowStyleMaskTitled
46 backing:NSBackingStoreNonretained
47 defer:NO];
48 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
49 [window setContentView:view];
50
51 __block BOOL signalled = NO;
52
53 TestDisplayLinkDelegate* delegate = [[TestDisplayLinkDelegate alloc]
54 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
55 signalled = YES;
56 }];
57
58 FlutterDisplayLink* displayLink = [FlutterDisplayLink displayLinkWithView:view];
59 displayLink.delegate = delegate;
60 displayLink.paused = NO;
61
62 while (!signalled) {
63 [FlutterRunLoop.mainRunLoop pollFlutterMessagesOnce];
64 }
65
66 [displayLink invalidate];
67 }
68
69 TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowLater) {
70 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
71
72 __block BOOL signalled = NO;
73
74 TestDisplayLinkDelegate* delegate = [[TestDisplayLinkDelegate alloc]
75 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
76 signalled = YES;
77 }];
78
79 FlutterDisplayLink* displayLink = [FlutterDisplayLink displayLinkWithView:view];
80 displayLink.delegate = delegate;
81 displayLink.paused = NO;
82
83 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
84 styleMask:NSWindowStyleMaskTitled
85 backing:NSBackingStoreNonretained
86 defer:NO];
87 [window setContentView:view];
88
89 while (!signalled) {
90 [FlutterRunLoop.mainRunLoop pollFlutterMessagesOnce];
91 }
92
93 [displayLink invalidate];
94 }
95
96 TEST_F(FlutterDisplayLinkTest, ViewRemovedFromWindow) {
97 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
98 styleMask:NSWindowStyleMaskTitled
99 backing:NSBackingStoreNonretained
100 defer:NO];
101 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
102 [window setContentView:view];
103
104 __block BOOL signalled = NO;
105
106 TestDisplayLinkDelegate* delegate = [[TestDisplayLinkDelegate alloc]
107 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
108 signalled = YES;
109 }];
110
111 FlutterDisplayLink* displayLink = [FlutterDisplayLink displayLinkWithView:view];
112 displayLink.delegate = delegate;
113 displayLink.paused = NO;
114
115 while (!signalled) {
116 [FlutterRunLoop.mainRunLoop pollFlutterMessagesOnce];
117 }
118 displayLink.paused = YES;
119
120 signalled = false;
121
122 displayLink.paused = NO;
123
124 [window setContentView:nil];
125
126 CFTimeInterval start = CACurrentMediaTime();
127 while (CACurrentMediaTime() < start + 0.1) {
128 [FlutterRunLoop.mainRunLoop pollFlutterMessagesOnce];
129 }
130
131 EXPECT_FALSE(signalled);
132
133 [displayLink invalidate];
134 }
135
136 TEST_F(FlutterDisplayLinkTest, CVDisplayLinkInterval) {
137 CVDisplayLinkRef link;
138 CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &link);
139 __block CFTimeInterval last = 0;
140 auto intervals = std::make_shared<std::vector<CFTimeInterval>>();
141 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
142 CVDisplayLinkSetOutputHandler(
143 link, ^(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow,
144 const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut) {
145 if (last != 0) {
146 intervals->push_back(CACurrentMediaTime() - last);
147 }
148 last = CACurrentMediaTime();
149 if (intervals->size() == 10) {
150 event->Signal();
151 }
152 return 0;
153 });
154
155 CVDisplayLinkStart(link);
156 event->Wait();
157 CVDisplayLinkStop(link);
158 CVDisplayLinkRelease(link);
159 CFTimeInterval average = std::reduce(intervals->begin(), intervals->end()) / intervals->size();
160 CFTimeInterval max = *std::max_element(intervals->begin(), intervals->end());
161 CFTimeInterval min = *std::min_element(intervals->begin(), intervals->end());
162 NSLog(@"CVDisplayLink Interval: Average: %fs, Max: %fs, Min: %fs", average, max, min);
163 }
FlutterDisplayLink.h
TEST_F
TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowFirst)
Definition: FlutterDisplayLinkTest.mm:43
FlutterDisplayLinkTest
Definition: FlutterDisplayLinkTest.mm:38
FlutterDisplayLinkTest::SetUp
void SetUp() override
Definition: FlutterDisplayLinkTest.mm:40
FlutterDisplayLink
Definition: FlutterDisplayLink.h:22
-[FlutterDisplayLink invalidate]
void invalidate()
Invalidates the display link.
Definition: FlutterDisplayLink.mm:296
FlutterDisplayLink::paused
BOOL paused
Pauses and resumes the display link.
Definition: FlutterDisplayLink.h:33
FlutterDisplayLink::delegate
id< FlutterDisplayLinkDelegate > delegate
Definition: FlutterDisplayLink.h:30
+[FlutterDisplayLink displayLinkWithView:]
instancetype displayLinkWithView:(NSView *view)
Definition: FlutterDisplayLink.mm:292
TestDisplayLinkDelegate
Definition: FlutterDisplayLinkTest.mm:15
TestDisplayLinkDelegate::_block
void(^ _block)(CFTimeInterval timestamp, CFTimeInterval targetTimestamp)
FlutterDisplayLinkDelegate-p
Definition: FlutterDisplayLink.h:9