5 #import <UIKit/UIGestureRecognizerSubclass.h>
12 #include "flutter/common/graphics/persistent_cache.h"
13 #include "flutter/fml/platform/darwin/scoped_nsobject.h"
22 if (
self.isFirstResponder) {
25 for (UIView* subview in
self.subviews) {
26 if (subview.flt_hasFirstResponderInViewHierarchySubtree) {
43 const SkRect& platformview_boundingrect,
44 const SkMatrix& transform_matrix) {
45 SkRect transformed_rect = transform_matrix.mapRect(clip_rect);
46 return transformed_rect.contains(platformview_boundingrect);
58 const SkRect& platformview_boundingrect,
59 const SkMatrix& transform_matrix) {
60 SkVector upper_left = clip_rrect.radii(SkRRect::Corner::kUpperLeft_Corner);
61 SkVector upper_right = clip_rrect.radii(SkRRect::Corner::kUpperRight_Corner);
62 SkVector lower_right = clip_rrect.radii(SkRRect::Corner::kLowerRight_Corner);
63 SkVector lower_left = clip_rrect.radii(SkRRect::Corner::kLowerLeft_Corner);
64 SkScalar transformed_upper_left_x = transform_matrix.mapRadius(upper_left.x());
65 SkScalar transformed_upper_left_y = transform_matrix.mapRadius(upper_left.y());
66 SkScalar transformed_upper_right_x = transform_matrix.mapRadius(upper_right.x());
67 SkScalar transformed_upper_right_y = transform_matrix.mapRadius(upper_right.y());
68 SkScalar transformed_lower_right_x = transform_matrix.mapRadius(lower_right.x());
69 SkScalar transformed_lower_right_y = transform_matrix.mapRadius(lower_right.y());
70 SkScalar transformed_lower_left_x = transform_matrix.mapRadius(lower_left.x());
71 SkScalar transformed_lower_left_y = transform_matrix.mapRadius(lower_left.y());
72 SkRect transformed_clip_rect = transform_matrix.mapRect(clip_rrect.rect());
73 SkRRect transformed_rrect;
74 SkVector corners[] = {{transformed_upper_left_x, transformed_upper_left_y},
75 {transformed_upper_right_x, transformed_upper_right_y},
76 {transformed_lower_right_x, transformed_lower_right_y},
77 {transformed_lower_left_x, transformed_lower_left_y}};
78 transformed_rrect.setRectRadii(transformed_clip_rect, corners);
79 return transformed_rrect.contains(platformview_boundingrect);
86 std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewLayerPool::GetLayer(
87 GrDirectContext* gr_context,
88 const std::shared_ptr<IOSContext>& ios_context) {
89 if (available_layer_index_ >= layers_.size()) {
90 std::shared_ptr<FlutterPlatformViewLayer> layer;
91 fml::scoped_nsobject<FlutterOverlayView> overlay_view;
92 fml::scoped_nsobject<FlutterOverlayView> overlay_view_wrapper;
98 auto ca_layer = fml::scoped_nsobject<CALayer>{[[overlay_view.get() layer] retain]};
99 std::unique_ptr<IOSSurface> ios_surface = IOSSurface::Create(ios_context, ca_layer);
100 std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
102 layer = std::make_shared<FlutterPlatformViewLayer>(
103 std::move(overlay_view), std::move(overlay_view_wrapper), std::move(ios_surface),
106 CGFloat screenScale = [UIScreen mainScreen].scale;
108 overlay_view_wrapper.reset([[
FlutterOverlayView alloc] initWithContentsScale:screenScale]);
110 auto ca_layer = fml::scoped_nsobject<CALayer>{[[overlay_view.get() layer] retain]};
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 retain]);
167 void FlutterPlatformViewsController::SetFlutterViewController(
168 UIViewController* flutter_view_controller) {
169 flutter_view_controller_.reset([flutter_view_controller retain]);
172 UIViewController* 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 retain]);
239 initWithEmbeddedView:platform_view
240 platformViewsController:GetWeakPtr()
241 gestureRecognizersBlockingPolicy:gesture_recognizers_blocking_policies[viewType]]
244 touch_interceptors_[viewId] =
245 fml::scoped_nsobject<FlutterTouchInterceptingView>([touch_interceptor retain]);
249 [clipping_view addSubview:touch_interceptor];
250 root_views_[viewId] = fml::scoped_nsobject<UIView>([clipping_view retain]);
257 int64_t viewId = [arg longLongValue];
259 if (views_.count(viewId) == 0) {
261 message:
@"trying to dispose an unknown"
262 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
266 views_to_dispose_.insert(viewId);
272 NSDictionary<NSString*, id>* args = [call
arguments];
273 int64_t viewId = [args[@"id"] longLongValue];
275 if (views_.count(viewId) == 0) {
277 message:
@"trying to set gesture state for an unknown view"
278 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
290 NSDictionary<NSString*, id>* args = [call
arguments];
291 int64_t viewId = [args[@"id"] longLongValue];
293 if (views_.count(viewId) == 0) {
295 message:
@"trying to set gesture state for an unknown view"
296 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
306 void FlutterPlatformViewsController::RegisterViewFactory(
307 NSObject<FlutterPlatformViewFactory>* factory,
310 std::string idString([factoryId UTF8String]);
311 FML_CHECK(factories_.count(idString) == 0);
312 factories_[idString] =
313 fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>([factory retain]);
314 gesture_recognizers_blocking_policies[idString] = gestureRecognizerBlockingPolicy;
317 void FlutterPlatformViewsController::BeginFrame(SkISize frame_size) {
319 frame_size_ = frame_size;
322 void FlutterPlatformViewsController::CancelFrame() {
329 bool FlutterPlatformViewsController::HasPlatformViewThisOrNextFrame() {
330 return !composition_order_.empty() || !active_composition_order_.empty();
333 const int FlutterPlatformViewsController::kDefaultMergedLeaseDuration;
335 PostPrerollResult FlutterPlatformViewsController::PostPrerollAction(
336 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {
339 if (!HasPlatformViewThisOrNextFrame()) {
340 return PostPrerollResult::kSuccess;
342 if (!raster_thread_merger->IsMerged()) {
352 return PostPrerollResult::kSkipAndRetryFrame;
358 BeginCATransaction();
359 raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration);
360 return PostPrerollResult::kSuccess;
363 void FlutterPlatformViewsController::EndFrame(
364 bool should_resubmit_frame,
365 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {
366 if (should_resubmit_frame) {
367 raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
371 void FlutterPlatformViewsController::PushFilterToVisitedPlatformViews(
372 const std::shared_ptr<const DlImageFilter>& filter,
373 const SkRect& filter_rect) {
374 for (int64_t
id : visited_platform_views_) {
375 EmbeddedViewParams params = current_composition_params_[id];
376 params.PushImageFilter(filter, filter_rect);
377 current_composition_params_[id] = params;
381 void FlutterPlatformViewsController::PrerollCompositeEmbeddedView(
383 std::unique_ptr<EmbeddedViewParams> params) {
386 FML_DCHECK(!catransaction_added_);
388 SkRect view_bounds = SkRect::Make(frame_size_);
389 std::unique_ptr<EmbedderViewSlice> view;
390 view = std::make_unique<DisplayListEmbedderViewSlice>(view_bounds);
391 slices_.insert_or_assign(view_id, std::move(view));
393 composition_order_.push_back(view_id);
395 if (current_composition_params_.count(view_id) == 1 &&
396 current_composition_params_[view_id] == *params.get()) {
400 current_composition_params_[view_id] = EmbeddedViewParams(*params.get());
401 views_to_recomposite_.insert(view_id);
404 size_t FlutterPlatformViewsController::EmbeddedViewCount() {
405 return composition_order_.size();
408 UIView* FlutterPlatformViewsController::GetPlatformViewByID(int64_t view_id) {
414 if (views_.empty()) {
417 return touch_interceptors_[view_id].get();
420 long FlutterPlatformViewsController::FindFirstResponderPlatformViewId() {
421 for (
auto const& [
id, root_view] : root_views_) {
422 if ((UIView*)(root_view.get()).flt_hasFirstResponderInViewHierarchySubtree) {
429 int FlutterPlatformViewsController::CountClips(
const MutatorsStack& mutators_stack) {
430 std::vector<std::shared_ptr<Mutator>>::const_reverse_iterator iter = mutators_stack.Bottom();
432 while (iter != mutators_stack.Top()) {
433 if ((*iter)->IsClipType()) {
441 void FlutterPlatformViewsController::ClipViewSetMaskView(UIView* clipView) {
442 if (clipView.maskView) {
445 UIView* flutterView = flutter_view_.get();
447 CGRectMake(-clipView.frame.origin.x, -clipView.frame.origin.y,
448 CGRectGetWidth(flutterView.bounds), CGRectGetHeight(flutterView.bounds));
449 clipView.maskView = [mask_view_pool_.get() getMaskViewWithFrame:frame];
454 void FlutterPlatformViewsController::ApplyMutators(
const MutatorsStack& mutators_stack,
455 UIView* embedded_view,
456 const SkRect& bounding_rect) {
457 if (flutter_view_ ==
nullptr) {
460 FML_DCHECK(CATransform3DEqualToTransform(embedded_view.layer.transform, CATransform3DIdentity));
464 SkMatrix transformMatrix;
465 NSMutableArray* blurFilters = [[[NSMutableArray alloc] init] autorelease];
466 FML_DCHECK(!clipView.maskView ||
468 if (clipView.maskView) {
469 [mask_view_pool_.get() insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)];
470 clipView.maskView = nil;
472 CGFloat screenScale = [UIScreen mainScreen].scale;
473 auto iter = mutators_stack.Begin();
474 while (iter != mutators_stack.End()) {
475 switch ((*iter)->GetType()) {
477 transformMatrix.preConcat((*iter)->GetMatrix());
485 ClipViewSetMaskView(clipView);
487 matrix:transformMatrix];
495 ClipViewSetMaskView(clipView);
497 matrix:transformMatrix];
504 ClipViewSetMaskView(clipView);
506 matrix:transformMatrix];
510 embedded_view.alpha = (*iter)->GetAlphaFloat() * embedded_view.alpha;
512 case kBackdropFilter: {
520 filterRect = CGRectApplyAffineTransform(
521 filterRect, CGAffineTransformMakeScale(1 / screenScale, 1 / screenScale));
525 if (CGRectIsNull(CGRectIntersection(filterRect, clipView.frame))) {
528 CGRect intersection = CGRectIntersection(filterRect, clipView.frame);
529 CGRect frameInClipView = [flutter_view_.get() convertRect:intersection toView:clipView];
534 CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x();
535 UIVisualEffectView* visualEffectView = [[[UIVisualEffectView alloc]
536 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]] autorelease];
539 blurRadius:blurRadius
540 visualEffectView:visualEffectView] autorelease];
544 [blurFilters addObject:filter];
561 transformMatrix.postScale(1 / screenScale, 1 / screenScale);
570 transformMatrix.postTranslate(-clipView.frame.origin.x, -clipView.frame.origin.y);
583 void FlutterPlatformViewsController::CompositeWithParams(int64_t view_id,
584 const EmbeddedViewParams& params) {
585 CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height());
587 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
588 FML_DCHECK(CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero));
589 if (non_zero_origin_views_.find(view_id) == non_zero_origin_views_.end() &&
590 !CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero)) {
591 non_zero_origin_views_.insert(view_id);
593 @"A Embedded PlatformView's origin is not CGPointZero.\n"
595 " View info: \n %@ \n"
596 "A non-zero origin might cause undefined behavior.\n"
597 "See https://github.com/flutter/flutter/issues/109700 for more details.\n"
598 "If you are the author of the PlatformView, please update the implementation of the "
599 "PlatformView to have a (0, 0) origin.\n"
600 "If you have a valid case of using a non-zero origin, "
601 "please leave a comment at https://github.com/flutter/flutter/issues/109700 with details.",
602 @(view_id), [touchInterceptor embeddedView]);
605 touchInterceptor.layer.transform = CATransform3DIdentity;
606 touchInterceptor.frame = frame;
607 touchInterceptor.alpha = 1;
609 const MutatorsStack& mutatorStack = params.mutatorsStack();
610 UIView* clippingView = root_views_[view_id].get();
615 const SkRect& rect = params.finalBoundingRect();
616 CGFloat screenScale = [UIScreen mainScreen].scale;
617 clippingView.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale,
618 rect.width() / screenScale, rect.height() / screenScale);
619 ApplyMutators(mutatorStack, touchInterceptor, rect);
622 DlCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(int64_t view_id) {
624 FML_DCHECK([[NSThread currentThread] isMainThread]);
626 if (views_to_recomposite_.count(view_id) == 0) {
627 return slices_[view_id]->canvas();
629 CompositeWithParams(view_id, current_composition_params_[view_id]);
630 views_to_recomposite_.erase(view_id);
631 return slices_[view_id]->canvas();
634 void FlutterPlatformViewsController::Reset() {
635 for (int64_t view_id : active_composition_order_) {
636 UIView* sub_view = root_views_[view_id].get();
637 [sub_view removeFromSuperview];
640 touch_interceptors_.clear();
642 composition_order_.clear();
643 active_composition_order_.clear();
645 current_composition_params_.clear();
647 views_to_recomposite_.clear();
648 layer_pool_->RecycleLayers();
649 visited_platform_views_.clear();
652 SkRect FlutterPlatformViewsController::GetPlatformViewRect(int64_t view_id) {
654 UIScreen* screen = [UIScreen mainScreen];
655 CGRect platform_view_cgrect = [platform_view convertRect:platform_view.bounds
656 toView:flutter_view_];
657 return SkRect::MakeXYWH(platform_view_cgrect.origin.x * screen.scale,
658 platform_view_cgrect.origin.y * screen.scale,
659 platform_view_cgrect.size.width * screen.scale,
660 platform_view_cgrect.size.height * screen.scale
664 bool FlutterPlatformViewsController::SubmitFrame(GrDirectContext* gr_context,
665 const std::shared_ptr<IOSContext>& ios_context,
666 std::unique_ptr<SurfaceFrame> frame) {
667 TRACE_EVENT0(
"flutter",
"FlutterPlatformViewsController::SubmitFrame");
670 FML_DCHECK([[NSThread currentThread] isMainThread]);
671 if (flutter_view_ ==
nullptr) {
672 return frame->Submit();
677 DlCanvas* background_canvas = frame->Canvas();
680 background_canvas->Flush();
684 DlAutoCanvasRestore save(background_canvas,
true);
687 LayersMap platform_view_layers;
689 auto did_submit =
true;
690 auto num_platform_views = composition_order_.size();
692 for (
size_t i = 0; i < num_platform_views; i++) {
693 int64_t platform_view_id = composition_order_[i];
694 EmbedderViewSlice* slice = slices_[platform_view_id].get();
695 slice->end_recording();
699 for (
size_t j = i + 1; j > 0; j--) {
700 int64_t current_platform_view_id = composition_order_[j - 1];
701 SkRect platform_view_rect = GetPlatformViewRect(current_platform_view_id);
702 std::list<SkRect> intersection_rects =
703 slice->searchNonOverlappingDrawnRects(platform_view_rect);
704 auto allocation_size = intersection_rects.size();
708 auto overlay_id = platform_view_layers[current_platform_view_id].size();
715 if (allocation_size > kMaxLayerAllocations) {
716 SkRect joined_rect = SkRect::MakeEmpty();
717 for (
const SkRect& rect : intersection_rects) {
718 joined_rect.join(rect);
722 intersection_rects.clear();
723 intersection_rects.push_back(joined_rect);
725 for (SkRect& joined_rect : intersection_rects) {
728 joined_rect.intersect(platform_view_rect);
732 joined_rect.setLTRB(std::floor(joined_rect.left()), std::floor(joined_rect.top()),
733 std::ceil(joined_rect.right()), std::ceil(joined_rect.bottom()));
736 background_canvas->ClipRect(joined_rect, DlCanvas::ClipOp::kDifference);
738 std::shared_ptr<FlutterPlatformViewLayer> layer = GetLayer(gr_context,
742 current_platform_view_id,
745 did_submit &= layer->did_submit_last_frame;
746 platform_view_layers[current_platform_view_id].push_back(layer);
750 slice->render_into(background_canvas);
758 RemoveUnusedLayers();
760 BringLayersIntoView(platform_view_layers);
762 layer_pool_->RecycleLayers();
764 did_submit &= frame->Submit();
769 CommitCATransactionIfNeeded();
773 void FlutterPlatformViewsController::BringLayersIntoView(LayersMap layer_map) {
774 FML_DCHECK(flutter_view_);
775 UIView* flutter_view = flutter_view_.get();
777 active_composition_order_.clear();
778 NSMutableArray* desired_platform_subviews = [NSMutableArray array];
779 for (
size_t i = 0; i < composition_order_.size(); i++) {
780 int64_t platform_view_id = composition_order_[i];
781 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_map[platform_view_id];
782 UIView* platform_view_root = root_views_[platform_view_id].get();
783 [desired_platform_subviews addObject:platform_view_root];
784 for (
const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
785 [desired_platform_subviews addObject:layer->overlay_view_wrapper];
787 active_composition_order_.push_back(platform_view_id);
790 NSSet* desired_platform_subviews_set = [NSSet setWithArray:desired_platform_subviews];
791 NSArray* existing_platform_subviews = [flutter_view.subviews
792 filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object,
793 NSDictionary* bindings) {
794 return [desired_platform_subviews_set containsObject:object];
800 if (![desired_platform_subviews isEqualToArray:existing_platform_subviews]) {
801 for (UIView* subview in desired_platform_subviews) {
803 [flutter_view addSubview:subview];
808 std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLayer(
809 GrDirectContext* gr_context,
810 const std::shared_ptr<IOSContext>& ios_context,
811 EmbedderViewSlice* slice,
814 int64_t overlay_id) {
815 FML_DCHECK(flutter_view_);
816 std::shared_ptr<FlutterPlatformViewLayer> layer = layer_pool_->GetLayer(gr_context, ios_context);
818 UIView* overlay_view_wrapper = layer->overlay_view_wrapper.get();
819 auto screenScale = [UIScreen mainScreen].scale;
822 overlay_view_wrapper.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale,
823 rect.width() / screenScale, rect.height() / screenScale);
825 overlay_view_wrapper.accessibilityIdentifier =
826 [NSString stringWithFormat:@"platform_view[%lld].overlay[%lld]", view_id, overlay_id];
828 UIView* overlay_view = layer->overlay_view.get();
831 overlay_view.frame = [flutter_view_.get() convertRect:flutter_view_.get().bounds
832 toView:overlay_view_wrapper];
834 overlay_view.accessibilityIdentifier =
835 [NSString stringWithFormat:@"platform_view[%lld].overlay_view[%lld]", view_id, overlay_id];
837 std::unique_ptr<SurfaceFrame> frame = layer->surface->AcquireFrame(frame_size_);
842 DlCanvas* overlay_canvas = frame->Canvas();
843 int restore_count = overlay_canvas->GetSaveCount();
844 overlay_canvas->Save();
845 overlay_canvas->ClipRect(rect);
846 overlay_canvas->Clear(DlColor::kTransparent());
847 slice->render_into(overlay_canvas);
848 overlay_canvas->RestoreToCount(restore_count);
850 layer->did_submit_last_frame = frame->Submit();
854 void FlutterPlatformViewsController::RemoveUnusedLayers() {
855 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_pool_->GetUnusedLayers();
856 for (
const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
857 [layer->overlay_view_wrapper removeFromSuperview];
860 std::unordered_set<int64_t> composition_order_set;
861 for (int64_t view_id : composition_order_) {
862 composition_order_set.insert(view_id);
865 for (int64_t view_id : active_composition_order_) {
866 if (composition_order_set.find(view_id) == composition_order_set.end()) {
867 UIView* platform_view_root = root_views_[view_id].get();
868 [platform_view_root removeFromSuperview];
873 void FlutterPlatformViewsController::DisposeViews() {
874 if (views_to_dispose_.empty()) {
878 FML_DCHECK([[NSThread currentThread] isMainThread]);
880 std::unordered_set<int64_t> views_to_composite(composition_order_.begin(),
881 composition_order_.end());
882 std::unordered_set<int64_t> views_to_delay_dispose;
883 for (int64_t viewId : views_to_dispose_) {
884 if (views_to_composite.count(viewId)) {
885 views_to_delay_dispose.insert(viewId);
888 UIView* root_view = root_views_[viewId].get();
889 [root_view removeFromSuperview];
890 views_.erase(viewId);
891 touch_interceptors_.erase(viewId);
892 root_views_.erase(viewId);
893 current_composition_params_.erase(viewId);
894 clip_count_.erase(viewId);
895 views_to_recomposite_.erase(viewId);
898 views_to_dispose_ = std::move(views_to_delay_dispose);
901 void FlutterPlatformViewsController::BeginCATransaction() {
902 FML_DCHECK([[NSThread currentThread] isMainThread]);
903 FML_DCHECK(!catransaction_added_);
904 [CATransaction begin];
905 catransaction_added_ =
true;
908 void FlutterPlatformViewsController::CommitCATransactionIfNeeded() {
909 if (catransaction_added_) {
910 FML_DCHECK([[NSThread currentThread] isMainThread]);
911 [CATransaction commit];
912 catransaction_added_ =
false;
916 void FlutterPlatformViewsController::ResetFrameState() {
918 composition_order_.clear();
919 visited_platform_views_.clear();
940 - (instancetype)initWithTarget:(
id)target
942 forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer;
956 - (instancetype)initWithTarget:(
id)target
957 platformViewsController:
958 (fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController;
962 fml::scoped_nsobject<DelayingGestureRecognizer> _delayingRecognizer;
970 - (instancetype)initWithEmbeddedView:(UIView*)embeddedView
971 platformViewsController:
972 (fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController
973 gestureRecognizersBlockingPolicy:
975 self = [
super initWithFrame:embeddedView.frame];
977 self.multipleTouchEnabled = YES;
979 embeddedView.autoresizingMask =
980 (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
982 [
self addSubview:embeddedView];
986 platformViewsController:std::move(platformViewsController)] autorelease];
991 forwardingRecognizer:forwardingRecognizer]);
994 [
self addGestureRecognizer:_delayingRecognizer.get()];
995 [
self addGestureRecognizer:forwardingRecognizer];
1000 - (UIView*)embeddedView {
1001 return [[_embeddedView retain] autorelease];
1004 - (void)releaseGesture {
1005 _delayingRecognizer.get().state = UIGestureRecognizerStateFailed;
1008 - (void)blockGesture {
1012 _delayingRecognizer.get().state = UIGestureRecognizerStateEnded;
1015 if (_delayingRecognizer.get().touchedEndedWithoutBlocking) {
1019 _delayingRecognizer.get().state = UIGestureRecognizerStateEnded;
1024 _delayingRecognizer.get().shouldEndInNextTouchesEnded = YES;
1035 - (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1038 - (void)touchesMoved:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1041 - (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1044 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
1047 - (void)setFlutterAccessibilityContainer:(NSObject*)flutterAccessibilityContainer {
1051 - (
id)accessibilityContainer {
1058 fml::scoped_nsobject<UIGestureRecognizer> _forwardingRecognizer;
1061 - (instancetype)initWithTarget:(
id)target
1063 forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer {
1064 self = [
super initWithTarget:target action:action];
1066 self.delaysTouchesBegan = YES;
1067 self.delaysTouchesEnded = YES;
1068 self.delegate =
self;
1070 self.touchedEndedWithoutBlocking = NO;
1071 _forwardingRecognizer.reset([forwardingRecognizer retain]);
1076 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1077 shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
1080 return otherGestureRecognizer != _forwardingRecognizer.get() && otherGestureRecognizer !=
self;
1083 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1084 shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
1085 return otherGestureRecognizer ==
self;
1088 - (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1089 self.touchedEndedWithoutBlocking = NO;
1090 [
super touchesBegan:touches withEvent:event];
1093 - (void)touchesEnded:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1094 if (
self.shouldEndInNextTouchesEnded) {
1095 self.state = UIGestureRecognizerStateEnded;
1096 self.shouldEndInNextTouchesEnded = NO;
1098 self.touchedEndedWithoutBlocking = YES;
1100 [
super touchesEnded:touches withEvent:event];
1103 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
1104 self.state = UIGestureRecognizerStateFailed;
1126 - (instancetype)initWithTarget:(
id)target
1127 platformViewsController:
1128 (fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController {
1129 self = [
super initWithTarget:target action:nil];
1131 self.delegate =
self;
1132 FML_DCHECK(platformViewsController.get() !=
nullptr);
1139 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
1147 [_flutterViewController.get() touchesBegan:touches withEvent:event];
1151 - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
1152 [_flutterViewController.get() touchesMoved:touches withEvent:event];
1155 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
1156 [_flutterViewController.get() touchesEnded:touches withEvent:event];
1163 self.state = UIGestureRecognizerStateFailed;
1168 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
1177 self.state = UIGestureRecognizerStateFailed;
1182 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1183 shouldRecognizeSimultaneouslyWithGestureRecognizer:
1184 (UIGestureRecognizer*)otherGestureRecognizer {