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