| Flutter macOS Embedder |

FlutterCompositor.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/FlutterCompositor.h"
6
7 #include "flutter/common/constants.h"
8 #include "flutter/fml/logging.h"
9
10 namespace flutter {
11
12 namespace {
13 std::vector<LayerVariant> CopyLayers(const FlutterLayer** layers, size_t layer_count) {
14 std::vector<LayerVariant> layers_copy;
15 for (size_t i = 0; i < layer_count; i++) {
16 const auto& layer = layers[i];
17 if (layer->type == kFlutterLayerContentTypePlatformView) {
18 layers_copy.push_back(PlatformViewLayer(layer));
19 } else if (layer->type == kFlutterLayerContentTypeBackingStore) {
20 std::vector<FlutterRect> rects;
21 auto present_info = layer->backing_store_present_info;
22 if (present_info != nullptr && present_info->paint_region != nullptr) {
23 rects.reserve(present_info->paint_region->rects_count);
24 std::copy(present_info->paint_region->rects,
25 present_info->paint_region->rects + present_info->paint_region->rects_count,
26 std::back_inserter(rects));
27 }
28 layers_copy.push_back(BackingStoreLayer{rects});
29 }
30 }
31 return layers_copy;
32 }
33 } // namespace
34
35 FlutterCompositor::FlutterCompositor(id<FlutterViewProvider> view_provider,
36 FlutterTimeConverter* time_converter,
37 FlutterPlatformViewController* platform_view_controller)
38 : view_provider_(view_provider),
39 time_converter_(time_converter),
40 platform_view_controller_(platform_view_controller) {
41 FML_CHECK(view_provider != nullptr) << "view_provider cannot be nullptr";
42 }
43
44 void FlutterCompositor::AddView(FlutterViewId view_id) {
45 dispatch_assert_queue(dispatch_get_main_queue());
46 presenters_.try_emplace(view_id);
47 }
48
49 void FlutterCompositor::RemoveView(FlutterViewId view_id) {
50 dispatch_assert_queue(dispatch_get_main_queue());
51 presenters_.erase(view_id);
52 }
53
54 bool FlutterCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config,
55 FlutterBackingStore* backing_store_out) {
56 FlutterView* view = [view_provider_ viewForIdentifier:config->view_id];
57 if (!view) {
58 return false;
59 }
60
61 CGSize size = CGSizeMake(config->size.width, config->size.height);
62 FlutterSurface* surface = [view.surfaceManager surfaceForSize:size];
63 memset(backing_store_out, 0, sizeof(FlutterBackingStore));
64 backing_store_out->struct_size = sizeof(FlutterBackingStore);
65 backing_store_out->type = kFlutterBackingStoreTypeMetal;
66 backing_store_out->metal.struct_size = sizeof(FlutterMetalBackingStore);
67 backing_store_out->metal.texture = surface.asFlutterMetalTexture;
68 return true;
69 }
70
71 bool FlutterCompositor::Present(FlutterViewIdentifier view_id,
72 const FlutterLayer** layers,
73 size_t layers_count) {
74 FlutterView* view = [view_provider_ viewForIdentifier:view_id];
75 if (!view) {
76 return false;
77 }
78
79 NSMutableArray* surfaces = [NSMutableArray array];
80 for (size_t i = 0; i < layers_count; i++) {
81 const FlutterLayer* layer = layers[i];
82 if (layer->type == kFlutterLayerContentTypeBackingStore) {
83 FlutterSurface* surface =
84 [FlutterSurface fromFlutterMetalTexture:&layer->backing_store->metal.texture];
85
86 if (surface) {
87 FlutterSurfacePresentInfo* info = [[FlutterSurfacePresentInfo alloc] init];
88 info.surface = surface;
89 info.offset = CGPointMake(layer->offset.x, layer->offset.y);
90 info.zIndex = i;
91 FlutterBackingStorePresentInfo* present_info = layer->backing_store_present_info;
92 if (present_info != nullptr && present_info->paint_region != nullptr) {
93 auto paint_region = present_info->paint_region;
94 // Safe because the size of FlutterRect is not expected to change.
95 info.paintRegion = std::vector<FlutterRect>(
96 paint_region->rects, paint_region->rects + paint_region->rects_count);
97 }
98 [surfaces addObject:info];
99 }
100 }
101 }
102
103 CFTimeInterval presentation_time = 0;
104
105 if (layers_count > 0 && layers[0]->presentation_time != 0) {
106 presentation_time = [time_converter_ engineTimeToCAMediaTime:layers[0]->presentation_time];
107 }
108
109 // Notify block below may be called asynchronously, hence the need to copy
110 // the layer information instead of passing the original pointers from embedder.
111 auto layers_copy = std::make_shared<std::vector<LayerVariant>>(CopyLayers(layers, layers_count));
112
113 [view.surfaceManager presentSurfaces:surfaces
114 atTime:presentation_time
115 notify:^{
116 // Accessing presenters_ here does not need a
117 // lock to avoid race condition against
118 // AddView and RemoveView, since all three
119 // take place on the platform thread. (The
120 // macOS API requires platform view presenting
121 // to take place on the platform thread,
122 // enforced by `FlutterThreadSynchronizer`.)
123 dispatch_assert_queue(dispatch_get_main_queue());
124 auto found_presenter = presenters_.find(view_id);
125 if (found_presenter != presenters_.end()) {
126 found_presenter->second.PresentPlatformViews(
127 view, *layers_copy, platform_view_controller_);
128 }
129 }];
130
131 return true;
132 }
133
134 size_t FlutterCompositor::DebugNumViews() {
135 return presenters_.size();
136 }
137
138 FlutterCompositor::ViewPresenter::ViewPresenter()
139 : mutator_views_([NSMapTable strongToStrongObjectsMapTable]) {}
140
141 void FlutterCompositor::ViewPresenter::PresentPlatformViews(
142 FlutterView* default_base_view,
143 const std::vector<LayerVariant>& layers,
144 const FlutterPlatformViewController* platform_view_controller) {
145 FML_DCHECK([[NSThread currentThread] isMainThread])
146 << "Must be on the main thread to present platform views";
147
148 // Active mutator views for this frame.
149 NSMutableArray<FlutterMutatorView*>* present_mutators = [NSMutableArray array];
150
151 for (size_t i = 0; i < layers.size(); i++) {
152 const auto& layer = layers[i];
153 if (!std::holds_alternative<PlatformViewLayer>(layer)) {
154 continue;
155 }
156 const auto& platform_view = std::get<PlatformViewLayer>(layer);
157 FlutterMutatorView* mutator_view =
158 PresentPlatformView(default_base_view, platform_view, i, platform_view_controller);
159 [present_mutators addObject:mutator_view];
160
161 // Gather all overlay regions above this mutator view.
162 [mutator_view resetHitTestRegion];
163 for (size_t j = i + 1; j < layers.size(); j++) {
164 const auto& overlay_layer = layers[j];
165 if (!std::holds_alternative<BackingStoreLayer>(overlay_layer)) {
166 continue;
167 }
168 const auto& backing_store_layer = std::get<BackingStoreLayer>(overlay_layer);
169 for (const auto& flutter_rect : backing_store_layer.paint_region) {
170 double scale = default_base_view.layer.contentsScale;
171 CGRect rect = CGRectMake(flutter_rect.left / scale, flutter_rect.top / scale,
172 (flutter_rect.right - flutter_rect.left) / scale,
173 (flutter_rect.bottom - flutter_rect.top) / scale);
174 CGRect intersection = CGRectIntersection(rect, mutator_view.frame);
175 if (!CGRectIsNull(intersection)) {
176 intersection.origin.x -= mutator_view.frame.origin.x;
177 intersection.origin.y -= mutator_view.frame.origin.y;
178 [mutator_view addHitTestIgnoreRegion:intersection];
179 }
180 }
181 }
182 }
183
184 NSMutableArray<FlutterMutatorView*>* obsolete_mutators =
185 [NSMutableArray arrayWithArray:[mutator_views_ objectEnumerator].allObjects];
186 [obsolete_mutators removeObjectsInArray:present_mutators];
187
188 for (FlutterMutatorView* mutator in obsolete_mutators) {
189 [mutator_views_ removeObjectForKey:mutator.platformView];
190 [mutator removeFromSuperview];
191 }
192
193 [platform_view_controller disposePlatformViews];
194 }
195
196 FlutterMutatorView* FlutterCompositor::ViewPresenter::PresentPlatformView(
197 FlutterView* default_base_view,
198 const PlatformViewLayer& layer,
199 size_t index,
200 const FlutterPlatformViewController* platform_view_controller) {
201 FML_DCHECK([[NSThread currentThread] isMainThread])
202 << "Must be on the main thread to present platform views";
203
204 int64_t platform_view_id = layer.identifier();
205 NSView* platform_view = [platform_view_controller platformViewWithID:platform_view_id];
206
207 FML_DCHECK(platform_view) << "Platform view not found for id: " << platform_view_id;
208
209 if (cursor_coordinator_ == nil) {
210 cursor_coordinator_ = [[FlutterCursorCoordinator alloc] initWithFlutterView:default_base_view];
211 }
212
213 FlutterMutatorView* container = [mutator_views_ objectForKey:platform_view];
214
215 if (!container) {
216 container = [[FlutterMutatorView alloc] initWithPlatformView:platform_view
217 cursorCoordiator:cursor_coordinator_];
218 [mutator_views_ setObject:container forKey:platform_view];
219 [default_base_view addSubview:container];
220 }
221
222 container.layer.zPosition = index;
223 [container applyFlutterLayer:&layer];
224
225 return container;
226 }
227
228 } // namespace flutter
FlutterView::surfaceManager
FlutterSurfaceManager * surfaceManager
Definition: FlutterView.h:57
FlutterMutatorView
Definition: FlutterMutatorView.h:63
FlutterCursorCoordinator
Definition: FlutterMutatorView.h:45
-[FlutterSurface asFlutterMetalTexture]
FlutterMetalTexture asFlutterMetalTexture()
Definition: FlutterSurface.mm:56
flutter::FlutterCompositor::RemoveView
void RemoveView(FlutterViewId view_id)
Definition: FlutterCompositor.mm:49
FlutterPlatformViewController
Definition: FlutterPlatformViewController.h:17
flutter::FlutterCompositor::DebugNumViews
size_t DebugNumViews()
Definition: FlutterCompositor.mm:134
FlutterSurface
Definition: FlutterSurface.h:16
flutter::FlutterCompositor::FlutterCompositor
FlutterCompositor(id< FlutterViewProvider > view_provider, FlutterTimeConverter *time_converter, FlutterPlatformViewController *platform_views_controller)
Definition: FlutterCompositor.mm:35
flutter::FlutterCompositor::CreateBackingStore
bool CreateBackingStore(const FlutterBackingStoreConfig *config, FlutterBackingStore *backing_store_out)
Definition: FlutterCompositor.mm:54
FlutterSurfacePresentInfo::surface
FlutterSurface * surface
Definition: FlutterSurfaceManager.h:20
flutter
Definition: AccessibilityBridgeMac.h:16
flutter::FlutterCompositor::Present
bool Present(FlutterViewIdentifier view_id, const FlutterLayer **layers, size_t layers_count)
Definition: FlutterCompositor.mm:71
FlutterSurfacePresentInfo::offset
CGPoint offset
Definition: FlutterSurfaceManager.h:21
FlutterTimeConverter
Converts between the time representation used by Flutter Engine and CAMediaTime.
Definition: FlutterTimeConverter.h:13
FlutterSurfacePresentInfo
Definition: FlutterSurfaceManager.h:18
FlutterSurfacePresentInfo::zIndex
size_t zIndex
Definition: FlutterSurfaceManager.h:22
FlutterView
Definition: FlutterView.h:35
FlutterSurfacePresentInfo::paintRegion
std::vector< FlutterRect > paintRegion
Definition: FlutterSurfaceManager.h:23
flutter::FlutterCompositor::AddView
void AddView(FlutterViewId view_id)
Definition: FlutterCompositor.mm:44
FlutterViewIdentifier
int64_t FlutterViewIdentifier
Definition: FlutterViewController.h:21
FlutterCompositor.h