Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 20d0b16

Browse files
author
Emmanuel Garcia
committed
Don't change the overlay surface size
1 parent f3db36b commit 20d0b16

File tree

5 files changed

+59
-33
lines changed

5 files changed

+59
-33
lines changed

shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ - (instancetype)init {
3939
if (self) {
4040
self.layer.opaque = NO;
4141
self.userInteractionEnabled = NO;
42+
self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
4243
}
4344

4445
return self;

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,50 @@
2626
std::shared_ptr<IOSContext> ios_context) {
2727
if (available_layer_index_ >= layers_.size()) {
2828
std::shared_ptr<FlutterPlatformViewLayer> layer;
29+
fml::scoped_nsobject<FlutterOverlayView> overlay_view;
30+
fml::scoped_nsobject<FlutterOverlayView> overlay_view_wrapper;
2931

3032
if (!gr_context) {
31-
fml::scoped_nsobject<FlutterOverlayView> overlay_view([[FlutterOverlayView alloc] init]);
32-
overlay_view.get().autoresizingMask =
33-
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
33+
overlay_view.reset([[FlutterOverlayView alloc] init]);
34+
overlay_view_wrapper.reset([[FlutterOverlayView alloc] init]);
35+
3436
std::unique_ptr<IOSSurface> ios_surface =
3537
[overlay_view.get() createSurface:std::move(ios_context)];
3638
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
3739

3840
layer = std::make_shared<FlutterPlatformViewLayer>(
39-
std::move(overlay_view), std::move(ios_surface), std::move(surface));
41+
std::move(overlay_view), std::move(overlay_view_wrapper), std::move(ios_surface),
42+
std::move(surface));
4043
} else {
4144
CGFloat screenScale = [UIScreen mainScreen].scale;
42-
fml::scoped_nsobject<FlutterOverlayView> overlay_view(
43-
[[FlutterOverlayView alloc] initWithContentsScale:screenScale]);
44-
overlay_view.get().autoresizingMask =
45-
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
45+
overlay_view.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale]);
46+
overlay_view_wrapper.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale]);
47+
4648
std::unique_ptr<IOSSurface> ios_surface =
4749
[overlay_view.get() createSurface:std::move(ios_context)];
4850
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
4951

5052
layer = std::make_shared<FlutterPlatformViewLayer>(
51-
std::move(overlay_view), std::move(ios_surface), std::move(surface));
53+
std::move(overlay_view), std::move(overlay_view_wrapper), std::move(ios_surface),
54+
std::move(surface));
5255
layer->gr_context = gr_context;
5356
}
57+
// The overlay view wrapper masks the overlay view.
58+
// This is required to keep the backing surface size unchanged between frames.
59+
//
60+
// Otherwise, changing the size of the overlay would require a new surface,
61+
// which can be very expensive.
62+
//
63+
// This is the case of an animation in which the overlay size is changing in every frame.
64+
//
65+
// +------------------------+
66+
// | overlay_view |
67+
// | +--------------+ | +--------------+
68+
// | | wrapper | | == mask => | overlay_view |
69+
// | +--------------+ | +--------------+
70+
// +------------------------+
71+
overlay_view_wrapper.get().clipsToBounds = YES;
72+
[overlay_view_wrapper.get() addSubview:overlay_view];
5473
layers_.push_back(layer);
5574
}
5675
auto layer = layers_[available_layer_index_];
@@ -424,7 +443,6 @@
424443
[sub_view removeFromSuperview];
425444
}
426445
views_.clear();
427-
overlays_.clear();
428446
composition_order_.clear();
429447
active_composition_order_.clear();
430448
picture_recorders_.clear();
@@ -500,6 +518,10 @@
500518
// Get the intersection rect between the current rect
501519
// and the platform view rect.
502520
joined_rect.intersect(platform_view_rect);
521+
// Subpixels in the platform may not align with the canvas subpixels.
522+
// To workaround it, round the rect values.
523+
joined_rect.setLTRB(std::round(joined_rect.left()), std::round(joined_rect.top()),
524+
std::round(joined_rect.right()), std::round(joined_rect.bottom()));
503525
// Clip the background canvas, so it doesn't contain any of the pixels drawn
504526
// on the overlay layer.
505527
background_canvas->clipRect(joined_rect, SkClipOp::kDifference);
@@ -545,10 +567,10 @@
545567
platform_view_root.layer.zPosition = zIndex++;
546568
}
547569
for (const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
548-
if ([layer->overlay_view superview] != flutter_view) {
549-
[flutter_view addSubview:layer->overlay_view];
570+
if ([layer->overlay_view_wrapper superview] != flutter_view) {
571+
[flutter_view addSubview:layer->overlay_view_wrapper];
550572
} else {
551-
layer->overlay_view.get().layer.zPosition = zIndex++;
573+
layer->overlay_view_wrapper.get().layer.zPosition = zIndex++;
552574
}
553575
}
554576
active_composition_order_.push_back(platform_view_id);
@@ -563,19 +585,23 @@
563585
int64_t view_id,
564586
int64_t overlay_id) {
565587
auto layer = layer_pool_->GetLayer(gr_context, ios_context);
588+
589+
auto overlay_view_wrapper = layer->overlay_view_wrapper.get();
566590
auto screenScale = [UIScreen mainScreen].scale;
567-
// Set the size of the overlay UIView.
568-
layer->overlay_view.get().frame = CGRectMake(rect.x() / screenScale, //
569-
rect.y() / screenScale, //
570-
rect.width() / screenScale, //
571-
rect.height() / screenScale //
572-
);
573-
// Set a unique view identifier, so the overlay can be identified in unit tests.
574-
layer->overlay_view.get().accessibilityIdentifier =
591+
// Set the size of the overlay view wrapper.
592+
// This wrapper view masks the overlay view.
593+
overlay_view_wrapper.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale,
594+
rect.width() / screenScale, rect.height() / screenScale);
595+
// Set a unique view identifier, so the overlay wrapper can be identified in unit tests.
596+
overlay_view_wrapper.accessibilityIdentifier =
575597
[NSString stringWithFormat:@"platform_view[%lld].overlay[%lld]", view_id, overlay_id];
576598

