| Flutter macOS Embedder |

FlutterThreadSynchronizer.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/FlutterThreadSynchronizer.h"
6
7 #import <QuartzCore/QuartzCore.h>
8
9 #include <mutex>
10 #include <unordered_map>
11 #include <vector>
12
13 #import "flutter/fml/logging.h"
14 #import "flutter/fml/synchronization/waitable_event.h"
15
16 @interface FlutterThreadSynchronizer () {
17 dispatch_queue_t _mainQueue;
18 std::mutex _mutex;
19 BOOL _shuttingDown;
20 std::unordered_map<int64_t, CGSize> _contentSizes;
21 std::vector<dispatch_block_t> _scheduledBlocks;
22
23 BOOL _beginResizeWaiting;
24
25 // Used to block [beginResize:].
26 std::condition_variable _condBlockBeginResize;
27 }
28
29 /**
30 * Returns true if all existing views have a non-zero size.
31 *
32 * If there are no views, still returns true.
33 */
34 - (BOOL)allViewsHaveFrame;
35
36 /**
37 * Returns true if there are any views that have a non-zero size.
38 *
39 * If there are no views, returns false.
40 */
41 - (BOOL)someViewsHaveFrame;
42
43 @end
44
45 @implementation FlutterThreadSynchronizer
46
47 - (instancetype)init {
48 return [self initWithMainQueue:dispatch_get_main_queue()];
49 }
50
51 - (instancetype)initWithMainQueue:(dispatch_queue_t)queue {
52 self = [super init];
53 if (self != nil) {
54 _mainQueue = queue;
55 }
56 return self;
57 }
58
59 - (BOOL)allViewsHaveFrame {
60 for (auto const& [viewIdentifier, contentSize] : _contentSizes) {
61 if (CGSizeEqualToSize(contentSize, CGSizeZero)) {
62 return NO;
63 }
64 }
65 return YES;
66 }
67
68 - (BOOL)someViewsHaveFrame {
69 for (auto const& [viewIdentifier, contentSize] : _contentSizes) {
70 if (!CGSizeEqualToSize(contentSize, CGSizeZero)) {
71 return YES;
72 }
73 }
74 return NO;
75 }
76
77 - (void)drain {
78 dispatch_assert_queue(_mainQueue);
79
80 [CATransaction begin];
81 [CATransaction setDisableActions:YES];
82 for (dispatch_block_t block : _scheduledBlocks) {
83 block();
84 }
85 [CATransaction commit];
86 _scheduledBlocks.clear();
87 }
88
89 - (void)blockUntilFrameAvailable {
90 std::unique_lock<std::mutex> lock(_mutex);
91 [self drain];
92
93 _beginResizeWaiting = YES;
94 while (![self someViewsHaveFrame] && !_shuttingDown) {
95 _condBlockBeginResize.wait(lock);
96 [self drain];
97 }
98
99 _beginResizeWaiting = NO;
100 }
101
102 - (void)beginResizeForView:(FlutterViewIdentifier)viewIdentifier
103 size:(CGSize)size
104 notify:(nonnull dispatch_block_t)notify {
105 dispatch_assert_queue(_mainQueue);
106 std::unique_lock<std::mutex> lock(_mutex);
107
108 if (![self allViewsHaveFrame] || _shuttingDown) {
109 // No blocking until framework produces at least one frame
110 notify();
111 return;
112 }
113
114 [self drain];
115
116 notify();
117
118 _contentSizes[viewIdentifier] = CGSizeMake(-1, -1);
119
120 _beginResizeWaiting = YES;
121
122 while (true) {
123 if (_shuttingDown) {
124 break;
125 }
126 const CGSize& contentSize = _contentSizes[viewIdentifier];
127 if (CGSizeEqualToSize(contentSize, size) || CGSizeEqualToSize(contentSize, CGSizeZero)) {
128 break;
129 }
130 _condBlockBeginResize.wait(lock);
131 [self drain];
132 }
133
134 _beginResizeWaiting = NO;
135 }
136
137 - (void)performCommitForView:(FlutterViewIdentifier)viewIdentifier
138 size:(CGSize)size
139 notify:(nonnull dispatch_block_t)notify {
140 dispatch_assert_queue_not(_mainQueue);
141 fml::AutoResetWaitableEvent event;
142 {
143 std::unique_lock<std::mutex> lock(_mutex);
144 if (_shuttingDown) {
145 // Engine is shutting down, main thread may be blocked by the engine
146 // waiting for raster thread to finish.
147 return;
148 }
149 fml::AutoResetWaitableEvent& e = event;
150 _scheduledBlocks.push_back(^{
151 notify();
152 _contentSizes[viewIdentifier] = size;
153 e.Signal();
154 });
155 if (_beginResizeWaiting) {
156 _condBlockBeginResize.notify_all();
157 } else {
158 dispatch_async(_mainQueue, ^{
159 std::unique_lock<std::mutex> lock(_mutex);
160 [self drain];
161 });
162 }
163 }
164 event.Wait();
165 }
166
167 - (void)performOnPlatformThread:(nonnull dispatch_block_t)block {
168 std::unique_lock<std::mutex> lock(_mutex);
169 _scheduledBlocks.push_back(block);
170 if (_beginResizeWaiting) {
171 _condBlockBeginResize.notify_all();
172 } else {
173 dispatch_async(_mainQueue, ^{
174 std::unique_lock<std::mutex> lock(_mutex);
175 [self drain];
176 });
177 }
178 }
179
180 - (void)registerView:(FlutterViewIdentifier)viewIdentifier {
181 dispatch_assert_queue(_mainQueue);
182 std::unique_lock<std::mutex> lock(_mutex);
183 _contentSizes[viewIdentifier] = CGSizeZero;
184 }
185
186 - (void)deregisterView:(FlutterViewIdentifier)viewIdentifier {
187 dispatch_assert_queue(_mainQueue);
188 std::unique_lock<std::mutex> lock(_mutex);
189 _contentSizes.erase(viewIdentifier);
190 }
191
192 - (void)shutdown {
193 dispatch_assert_queue(_mainQueue);
194 std::unique_lock<std::mutex> lock(_mutex);
195 _shuttingDown = YES;
196 _condBlockBeginResize.notify_all();
197 [self drain];
198 }
199
200 - (BOOL)isWaitingWhenMutexIsAvailable {
201 std::unique_lock<std::mutex> lock(_mutex);
202 return _beginResizeWaiting;
203 }
204
205 @end
FlutterThreadSynchronizer.h
FlutterViewIdentifier
int64_t FlutterViewIdentifier
Definition: FlutterViewController.h:21
FlutterThreadSynchronizer()::_contentSizes
std::unordered_map< int64_t, CGSize > _contentSizes
Definition: FlutterThreadSynchronizer.mm:20
FlutterThreadSynchronizer()::_scheduledBlocks
std::vector< dispatch_block_t > _scheduledBlocks
Definition: FlutterThreadSynchronizer.mm:21
FlutterThreadSynchronizer()::_mutex
std::mutex _mutex
Definition: FlutterThreadSynchronizer.mm:18
FlutterThreadSynchronizer()::_beginResizeWaiting
BOOL _beginResizeWaiting
Definition: FlutterThreadSynchronizer.mm:23
FlutterThreadSynchronizer()::_mainQueue
dispatch_queue_t _mainQueue
Definition: FlutterThreadSynchronizer.mm:17
FlutterThreadSynchronizer()::_shuttingDown
BOOL _shuttingDown
Definition: FlutterThreadSynchronizer.mm:19
FlutterThreadSynchronizer()::_condBlockBeginResize
std::condition_variable _condBlockBeginResize
Definition: FlutterThreadSynchronizer.mm:26
-[FlutterThreadSynchronizer(TestUtils) blockUntilFrameAvailable]
void blockUntilFrameAvailable()
-[FlutterThreadSynchronizer(TestUtils) isWaitingWhenMutexIsAvailable]
BOOL isWaitingWhenMutexIsAvailable()
FlutterThreadSynchronizer
Definition: FlutterThreadSynchronizer.h:19
-[FlutterThreadSynchronizer shutdown]
void shutdown()
Definition: FlutterThreadSynchronizer.mm:192
-[FlutterThreadSynchronizer init]
nullable instancetype init()
Definition: FlutterThreadSynchronizer.mm:47