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 
6 
7 #import <AppKit/AppKit.h>
8 
9 #include "flutter/fml/synchronization/waitable_event.h"
10 #include "flutter/testing/testing.h"
11 
13  void (^_block)(CFTimeInterval timestamp, CFTimeInterval targetTimestamp);
14 }
15 
16 - (instancetype)initWithBlock:(void (^)(CFTimeInterval timestamp,
17  CFTimeInterval targetTimestamp))block;
18 
19 @end
20 
21 @implementation TestDisplayLinkDelegate
22 - (instancetype)initWithBlock:(void (^__strong)(CFTimeInterval, CFTimeInterval))block {
23  if (self = [super init]) {
24  _block = block;
25  }
26  return self;
27 }
28 
29 - (void)onDisplayLink:(CFTimeInterval)timestamp targetTimestamp:(CFTimeInterval)targetTimestamp {
30  _block(timestamp, targetTimestamp);
31 }
32 
33 @end
34 
35 TEST(FlutterDisplayLinkTest, ViewAddedToWindowFirst) {
36  NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
37  styleMask:NSWindowStyleMaskTitled
38  backing:NSBackingStoreNonretained
39  defer:NO];
40  NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
41  [window setContentView:view];
42 
43  auto event = std::make_shared<fml::AutoResetWaitableEvent>();
44 
46  initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
47  event->Signal();
48  }];
49 
51  displayLink.delegate = delegate;
52  displayLink.paused = NO;
53 
54  event->Wait();
55 
56  [displayLink invalidate];
57 }
58 
59 TEST(FlutterDisplayLinkTest, ViewAddedToWindowLater) {
60  NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
61 
62  auto event = std::make_shared<fml::AutoResetWaitableEvent>();
63 
65  initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
66  event->Signal();
67  }];
68 
70  displayLink.delegate = delegate;
71  displayLink.paused = NO;
72 
73  NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
74  styleMask:NSWindowStyleMaskTitled
75  backing:NSBackingStoreNonretained
76  defer:NO];
77  [window setContentView:view];
78 
79  event->Wait();
80 
81  [displayLink invalidate];
82 }
83 
84 TEST(FlutterDisplayLinkTest, ViewRemovedFromWindow) {
85  NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
86  styleMask:NSWindowStyleMaskTitled
87  backing:NSBackingStoreNonretained
88  defer:NO];
89  NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
90  [window setContentView:view];
91 
92  auto event = std::make_shared<fml::AutoResetWaitableEvent>();
93 
95  initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
96  event->Signal();
97  }];
98 
100  displayLink.delegate = delegate;
101  displayLink.paused = NO;
102 
103  event->Wait();
104  displayLink.paused = YES;
105 
106  event->Reset();
107 
108  displayLink.paused = NO;
109 
110  [window setContentView:nil];
111 
112  EXPECT_TRUE(event->WaitWithTimeout(fml::TimeDelta::FromMilliseconds(100)));
113  EXPECT_FALSE(event->IsSignaledForTest());
114 
115  [displayLink invalidate];
116 }
117 
118 TEST(FlutterDisplayLinkTest, WorkaroundForFB13482573) {
119  NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
120  styleMask:NSWindowStyleMaskTitled
121  backing:NSBackingStoreNonretained
122  defer:NO];
123  NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
124  [window setContentView:view];
125 
126  auto event = std::make_shared<fml::AutoResetWaitableEvent>();
127 
129  initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
130  event->Signal();
131  }];
132 
134  displayLink.delegate = delegate;
135  displayLink.paused = NO;
136 
137  event->Wait();
138  displayLink.paused = YES;
139 
140  event->Reset();
141  [NSThread detachNewThreadWithBlock:^{
142  // Here pthread_self() will be same as pthread_self inside first invocation of
143  // display link callback, causing CVDisplayLinkStart to return error.
144  displayLink.paused = NO;
145  }];
146 
147  event->Wait();
148 
149  [displayLink invalidate];
150 }