577-
std::unique_ptr<SurfaceFrame> frame =
578-
layer->surface->AcquireFrame(SkISize::Make(rect.width(), rect.height()));
599+
auto overlay_view = layer->overlay_view.get();
600+
// Set the size of the overlay view.
601+
// This size is equal to the the device screen size.
602+
overlay_view.frame = flutter_view_.get().bounds;
603+
604+
std::unique_ptr<SurfaceFrame> frame = layer->surface->AcquireFrame(frame_size_);
579605
// If frame is null, AcquireFrame already printed out an error message.
580606
if (!frame) {
581607
return layer;
@@ -594,11 +620,10 @@
594620
void FlutterPlatformViewsController::RemoveUnusedLayers() {
595621
auto layers = layer_pool_->GetUnusedLayers();
596622
for (const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
597-
[layer->overlay_view removeFromSuperview];
623+
[layer->overlay_view_wrapper removeFromSuperview];
598624
}
599625

600626
std::unordered_set<int64_t> composition_order_set;
601-
602627
for (int64_t view_id : composition_order_) {
603628
composition_order_set.insert(view_id);
604629
}
@@ -622,10 +647,6 @@
622647
views_.erase(viewId);
623648
touch_interceptors_.erase(viewId);
624649
root_views_.erase(viewId);
625-
if (overlays_.find(viewId) != overlays_.end()) {
626-
[overlays_[viewId]->overlay_view.get() removeFromSuperview];
627-
}
628-
overlays_.erase(viewId);
629650
current_composition_params_.erase(viewId);
630651
clip_count_.erase(viewId);
631652
views_to_recomposite_.erase(viewId);

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,14 @@ class IOSSurface;
6060

6161
struct FlutterPlatformViewLayer {
6262
FlutterPlatformViewLayer(fml::scoped_nsobject<UIView> overlay_view,
63+
fml::scoped_nsobject<UIView> overlay_view_wrapper,
6364
std::unique_ptr<IOSSurface> ios_surface,
6465
std::unique_ptr<Surface> surface);
6566

6667
~FlutterPlatformViewLayer();
6768

6869
fml::scoped_nsobject<UIView> overlay_view;
70+
fml::scoped_nsobject<UIView> overlay_view_wrapper;
6971
std::unique_ptr<IOSSurface> ios_surface;
7072
std::unique_ptr<Surface> surface;
7173

@@ -198,7 +200,6 @@ class FlutterPlatformViewsController {
198200
// Mapping a platform view ID to the count of the clipping operations that were applied to the
199201
// platform view last time it was composited.
200202
std::map<int64_t, int64_t> clip_count_;
201-
std::map<int64_t, std::unique_ptr<FlutterPlatformViewLayer>> overlays_;
202203
SkISize frame_size_;
203204

204205
// This is the number of frames the task runners will stay

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111

1212
namespace flutter {
1313

14-
FlutterPlatformViewLayer::FlutterPlatformViewLayer(fml::scoped_nsobject<UIView> overlay_view,
15-
std::unique_ptr<IOSSurface> ios_surface,
16-
std::unique_ptr<Surface> surface)
14+
FlutterPlatformViewLayer::FlutterPlatformViewLayer(
15+
fml::scoped_nsobject<UIView> overlay_view,
16+
fml::scoped_nsobject<UIView> overlay_view_wrapper,
17+
std::unique_ptr<IOSSurface> ios_surface,
18+
std::unique_ptr<Surface> surface)
1719
: overlay_view(std::move(overlay_view)),
20+
overlay_view_wrapper(std::move(overlay_view_wrapper)),
1821
ios_surface(std::move(ios_surface)),
1922
surface(std::move(surface)){};
2023

-522 Bytes
Loading

0 commit comments

Comments
 (0)