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 
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 bool FlutterCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config,
45  FlutterBackingStore* backing_store_out) {
46  // TODO(dkwingsmt): This class only supports single-view for now. As more
47  // classes are gradually converted to multi-view, it should get the view ID
48  // from somewhere.
49  FlutterView* view = [view_provider_ viewForIdentifier:kFlutterImplicitViewId];
50  if (!view) {
51  return false;
52  }
53 
54  CGSize size = CGSizeMake(config->size.width, config->size.height);
55  FlutterSurface* surface = [view.surfaceManager surfaceForSize:size];
56  memset(backing_store_out, 0, sizeof(FlutterBackingStore));
57  backing_store_out->struct_size = sizeof(FlutterBackingStore);
58  backing_store_out->type = kFlutterBackingStoreTypeMetal;
59  backing_store_out->metal.struct_size = sizeof(FlutterMetalBackingStore);
60  backing_store_out->metal.texture = surface.asFlutterMetalTexture;
61  return true;
62 }
63 
65  const FlutterLayer** layers,
66  size_t layers_count) {
67  FlutterView* view = [view_provider_ viewForIdentifier:view_id];
68  if (!view) {
69  return false;
70  }
71 
72  NSMutableArray* surfaces = [NSMutableArray array];
73  for (size_t i = 0; i < layers_count; i++) {
74  const FlutterLayer* layer = layers[i];
75  if (layer->type == kFlutterLayerContentTypeBackingStore) {
76  FlutterSurface* surface =
77  [FlutterSurface fromFlutterMetalTexture:&layer->backing_store->metal.texture];
78 
79  if (surface) {
81  info.surface = surface;
82  info.offset = CGPointMake(layer->offset.x, layer->offset.y);
83  info.zIndex = i;
84  FlutterBackingStorePresentInfo* present_info = layer->backing_store_present_info;
85  if (present_info != nullptr && present_info->paint_region != nullptr) {
86  auto paint_region = present_info->paint_region;
87  // Safe because the size of FlutterRect is not expected to change.
88  info.paintRegion = std::vector<FlutterRect>(
89  paint_region->rects, paint_region->rects + paint_region->rects_count);
90  }
91  [surfaces addObject:info];
92  }
93  }
94  }
95 
96  CFTimeInterval presentation_time = 0;
97 
98  if (layers_count > 0 && layers[0]->presentation_time != 0) {
99  presentation_time = [time_converter_ engineTimeToCAMediaTime:layers[0]->presentation_time];
100  }
101 
102  // Notify block below may be called asynchronously, hence the need to copy
103  // the layer information instead of passing the original pointers from embedder.
104  auto layers_copy = std::make_shared<std::vector<LayerVariant>>(CopyLayers(layers, layers_count));
105 
106  [view.surfaceManager
107  presentSurfaces:surfaces
108  atTime:presentation_time
109  notify:^{
110  // Gets a presenter or create a new one for the view.
111  ViewPresenter& presenter = presenters_[view_id];
112  presenter.PresentPlatformViews(view, *layers_copy, platform_view_controller_);
113  }];
114 
115  return true;
116 }
117 
118 FlutterCompositor::ViewPresenter::ViewPresenter()
119  : mutator_views_([NSMapTable strongToStrongObjectsMapTable]) {}
120 
121 void FlutterCompositor::ViewPresenter::PresentPlatformViews(
122  FlutterView* default_base_view,
123  const std::vector<LayerVariant>& layers,
124  const FlutterPlatformViewController* platform_view_controller) {
125  FML_DCHECK([[NSThread currentThread] isMainThread])
126  << "Must be on the main thread to present platform views";
127 
128  // Active mutator views for this frame.
129  NSMutableArray<FlutterMutatorView*>* present_mutators = [NSMutableArray array];
130 
131  for (size_t i = 0; i < layers.size(); i++) {
132  const auto& layer = layers[i];
133  if (!std::holds_alternative<PlatformViewLayer>(layer)) {
134  continue;
135  }
136  const auto& platform_view = std::get<PlatformViewLayer>(layer);
137  FlutterMutatorView* mutator_view =
138  PresentPlatformView(default_base_view, platform_view, i, platform_view_controller);
139  [present_mutators addObject:mutator_view];
140 
141  // Gather all overlay regions above this mutator view.
142  [mutator_view resetHitTestRegion];
143  for (size_t j = i + 1; j < layers.size(); j++) {
144  const auto& overlay_layer = layers[j];
145  if (!std::holds_alternative<BackingStoreLayer>(overlay_layer)) {
146  continue;
147  }
148  const auto& backing_store_layer = std::get<BackingStoreLayer>(overlay_layer);
149  for (const auto& flutter_rect : backing_store_layer.paint_region) {
150  double scale = default_base_view.layer.contentsScale;
151  CGRect rect = CGRectMake(flutter_rect.left / scale, flutter_rect.top / scale,
152  (flutter_rect.right - flutter_rect.left) / scale,
153  (flutter_rect.bottom - flutter_rect.top) / scale);
154  CGRect intersection = CGRectIntersection(rect, mutator_view.frame);
155  if (!CGRectIsNull(intersection)) {
156  intersection.origin.x -= mutator_view.frame.origin.x;
157  intersection.origin.y -= mutator_view.frame.origin.y;
158  [mutator_view addHitTestIgnoreRegion:intersection];
159  }
160  }
161  }
162  }
163 
164  NSMutableArray<FlutterMutatorView*>* obsolete_mutators =
165  [NSMutableArray arrayWithArray:[mutator_views_ objectEnumerator].allObjects];
166  [obsolete_mutators removeObjectsInArray:present_mutators];
167 
168  for (FlutterMutatorView* mutator in obsolete_mutators) {
169  [mutator_views_ removeObjectForKey:mutator.platformView];
170  [mutator removeFromSuperview];
171  }
172 
173  [platform_view_controller disposePlatformViews];
174 }
175 
176 FlutterMutatorView* FlutterCompositor::ViewPresenter::PresentPlatformView(
177  FlutterView* default_base_view,
178  const PlatformViewLayer& layer,
179  size_t index,
180  const FlutterPlatformViewController* platform_view_controller) {
181  FML_DCHECK([[NSThread currentThread] isMainThread])
182  << "Must be on the main thread to present platform views";
183 
184  int64_t platform_view_id = layer.identifier();
185  NSView* platform_view = [platform_view_controller platformViewWithID:platform_view_id];
186 
187  FML_DCHECK(platform_view) << "Platform view not found for id: " << platform_view_id;
188 
189  if (cursor_coordinator_ == nil) {
190  cursor_coordinator_ = [[FlutterCursorCoordinator alloc] initWithFlutterView:default_base_view];
191  }
192 
193  FlutterMutatorView* container = [mutator_views_ objectForKey:platform_view];
194 
195  if (!container) {
196  container = [[FlutterMutatorView alloc] initWithPlatformView:platform_view
197  cursorCoordiator:cursor_coordinator_];
198  [mutator_views_ setObject:container forKey:platform_view];
199  [default_base_view addSubview:container];
200  }
201 
202  container.layer.zPosition = index;
203  [container applyFlutterLayer:&layer];
204 
205  return container;
206 }
207 
208 } // 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:59
FlutterPlatformViewController
Definition: FlutterPlatformViewController.h:17
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:44
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:64
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
FlutterViewIdentifier
int64_t FlutterViewIdentifier
Definition: FlutterViewController.h:21
FlutterCompositor.h