5#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDisplayLink.h"
7#import <AppKit/AppKit.h>
10#include "flutter/fml/synchronization/waitable_event.h"
11#include "flutter/testing/testing.h"
14 void (^
_block)(CFTimeInterval timestamp, CFTimeInterval targetTimestamp);
17- (instancetype)initWithBlock:(
void (^)(CFTimeInterval timestamp,
18 CFTimeInterval targetTimestamp))block;
23- (instancetype)initWithBlock:(
void (^__strong)(CFTimeInterval, CFTimeInterval))block {
30- (void)onDisplayLink:(CFTimeInterval)timestamp targetTimestamp:(CFTimeInterval)targetTimestamp {
31 _block(timestamp, targetTimestamp);
36TEST(FlutterDisplayLinkTest, ViewAddedToWindowFirst) {
37 NSWindow*
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
38 styleMask:NSWindowStyleMaskTitled
39 backing:NSBackingStoreNonretained
41 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
42 [window setContentView:view];
44 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
47 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
60TEST(FlutterDisplayLinkTest, ViewAddedToWindowLater) {
61 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
63 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
66 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
74 NSWindow*
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
75 styleMask:NSWindowStyleMaskTitled
76 backing:NSBackingStoreNonretained
78 [window setContentView:view];
85TEST(FlutterDisplayLinkTest, ViewRemovedFromWindow) {
86 NSWindow*
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
87 styleMask:NSWindowStyleMaskTitled
88 backing:NSBackingStoreNonretained
90 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
91 [window setContentView:view];
93 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
96 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
111 [window setContentView:nil];
114 EXPECT_FALSE(
event->IsSignaledForTest());
119TEST(FlutterDisplayLinkTest, WorkaroundForFB13482573) {
120 NSWindow*
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
121 styleMask:NSWindowStyleMaskTitled
122 backing:NSBackingStoreNonretained
124 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
125 [window setContentView:view];
127 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
130 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
142 [NSThread detachNewThreadWithBlock:^{
145 displayLink.paused = NO;
153TEST(FlutterDisplayLinkTest, CVDisplayLinkInterval) {
154 CVDisplayLinkRef
link;
155 CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &
link);
156 __block CFTimeInterval last = 0;
157 auto intervals = std::make_shared<std::vector<CFTimeInterval>>();
158 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
159 CVDisplayLinkSetOutputHandler(
160 link, ^(CVDisplayLinkRef displayLink,
const CVTimeStamp* inNow,
161 const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut) {
163 intervals->push_back(CACurrentMediaTime() - last);
165 last = CACurrentMediaTime();
166 if (intervals->size() == 10) {
172 CVDisplayLinkStart(
link);
174 CVDisplayLinkStop(
link);
175 CVDisplayLinkRelease(
link);
176 CFTimeInterval average = std::reduce(intervals->begin(), intervals->end()) / intervals->size();
177 CFTimeInterval
max = *std::max_element(intervals->begin(), intervals->end());
178 CFTimeInterval
min = *std::min_element(intervals->begin(), intervals->end());
179 NSLog(
@"CVDisplayLink Interval: Average: %fs, Max: %fs, Min: %fs", average,
max,
min);
TEST(FlutterDisplayLinkTest, ViewAddedToWindowFirst)
static constexpr TimeDelta FromMilliseconds(int64_t millis)
static float max(float r, float g, float b)
static float min(float r, float g, float b)
void invalidate()
Invalidates the display link. Must be called on the main thread.
BOOL paused
Pauses and resumes the display link. May be called from any thread.
id< FlutterDisplayLinkDelegate > delegate
instancetype displayLinkWithView:(NSView *view)
void(^ _block)(CFTimeInterval timestamp, CFTimeInterval targetTimestamp)
def link(from_root, to_root)
#define EXPECT_TRUE(handle)