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 
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 
17  dispatch_queue_t _mainQueue;
18  std::mutex _mutex;
20  std::unordered_map<int64_t, CGSize> _contentSizes;
21  std::vector<dispatch_block_t> _scheduledBlocks;
22 
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 
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 
201  std::unique_lock<std::mutex> lock(_mutex);
202  return _beginResizeWaiting;
203 }
204 
205 @end
FlutterThreadSynchronizer()::_scheduledBlocks
std::vector< dispatch_block_t > _scheduledBlocks
Definition: FlutterThreadSynchronizer.mm:21
FlutterThreadSynchronizer()::_shuttingDown
BOOL _shuttingDown
Definition: FlutterThreadSynchronizer.mm:19
-[FlutterThreadSynchronizer init]
nullable instancetype init()
Definition: FlutterThreadSynchronizer.mm:47
-[FlutterThreadSynchronizer(TestUtils) isWaitingWhenMutexIsAvailable]
BOOL isWaitingWhenMutexIsAvailable()
-[FlutterThreadSynchronizer initWithMainQueue:]
nullable instancetype initWithMainQueue:(nonnull dispatch_queue_t queue)
FlutterThreadSynchronizer()::_beginResizeWaiting
BOOL _beginResizeWaiting
Definition: FlutterThreadSynchronizer.mm:23
FlutterThreadSynchronizer()::_mutex
std::mutex _mutex
Definition: FlutterThreadSynchronizer.mm:18
FlutterThreadSynchronizer()::_mainQueue
dispatch_queue_t _mainQueue
Definition: FlutterThreadSynchronizer.mm:17
FlutterThreadSynchronizer
Definition: FlutterThreadSynchronizer.h:18
FlutterThreadSynchronizer()::_condBlockBeginResize
std::condition_variable _condBlockBeginResize
Definition: FlutterThreadSynchronizer.mm:26
FlutterThreadSynchronizer()::_contentSizes
std::unordered_map< int64_t, CGSize > _contentSizes
Definition: FlutterThreadSynchronizer.mm:20
FlutterThreadSynchronizer.h
-[FlutterThreadSynchronizer(TestUtils) blockUntilFrameAvailable]
void blockUntilFrameAvailable()
FlutterViewIdentifier
int64_t FlutterViewIdentifier
Definition: FlutterViewController.h:21
-[FlutterThreadSynchronizer shutdown]
void shutdown()
Definition: FlutterThreadSynchronizer.mm:192