Flutter iOS Embedder
overlay_layer_pool.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 
9 
10 namespace flutter {
11 
12 OverlayLayer::OverlayLayer(const fml::scoped_nsobject<UIView>& overlay_view,
13  const fml::scoped_nsobject<UIView>& overlay_view_wrapper,
14  std::unique_ptr<IOSSurface> ios_surface,
15  std::unique_ptr<Surface> surface)
16  : overlay_view(overlay_view),
17  overlay_view_wrapper(overlay_view_wrapper),
18  ios_surface(std::move(ios_surface)),
19  surface(std::move(surface)){};
20 
21 void OverlayLayer::UpdateViewState(UIView* flutter_view,
22  SkRect rect,
23  int64_t view_id,
24  int64_t overlay_id) {
25  UIView* overlay_view_wrapper = this->overlay_view_wrapper.get();
26  auto screenScale = [UIScreen mainScreen].scale;
27  // Set the size of the overlay view wrapper.
28  // This wrapper view masks the overlay view.
29  overlay_view_wrapper.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale,
30  rect.width() / screenScale, rect.height() / screenScale);
31  // Set a unique view identifier, so the overlay_view_wrapper can be identified in XCUITests.
32  overlay_view_wrapper.accessibilityIdentifier =
33  [NSString stringWithFormat:@"platform_view[%lld].overlay[%lld]", view_id, overlay_id];
34 
35  UIView* overlay_view = this->overlay_view.get();
36  // Set the size of the overlay view.
37  // This size is equal to the device screen size.
38  overlay_view.frame = [flutter_view convertRect:flutter_view.bounds toView:overlay_view_wrapper];
39  // Set a unique view identifier, so the overlay_view can be identified in XCUITests.
40  overlay_view.accessibilityIdentifier =
41  [NSString stringWithFormat:@"platform_view[%lld].overlay_view[%lld]", view_id, overlay_id];
42 }
43 
44 // OverlayLayerPool
45 ////////////////////////////////////////////////////////
46 
47 std::shared_ptr<OverlayLayer> OverlayLayerPool::GetNextLayer() {
48  std::shared_ptr<OverlayLayer> result;
49  if (available_layer_index_ < layers_.size()) {
50  result = layers_[available_layer_index_];
51  available_layer_index_++;
52  }
53 
54  return result;
55 }
56 
57 void OverlayLayerPool::CreateLayer(GrDirectContext* gr_context,
58  const std::shared_ptr<IOSContext>& ios_context,
59  MTLPixelFormat pixel_format) {
60  FML_DCHECK([[NSThread currentThread] isMainThread]);
61  std::shared_ptr<OverlayLayer> layer;
62  fml::scoped_nsobject<UIView> overlay_view;
63  fml::scoped_nsobject<UIView> overlay_view_wrapper;
64 
65  bool impeller_enabled = !!ios_context->GetImpellerContext();
66  if (!gr_context && !impeller_enabled) {
67  overlay_view.reset([[FlutterOverlayView alloc] init]);
68  overlay_view_wrapper.reset([[FlutterOverlayView alloc] init]);
69 
70  auto ca_layer = fml::scoped_nsobject<CALayer>{[overlay_view.get() layer]};
71  std::unique_ptr<IOSSurface> ios_surface = IOSSurface::Create(ios_context, ca_layer);
72  std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
73 
74  layer = std::make_shared<OverlayLayer>(std::move(overlay_view), std::move(overlay_view_wrapper),
75  std::move(ios_surface), std::move(surface));
76  } else {
77  CGFloat screenScale = [UIScreen mainScreen].scale;
78  overlay_view.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale
79  pixelFormat:pixel_format]);
80  overlay_view_wrapper.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale
81  pixelFormat:pixel_format]);
82 
83  auto ca_layer = fml::scoped_nsobject<CALayer>{[overlay_view.get() layer]};
84  std::unique_ptr<IOSSurface> ios_surface = IOSSurface::Create(ios_context, ca_layer);
85  std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
86 
87  layer = std::make_shared<OverlayLayer>(std::move(overlay_view), std::move(overlay_view_wrapper),
88  std::move(ios_surface), std::move(surface));
89  layer->gr_context = gr_context;
90  }
91  // The overlay view wrapper masks the overlay view.
92  // This is required to keep the backing surface size unchanged between frames.
93  //
94  // Otherwise, changing the size of the overlay would require a new surface,
95  // which can be very expensive.
96  //
97  // This is the case of an animation in which the overlay size is changing in every frame.
98  //
99  // +------------------------+
100  // | overlay_view |
101  // | +--------------+ | +--------------+
102  // | | wrapper | | == mask => | overlay_view |
103  // | +--------------+ | +--------------+
104  // +------------------------+
105  layer->overlay_view_wrapper.get().clipsToBounds = YES;
106  [layer->overlay_view_wrapper.get() addSubview:layer->overlay_view];
107 
108  layers_.push_back(layer);
109 }
110 
112  available_layer_index_ = 0;
113 }
114 
115 std::vector<std::shared_ptr<OverlayLayer>> OverlayLayerPool::RemoveUnusedLayers() {
116  std::vector<std::shared_ptr<OverlayLayer>> results;
117  for (size_t i = available_layer_index_; i < layers_.size(); i++) {
118  results.push_back(layers_[i]);
119  }
120  // Leave at least one overlay layer, to work around cases where scrolling
121  // platform views under an app bar continually adds and removes an
122  // overlay layer. This logic could be removed if https://github.com/flutter/flutter/issues/150646
123  // is fixed.
124  static constexpr size_t kLeakLayerCount = 1;
125  size_t erase_offset = std::max(available_layer_index_, kLeakLayerCount);
126  if (erase_offset < layers_.size()) {
127  layers_.erase(layers_.begin() + erase_offset, layers_.end());
128  }
129  return results;
130 }
131 
132 size_t OverlayLayerPool::size() const {
133  return layers_.size();
134 }
135 
136 } // namespace flutter
flutter::OverlayLayerPool::GetNextLayer
std::shared_ptr< OverlayLayer > GetNextLayer()
Gets a layer from the pool if available.
Definition: overlay_layer_pool.mm:47
flutter::OverlayLayerPool::CreateLayer
void CreateLayer(GrDirectContext *gr_context, const std::shared_ptr< IOSContext > &ios_context, MTLPixelFormat pixel_format)
Create a new overlay layer.
Definition: overlay_layer_pool.mm:57
flutter::OverlayLayerPool::size
size_t size() const
The count of layers currently in the pool.
Definition: overlay_layer_pool.mm:132
ios_surface.h
flutter
Definition: accessibility_bridge.h:28
FlutterOverlayView.h
flutter::OverlayLayerPool::RecycleLayers
void RecycleLayers()
Marks the layers in the pool as available for reuse.
Definition: overlay_layer_pool.mm:111
flutter::OverlayLayerPool::RemoveUnusedLayers
std::vector< std::shared_ptr< OverlayLayer > > RemoveUnusedLayers()
Removes unused layers from the pool. Returns the unused layers.
Definition: overlay_layer_pool.mm:115
FlutterOverlayView
Definition: FlutterOverlayView.h:22
overlay_layer_pool.h
flutter::IOSSurface::Create
static std::unique_ptr< IOSSurface > Create(std::shared_ptr< IOSContext > context, const fml::scoped_nsobject< CALayer > &layer)
Definition: ios_surface.mm:19
flutter::OverlayLayer::OverlayLayer
OverlayLayer(const fml::scoped_nsobject< UIView > &overlay_view, const fml::scoped_nsobject< UIView > &overlay_view_wrapper, std::unique_ptr< IOSSurface > ios_surface, std::unique_ptr< Surface > surface)
Definition: overlay_layer_pool.mm:12
flutter::OverlayLayer::overlay_view
fml::scoped_nsobject< UIView > overlay_view
Definition: overlay_layer_pool.h:31
flutter::OverlayLayer::overlay_view_wrapper
fml::scoped_nsobject< UIView > overlay_view_wrapper
Definition: overlay_layer_pool.h:32
flutter::OverlayLayer::UpdateViewState
void UpdateViewState(UIView *flutter_view, SkRect rect, int64_t view_id, int64_t overlay_id)
Definition: overlay_layer_pool.mm:21