7 #include <Metal/Metal.h>
9 #include "flutter/fml/platform/darwin/scoped_nsobject.h"
18 if (
self.isFirstResponder) {
21 for (UIView* subview in
self.subviews) {
22 if (subview.flt_hasFirstResponderInViewHierarchySubtree) {
39 const SkRect& platformview_boundingrect,
40 const SkMatrix& transform_matrix) {
41 SkRect transformed_rect = transform_matrix.mapRect(clip_rect);
42 return transformed_rect.contains(platformview_boundingrect);
54 const SkRect& platformview_boundingrect,
55 const SkMatrix& transform_matrix) {
56 SkVector upper_left = clip_rrect.radii(SkRRect::Corner::kUpperLeft_Corner);
57 SkVector upper_right = clip_rrect.radii(SkRRect::Corner::kUpperRight_Corner);
58 SkVector lower_right = clip_rrect.radii(SkRRect::Corner::kLowerRight_Corner);
59 SkVector lower_left = clip_rrect.radii(SkRRect::Corner::kLowerLeft_Corner);
60 SkScalar transformed_upper_left_x = transform_matrix.mapRadius(upper_left.x());
61 SkScalar transformed_upper_left_y = transform_matrix.mapRadius(upper_left.y());
62 SkScalar transformed_upper_right_x = transform_matrix.mapRadius(upper_right.x());
63 SkScalar transformed_upper_right_y = transform_matrix.mapRadius(upper_right.y());
64 SkScalar transformed_lower_right_x = transform_matrix.mapRadius(lower_right.x());
65 SkScalar transformed_lower_right_y = transform_matrix.mapRadius(lower_right.y());
66 SkScalar transformed_lower_left_x = transform_matrix.mapRadius(lower_left.x());
67 SkScalar transformed_lower_left_y = transform_matrix.mapRadius(lower_left.y());
68 SkRect transformed_clip_rect = transform_matrix.mapRect(clip_rrect.rect());
69 SkRRect transformed_rrect;
70 SkVector corners[] = {{transformed_upper_left_x, transformed_upper_left_y},
71 {transformed_upper_right_x, transformed_upper_right_y},
72 {transformed_lower_right_x, transformed_lower_right_y},
73 {transformed_lower_left_x, transformed_lower_left_y}};
74 transformed_rrect.setRectRadii(transformed_clip_rect, corners);
75 return transformed_rrect.contains(platformview_boundingrect);
82 std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewLayerPool::GetLayer(
83 GrDirectContext* gr_context,
84 const std::shared_ptr<IOSContext>& ios_context,
85 MTLPixelFormat pixel_format) {
86 if (available_layer_index_ >= layers_.size()) {
87 std::shared_ptr<FlutterPlatformViewLayer> layer;
88 fml::scoped_nsobject<UIView> overlay_view;
89 fml::scoped_nsobject<UIView> overlay_view_wrapper;
91 bool impeller_enabled = !!ios_context->GetImpellerContext();
92 if (!gr_context && !impeller_enabled) {
96 auto ca_layer = fml::scoped_nsobject<CALayer>{[overlay_view.get() layer]};
97 std::unique_ptr<IOSSurface> ios_surface = IOSSurface::Create(ios_context, ca_layer);
98 std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
100 layer = std::make_shared<FlutterPlatformViewLayer>(
101 std::move(overlay_view), std::move(overlay_view_wrapper), std::move(ios_surface),
104 CGFloat screenScale = [UIScreen mainScreen].scale;
106 pixelFormat:pixel_format]);
107 overlay_view_wrapper.reset([[
FlutterOverlayView alloc] initWithContentsScale:screenScale
108 pixelFormat:pixel_format]);
110 auto ca_layer = fml::scoped_nsobject<CALayer>{[overlay_view.get() layer]};
111 std::unique_ptr<IOSSurface> ios_surface = IOSSurface::Create(ios_context, ca_layer);
112 std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
114 layer = std::make_shared<FlutterPlatformViewLayer>(
115 std::move(overlay_view), std::move(overlay_view_wrapper), std::move(ios_surface),
117 layer->gr_context = gr_context;
133 layer->overlay_view_wrapper.get().clipsToBounds = YES;
134 [layer->overlay_view_wrapper.get() addSubview:layer->overlay_view];
135 layers_.push_back(layer);
137 std::shared_ptr<FlutterPlatformViewLayer> layer = layers_[available_layer_index_];
138 if (gr_context != layer->gr_context) {
139 layer->gr_context = gr_context;
142 IOSSurface* ios_surface = layer->ios_surface.get();
143 std::unique_ptr<Surface> surface = ios_surface->
CreateGPUSurface(gr_context);
144 layer->surface = std::move(surface);
146 available_layer_index_++;
150 void FlutterPlatformViewLayerPool::RecycleLayers() {
151 available_layer_index_ = 0;
154 std::vector<std::shared_ptr<FlutterPlatformViewLayer>>
155 FlutterPlatformViewLayerPool::GetUnusedLayers() {
156 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> results;
157 for (
size_t i = available_layer_index_; i < layers_.size(); i++) {
158 results.push_back(layers_[i]);
163 void FlutterPlatformViewsController::SetFlutterView(UIView* flutter_view) {
164 flutter_view_.reset(flutter_view);
167 void FlutterPlatformViewsController::SetFlutterViewController(
168 UIViewController<FlutterViewResponder>* flutter_view_controller) {
169 flutter_view_controller_.reset(flutter_view_controller);
172 UIViewController<FlutterViewResponder>* FlutterPlatformViewsController::getFlutterViewController() {
173 return flutter_view_controller_.get();
177 if ([[call method] isEqualToString:
@"create"]) {
178 OnCreate(call, result);
179 }
else if ([[call method] isEqualToString:
@"dispose"]) {
180 OnDispose(call, result);
181 }
else if ([[call method] isEqualToString:
@"acceptGesture"]) {
182 OnAcceptGesture(call, result);
183 }
else if ([[call method] isEqualToString:
@"rejectGesture"]) {
184 OnRejectGesture(call, result);
191 NSDictionary<NSString*, id>* args = [call
arguments];
193 int64_t viewId = [args[@"id"] longLongValue];
194 NSString* viewTypeString = args[@"viewType"];
195 std::string viewType(viewTypeString.UTF8String);
197 if (views_.count(viewId) != 0) {
199 message:
@"trying to create an already created view"
200 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
203 NSObject<FlutterPlatformViewFactory>* factory = factories_[viewType].get();
204 if (factory == nil) {
206 errorWithCode:
@"unregistered_view_type"
207 message:[NSString stringWithFormat:
@"A UIKitView widget is trying to create a "
208 @"PlatformView with an unregistered type: < %@ >",
210 details:
@"If you are the author of the PlatformView, make sure `registerViewFactory` "
213 @"https://docs.flutter.dev/development/platform-integration/"
214 @"platform-views#on-the-platform-side-1 for more details.\n"
215 @"If you are not the author of the PlatformView, make sure to call "
216 @"`GeneratedPluginRegistrant.register`."]);
221 if ([factory respondsToSelector:
@selector(createArgsCodec)]) {
222 NSObject<FlutterMessageCodec>* codec = [factory createArgsCodec];
223 if (codec != nil && args[
@"params"] != nil) {
225 params = [codec decode:paramsData.data];
229 NSObject<FlutterPlatformView>* embedded_view = [factory createWithFrame:CGRectZero
230 viewIdentifier:viewId
235 [NSString stringWithFormat:@"platform_view[%lld]", viewId];
236 views_[viewId] = fml::scoped_nsobject<NSObject<FlutterPlatformView>>(embedded_view);
239 initWithEmbeddedView:platform_view
240 platformViewsController:GetWeakPtr()
241 gestureRecognizersBlockingPolicy:gesture_recognizers_blocking_policies_[viewType]];
243 touch_interceptors_[viewId] =
244 fml::scoped_nsobject<FlutterTouchInterceptingView>(touch_interceptor);
247 [clipping_view addSubview:touch_interceptor];
248 root_views_[viewId] = fml::scoped_nsobject<UIView>(clipping_view);
255 int64_t viewId = [arg longLongValue];
257 if (views_.count(viewId) == 0) {
259 message:
@"trying to dispose an unknown"
260 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
264 views_to_dispose_.insert(viewId);
270 NSDictionary<NSString*, id>* args = [call
arguments];
271 int64_t viewId = [args[@"id"] longLongValue];
273 if (views_.count(viewId) == 0) {
275 message:
@"trying to set gesture state for an unknown view"
276 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
288 NSDictionary<NSString*, id>* args = [call
arguments];
289 int64_t viewId = [args[@"id"] longLongValue];
291 if (views_.count(viewId) == 0) {
293 message:
@"trying to set gesture state for an unknown view"
294 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
304 void FlutterPlatformViewsController::RegisterViewFactory(
305 NSObject<FlutterPlatformViewFactory>* factory,
308 std::string idString([factoryId UTF8String]);
309 FML_CHECK(factories_.count(idString) == 0);
310 factories_[idString] = fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>(factory);
311 gesture_recognizers_blocking_policies_[idString] = gestureRecognizerBlockingPolicy;
314 void FlutterPlatformViewsController::BeginFrame(SkISize frame_size) {
316 frame_size_ = frame_size;
319 void FlutterPlatformViewsController::CancelFrame() {
326 bool FlutterPlatformViewsController::HasPlatformViewThisOrNextFrame() {
327 return !composition_order_.empty() || !active_composition_order_.empty();
330 const int FlutterPlatformViewsController::kDefaultMergedLeaseDuration;
332 PostPrerollResult FlutterPlatformViewsController::PostPrerollAction(
333 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {
336 if (!HasPlatformViewThisOrNextFrame()) {
337 return PostPrerollResult::kSuccess;
339 if (!raster_thread_merger->IsMerged()) {
349 return PostPrerollResult::kSkipAndRetryFrame;
355 BeginCATransaction();
356 raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration);
357 return PostPrerollResult::kSuccess;
360 void FlutterPlatformViewsController::EndFrame(
361 bool should_resubmit_frame,
362 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {
363 if (should_resubmit_frame) {
364 raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
368 void FlutterPlatformViewsController::PushFilterToVisitedPlatformViews(
369 const std::shared_ptr<const DlImageFilter>& filter,
370 const SkRect& filter_rect) {
371 for (int64_t
id : visited_platform_views_) {
372 EmbeddedViewParams params = current_composition_params_[id];
373 params.PushImageFilter(filter, filter_rect);
374 current_composition_params_[id] = params;
378 void FlutterPlatformViewsController::PrerollCompositeEmbeddedView(
380 std::unique_ptr<EmbeddedViewParams> params) {
383 FML_DCHECK(!catransaction_added_);
385 SkRect view_bounds = SkRect::Make(frame_size_);
386 std::unique_ptr<EmbedderViewSlice> view;
387 view = std::make_unique<DisplayListEmbedderViewSlice>(view_bounds);
388 slices_.insert_or_assign(view_id, std::move(view));
390 composition_order_.push_back(view_id);
392 if (current_composition_params_.count(view_id) == 1 &&
393 current_composition_params_[view_id] == *params.get()) {
397 current_composition_params_[view_id] = EmbeddedViewParams(*params.get());
398 views_to_recomposite_.insert(view_id);
401 size_t FlutterPlatformViewsController::EmbeddedViewCount() {
402 return composition_order_.size();
405 UIView* FlutterPlatformViewsController::GetPlatformViewByID(int64_t view_id) {
411 if (views_.empty()) {
414 return touch_interceptors_[view_id].get();
417 long FlutterPlatformViewsController::FindFirstResponderPlatformViewId() {
418 for (
auto const& [
id, root_view] : root_views_) {
419 if (((UIView*)root_view.get()).flt_hasFirstResponderInViewHierarchySubtree) {
426 int FlutterPlatformViewsController::CountClips(
const MutatorsStack& mutators_stack) {
427 std::vector<std::shared_ptr<Mutator>>::const_reverse_iterator iter = mutators_stack.Bottom();
429 while (iter != mutators_stack.Top()) {
430 if ((*iter)->IsClipType()) {
438 void FlutterPlatformViewsController::ClipViewSetMaskView(UIView* clipView) {
439 if (clipView.maskView) {
442 UIView* flutterView = flutter_view_.get();
444 CGRectMake(-clipView.frame.origin.x, -clipView.frame.origin.y,
445 CGRectGetWidth(flutterView.bounds), CGRectGetHeight(flutterView.bounds));
446 clipView.maskView = [mask_view_pool_.get() getMaskViewWithFrame:frame];
451 void FlutterPlatformViewsController::ApplyMutators(
const MutatorsStack& mutators_stack,
452 UIView* embedded_view,
453 const SkRect& bounding_rect) {
454 if (flutter_view_ ==
nullptr) {
457 FML_DCHECK(CATransform3DEqualToTransform(embedded_view.layer.transform, CATransform3DIdentity));
461 SkMatrix transformMatrix;
462 NSMutableArray* blurFilters = [[NSMutableArray alloc] init];
463 FML_DCHECK(!clipView.maskView ||
465 if (clipView.maskView) {
466 [mask_view_pool_.get() insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)];
467 clipView.maskView = nil;
469 CGFloat screenScale = [UIScreen mainScreen].scale;
470 auto iter = mutators_stack.Begin();
471 while (iter != mutators_stack.End()) {
472 switch ((*iter)->GetType()) {
474 transformMatrix.preConcat((*iter)->GetMatrix());
482 ClipViewSetMaskView(clipView);
484 matrix:transformMatrix];
492 ClipViewSetMaskView(clipView);
494 matrix:transformMatrix];
501 ClipViewSetMaskView(clipView);
503 matrix:transformMatrix];
507 embedded_view.alpha = (*iter)->GetAlphaFloat() * embedded_view.alpha;
509 case kBackdropFilter: {
517 filterRect = CGRectApplyAffineTransform(
518 filterRect, CGAffineTransformMakeScale(1 / screenScale, 1 / screenScale));
522 if (CGRectIsNull(CGRectIntersection(filterRect, clipView.frame))) {
525 CGRect intersection = CGRectIntersection(filterRect, clipView.frame);
526 CGRect frameInClipView = [flutter_view_.get() convertRect:intersection toView:clipView];
531 CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x();
532 UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc]
533 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
535 blurRadius:blurRadius
536 visualEffectView:visualEffectView];
540 [blurFilters addObject:filter];
557 transformMatrix.postScale(1 / screenScale, 1 / screenScale);
566 transformMatrix.postTranslate(-clipView.frame.origin.x, -clipView.frame.origin.y);
579 void FlutterPlatformViewsController::CompositeWithParams(int64_t view_id,
580 const EmbeddedViewParams& params) {
581 CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height());
583 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
584 FML_DCHECK(CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero));
585 if (non_zero_origin_views_.find(view_id) == non_zero_origin_views_.end() &&
586 !CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero)) {
587 non_zero_origin_views_.insert(view_id);
589 @"A Embedded PlatformView's origin is not CGPointZero.\n"
591 " View info: \n %@ \n"
592 "A non-zero origin might cause undefined behavior.\n"
593 "See https://github.com/flutter/flutter/issues/109700 for more details.\n"
594 "If you are the author of the PlatformView, please update the implementation of the "
595 "PlatformView to have a (0, 0) origin.\n"
596 "If you have a valid case of using a non-zero origin, "
597 "please leave a comment at https://github.com/flutter/flutter/issues/109700 with details.",
598 @(view_id), [touchInterceptor embeddedView]);
601 touchInterceptor.layer.transform = CATransform3DIdentity;
602 touchInterceptor.frame = frame;
603 touchInterceptor.alpha = 1;
605 const MutatorsStack& mutatorStack = params.mutatorsStack();
606 UIView* clippingView = root_views_[view_id].get();
611 const SkRect& rect = params.finalBoundingRect();
612 CGFloat screenScale = [UIScreen mainScreen].scale;
613 clippingView.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale,
614 rect.width() / screenScale, rect.height() / screenScale);
615 ApplyMutators(mutatorStack, touchInterceptor, rect);
618 DlCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(int64_t view_id) {
620 FML_DCHECK([[NSThread currentThread] isMainThread]);
622 if (views_to_recomposite_.count(view_id) == 0) {
623 return slices_[view_id]->canvas();
625 CompositeWithParams(view_id, current_composition_params_[view_id]);
626 views_to_recomposite_.erase(view_id);
627 return slices_[view_id]->canvas();
630 void FlutterPlatformViewsController::Reset() {
631 for (int64_t view_id : active_composition_order_) {
632 UIView* sub_view = root_views_[view_id].get();
633 [sub_view removeFromSuperview];
636 touch_interceptors_.clear();
638 composition_order_.clear();
639 active_composition_order_.clear();
641 current_composition_params_.clear();
643 views_to_recomposite_.clear();
644 layer_pool_->RecycleLayers();
645 visited_platform_views_.clear();
648 SkRect FlutterPlatformViewsController::GetPlatformViewRect(int64_t view_id) {
650 UIScreen* screen = [UIScreen mainScreen];
651 CGRect platform_view_cgrect = [platform_view convertRect:platform_view.bounds
652 toView:flutter_view_];
653 return SkRect::MakeXYWH(platform_view_cgrect.origin.x * screen.scale,
654 platform_view_cgrect.origin.y * screen.scale,
655 platform_view_cgrect.size.width * screen.scale,
656 platform_view_cgrect.size.height * screen.scale
660 bool FlutterPlatformViewsController::SubmitFrame(GrDirectContext* gr_context,
661 const std::shared_ptr<IOSContext>& ios_context,
662 std::unique_ptr<SurfaceFrame> frame) {
663 TRACE_EVENT0(
"flutter",
"FlutterPlatformViewsController::SubmitFrame");
666 FML_DCHECK([[NSThread currentThread] isMainThread]);
667 if (flutter_view_ ==
nullptr) {
668 return frame->Submit();
673 DlCanvas* background_canvas = frame->Canvas();
676 background_canvas->Flush();
680 DlAutoCanvasRestore save(background_canvas,
true);
683 LayersMap platform_view_layers;
685 auto did_submit =
true;
686 auto num_platform_views = composition_order_.size();
690 for (
size_t i = 0; i < num_platform_views; i++) {
691 int64_t platform_view_id = composition_order_[i];
692 EmbedderViewSlice* slice = slices_[platform_view_id].get();
693 slice->end_recording();
697 for (
size_t j = i + 1; j > 0; j--) {
698 int64_t current_platform_view_id = composition_order_[j - 1];
699 SkRect platform_view_rect = GetPlatformViewRect(current_platform_view_id);
700 std::vector<SkIRect> intersection_rects = slice->region(platform_view_rect).getRects();
701 const SkIRect rounded_in_platform_view_rect = platform_view_rect.roundIn();
712 for (
auto it = intersection_rects.begin(); it != intersection_rects.end(); ) {
715 if (!SkIRect::Intersects(*it, rounded_in_platform_view_rect)) {
716 it = intersection_rects.erase(it);
722 auto allocation_size = intersection_rects.size();
726 auto overlay_id = platform_view_layers[current_platform_view_id].size();
733 if (allocation_size > kMaxLayerAllocations) {
734 SkIRect joined_rect = SkIRect::MakeEmpty();
735 for (
const SkIRect& rect : intersection_rects) {
736 joined_rect.join(rect);
740 intersection_rects.clear();
741 intersection_rects.push_back(joined_rect);
743 for (SkIRect& joined_rect : intersection_rects) {
746 joined_rect.intersect(platform_view_rect.roundOut());
749 background_canvas->ClipRect(SkRect::Make(joined_rect), DlCanvas::ClipOp::kDifference);
751 std::shared_ptr<FlutterPlatformViewLayer> layer =
756 current_platform_view_id,
760 did_submit &= layer->did_submit_last_frame;
761 platform_view_layers[current_platform_view_id].push_back(layer);
765 slice->render_into(background_canvas);
773 RemoveUnusedLayers();
775 BringLayersIntoView(platform_view_layers);
777 layer_pool_->RecycleLayers();
779 did_submit &= frame->Submit();
784 CommitCATransactionIfNeeded();
788 void FlutterPlatformViewsController::BringLayersIntoView(LayersMap layer_map) {
789 FML_DCHECK(flutter_view_);
790 UIView* flutter_view = flutter_view_.get();
792 active_composition_order_.clear();
793 NSMutableArray* desired_platform_subviews = [NSMutableArray array];
794 for (
size_t i = 0; i < composition_order_.size(); i++) {
795 int64_t platform_view_id = composition_order_[i];
796 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_map[platform_view_id];
797 UIView* platform_view_root = root_views_[platform_view_id].get();
798 [desired_platform_subviews addObject:platform_view_root];
799 for (
const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
800 [desired_platform_subviews addObject:layer->overlay_view_wrapper];
802 active_composition_order_.push_back(platform_view_id);
805 NSSet* desired_platform_subviews_set = [NSSet setWithArray:desired_platform_subviews];
806 NSArray* existing_platform_subviews = [flutter_view.subviews
807 filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object,
808 NSDictionary* bindings) {
809 return [desired_platform_subviews_set containsObject:object];
815 if (![desired_platform_subviews isEqualToArray:existing_platform_subviews]) {
816 for (UIView* subview in desired_platform_subviews) {
818 [flutter_view addSubview:subview];
823 std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLayer(
824 GrDirectContext* gr_context,
825 const std::shared_ptr<IOSContext>& ios_context,
826 EmbedderViewSlice* slice,
830 MTLPixelFormat pixel_format) {
831 FML_DCHECK(flutter_view_);
832 std::shared_ptr<FlutterPlatformViewLayer> layer =
833 layer_pool_->GetLayer(gr_context, ios_context, pixel_format);
835 UIView* overlay_view_wrapper = layer->overlay_view_wrapper.get();
836 auto screenScale = [UIScreen mainScreen].scale;
839 overlay_view_wrapper.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale,
840 rect.width() / screenScale, rect.height() / screenScale);
842 overlay_view_wrapper.accessibilityIdentifier =
843 [NSString stringWithFormat:@"platform_view[%lld].overlay[%lld]", view_id, overlay_id];
845 UIView* overlay_view = layer->overlay_view.get();
848 overlay_view.frame = [flutter_view_.get() convertRect:flutter_view_.get().bounds
849 toView:overlay_view_wrapper];
851 overlay_view.accessibilityIdentifier =
852 [NSString stringWithFormat:@"platform_view[%lld].overlay_view[%lld]", view_id, overlay_id];
854 std::unique_ptr<SurfaceFrame> frame = layer->surface->AcquireFrame(frame_size_);
859 DlCanvas* overlay_canvas = frame->Canvas();
860 int restore_count = overlay_canvas->GetSaveCount();
861 overlay_canvas->Save();
862 overlay_canvas->ClipRect(SkRect::Make(rect));
863 overlay_canvas->Clear(DlColor::kTransparent());
864 slice->render_into(overlay_canvas);
865 overlay_canvas->RestoreToCount(restore_count);
869 frame->set_submit_info({.frame_boundary =
false});
871 layer->did_submit_last_frame = frame->Submit();
875 void FlutterPlatformViewsController::RemoveUnusedLayers() {
876 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_pool_->GetUnusedLayers();
877 for (
const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
878 [layer->overlay_view_wrapper removeFromSuperview];
881 std::unordered_set<int64_t> composition_order_set;
882 for (int64_t view_id : composition_order_) {
883 composition_order_set.insert(view_id);
886 for (int64_t view_id : active_composition_order_) {
887 if (composition_order_set.find(view_id) == composition_order_set.end()) {
888 UIView* platform_view_root = root_views_[view_id].get();
889 [platform_view_root removeFromSuperview];
894 void FlutterPlatformViewsController::DisposeViews() {
895 if (views_to_dispose_.empty()) {
899 FML_DCHECK([[NSThread currentThread] isMainThread]);
901 std::unordered_set<int64_t> views_to_composite(composition_order_.begin(),
902 composition_order_.end());
903 std::unordered_set<int64_t> views_to_delay_dispose;
904 for (int64_t viewId : views_to_dispose_) {
905 if (views_to_composite.count(viewId)) {
906 views_to_delay_dispose.insert(viewId);
909 UIView* root_view = root_views_[viewId].get();
910 [root_view removeFromSuperview];
911 views_.erase(viewId);
912 touch_interceptors_.erase(viewId);
913 root_views_.erase(viewId);
914 current_composition_params_.erase(viewId);
915 clip_count_.erase(viewId);
916 views_to_recomposite_.erase(viewId);
919 views_to_dispose_ = std::move(views_to_delay_dispose);
922 void FlutterPlatformViewsController::BeginCATransaction() {
923 FML_DCHECK([[NSThread currentThread] isMainThread]);
924 FML_DCHECK(!catransaction_added_);
925 [CATransaction begin];
926 catransaction_added_ =
true;
929 void FlutterPlatformViewsController::CommitCATransactionIfNeeded() {
930 if (catransaction_added_) {
931 FML_DCHECK([[NSThread currentThread] isMainThread]);
932 [CATransaction commit];
933 catransaction_added_ =
false;
937 void FlutterPlatformViewsController::ResetFrameState() {
939 composition_order_.clear();
940 visited_platform_views_.clear();
963 - (instancetype)initWithTarget:(
id)target
965 forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer;
979 - (instancetype)initWithTarget:(
id)target
980 platformViewsController:
981 (fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController;
991 - (instancetype)initWithEmbeddedView:(UIView*)embeddedView
992 platformViewsController:
993 (fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController
994 gestureRecognizersBlockingPolicy:
996 self = [
super initWithFrame:embeddedView.frame];
998 self.multipleTouchEnabled = YES;
1001 (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
1003 [
self addSubview:embeddedView];
1007 platformViewsController:platformViewsController];
1011 forwardingRecognizer:forwardingRecognizer];
1012 _blockingPolicy = blockingPolicy;
1014 [
self addGestureRecognizer:_delayingRecognizer];
1015 [
self addGestureRecognizer:forwardingRecognizer];
1021 self.delayingRecognizer.state = UIGestureRecognizerStateFailed;
1025 switch (_blockingPolicy) {
1028 self.delayingRecognizer.state = UIGestureRecognizerStateEnded;
1031 if (
self.delayingRecognizer.touchedEndedWithoutBlocking) {
1035 self.delayingRecognizer.state = UIGestureRecognizerStateEnded;
1040 self.delayingRecognizer.shouldEndInNextTouchesEnded = YES;
1051 - (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1054 - (void)touchesMoved:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1057 - (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1060 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
1064 return self.flutterAccessibilityContainer;
1071 - (instancetype)initWithTarget:(
id)target
1073 forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer {
1074 self = [
super initWithTarget:target action:action];
1076 self.delaysTouchesBegan = YES;
1077 self.delaysTouchesEnded = YES;
1078 self.delegate =
self;
1079 _shouldEndInNextTouchesEnded = NO;
1080 _touchedEndedWithoutBlocking = NO;
1086 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1087 shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
1090 return otherGestureRecognizer != _forwardingRecognizer && otherGestureRecognizer !=
self;
1093 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1094 shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
1095 return otherGestureRecognizer ==
self;
1098 - (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1099 self.touchedEndedWithoutBlocking = NO;
1100 [
super touchesBegan:touches withEvent:event];
1103 - (void)touchesEnded:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1105 self.state = UIGestureRecognizerStateEnded;
1106 self.shouldEndInNextTouchesEnded = NO;
1108 self.touchedEndedWithoutBlocking = YES;
1110 [
super touchesEnded:touches withEvent:event];
1113 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
1114 self.state = UIGestureRecognizerStateFailed;
1136 - (instancetype)initWithTarget:(
id)target
1137 platformViewsController:
1138 (fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController {
1139 self = [
super initWithTarget:target action:nil];
1141 self.delegate =
self;
1142 FML_DCHECK(platformViewsController.get() !=
nullptr);
1149 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
1157 [_flutterViewController.get() touchesBegan:touches withEvent:event];
1161 - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
1162 [_flutterViewController.get() touchesMoved:touches withEvent:event];
1165 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
1166 [_flutterViewController.get() touchesEnded:touches withEvent:event];
1173 self.state = UIGestureRecognizerStateFailed;
1178 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
1184 [_flutterViewController.get() forceTouchesCancelled:touches];
1187 self.state = UIGestureRecognizerStateFailed;
1192 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1193 shouldRecognizeSimultaneouslyWithGestureRecognizer:
1194 (UIGestureRecognizer*)otherGestureRecognizer {