5 #include <Metal/Metal.h>
6 #import <UIKit/UIGestureRecognizerSubclass.h>
13 #include "flutter/common/graphics/persistent_cache.h"
14 #include "flutter/fml/platform/darwin/scoped_nsobject.h"
24 if (
self.isFirstResponder) {
27 for (UIView* subview in
self.subviews) {
28 if (subview.flt_hasFirstResponderInViewHierarchySubtree) {
45 const SkRect& platformview_boundingrect,
46 const SkMatrix& transform_matrix) {
47 SkRect transformed_rect = transform_matrix.mapRect(clip_rect);
48 return transformed_rect.contains(platformview_boundingrect);
60 const SkRect& platformview_boundingrect,
61 const SkMatrix& transform_matrix) {
62 SkVector upper_left = clip_rrect.radii(SkRRect::Corner::kUpperLeft_Corner);
63 SkVector upper_right = clip_rrect.radii(SkRRect::Corner::kUpperRight_Corner);
64 SkVector lower_right = clip_rrect.radii(SkRRect::Corner::kLowerRight_Corner);
65 SkVector lower_left = clip_rrect.radii(SkRRect::Corner::kLowerLeft_Corner);
66 SkScalar transformed_upper_left_x = transform_matrix.mapRadius(upper_left.x());
67 SkScalar transformed_upper_left_y = transform_matrix.mapRadius(upper_left.y());
68 SkScalar transformed_upper_right_x = transform_matrix.mapRadius(upper_right.x());
69 SkScalar transformed_upper_right_y = transform_matrix.mapRadius(upper_right.y());
70 SkScalar transformed_lower_right_x = transform_matrix.mapRadius(lower_right.x());
71 SkScalar transformed_lower_right_y = transform_matrix.mapRadius(lower_right.y());
72 SkScalar transformed_lower_left_x = transform_matrix.mapRadius(lower_left.x());
73 SkScalar transformed_lower_left_y = transform_matrix.mapRadius(lower_left.y());
74 SkRect transformed_clip_rect = transform_matrix.mapRect(clip_rrect.rect());
75 SkRRect transformed_rrect;
76 SkVector corners[] = {{transformed_upper_left_x, transformed_upper_left_y},
77 {transformed_upper_right_x, transformed_upper_right_y},
78 {transformed_lower_right_x, transformed_lower_right_y},
79 {transformed_lower_left_x, transformed_lower_left_y}};
80 transformed_rrect.setRectRadii(transformed_clip_rect, corners);
81 return transformed_rrect.contains(platformview_boundingrect);
88 std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewLayerPool::GetLayer(
89 GrDirectContext* gr_context,
90 const std::shared_ptr<IOSContext>& ios_context,
91 MTLPixelFormat pixel_format) {
92 if (available_layer_index_ >= layers_.size()) {
93 std::shared_ptr<FlutterPlatformViewLayer> layer;
94 fml::scoped_nsobject<UIView> overlay_view;
95 fml::scoped_nsobject<UIView> overlay_view_wrapper;
97 bool impeller_enabled = !!ios_context->GetImpellerContext();
98 if (!gr_context && !impeller_enabled) {
102 auto ca_layer = fml::scoped_nsobject<CALayer>{[[overlay_view.get() layer] retain]};
103 std::unique_ptr<IOSSurface> ios_surface = IOSSurface::Create(ios_context, ca_layer);
104 std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
106 layer = std::make_shared<FlutterPlatformViewLayer>(
107 std::move(overlay_view), std::move(overlay_view_wrapper), std::move(ios_surface),
110 CGFloat screenScale = [UIScreen mainScreen].scale;
112 pixelFormat:pixel_format]);
113 overlay_view_wrapper.reset([[
FlutterOverlayView alloc] initWithContentsScale:screenScale
114 pixelFormat:pixel_format]);
116 auto ca_layer = fml::scoped_nsobject<CALayer>{[[overlay_view.get() layer] retain]};
117 std::unique_ptr<IOSSurface> ios_surface = IOSSurface::Create(ios_context, ca_layer);
118 std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
120 layer = std::make_shared<FlutterPlatformViewLayer>(
121 std::move(overlay_view), std::move(overlay_view_wrapper), std::move(ios_surface),
123 layer->gr_context = gr_context;
139 layer->overlay_view_wrapper.get().clipsToBounds = YES;
140 [layer->overlay_view_wrapper.get() addSubview:layer->overlay_view];
141 layers_.push_back(layer);
143 std::shared_ptr<FlutterPlatformViewLayer> layer = layers_[available_layer_index_];
144 if (gr_context != layer->gr_context) {
145 layer->gr_context = gr_context;
148 IOSSurface* ios_surface = layer->ios_surface.get();
149 std::unique_ptr<Surface> surface = ios_surface->
CreateGPUSurface(gr_context);
150 layer->surface = std::move(surface);
152 available_layer_index_++;
156 void FlutterPlatformViewLayerPool::RecycleLayers() {
157 available_layer_index_ = 0;
160 std::vector<std::shared_ptr<FlutterPlatformViewLayer>>
161 FlutterPlatformViewLayerPool::GetUnusedLayers() {
162 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> results;
163 for (
size_t i = available_layer_index_; i < layers_.size(); i++) {
164 results.push_back(layers_[i]);
169 void FlutterPlatformViewsController::SetFlutterView(UIView* flutter_view) {
170 flutter_view_.reset([flutter_view retain]);
173 void FlutterPlatformViewsController::SetFlutterViewController(
174 UIViewController* flutter_view_controller) {
175 flutter_view_controller_.reset([flutter_view_controller retain]);
178 UIViewController* FlutterPlatformViewsController::getFlutterViewController() {
179 return flutter_view_controller_.get();
183 if ([[call method] isEqualToString:
@"create"]) {
184 OnCreate(call, result);
185 }
else if ([[call method] isEqualToString:
@"dispose"]) {
186 OnDispose(call, result);
187 }
else if ([[call method] isEqualToString:
@"acceptGesture"]) {
188 OnAcceptGesture(call, result);
189 }
else if ([[call method] isEqualToString:
@"rejectGesture"]) {
190 OnRejectGesture(call, result);
197 NSDictionary<NSString*, id>* args = [call
arguments];
199 int64_t viewId = [args[@"id"] longLongValue];
200 NSString* viewTypeString = args[@"viewType"];
201 std::string viewType(viewTypeString.UTF8String);
203 if (views_.count(viewId) != 0) {
205 message:
@"trying to create an already created view"
206 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
209 NSObject<FlutterPlatformViewFactory>* factory = factories_[viewType].get();
210 if (factory == nil) {
212 errorWithCode:
@"unregistered_view_type"
213 message:[NSString stringWithFormat:
@"A UIKitView widget is trying to create a "
214 @"PlatformView with an unregistered type: < %@ >",
216 details:
@"If you are the author of the PlatformView, make sure `registerViewFactory` "
219 @"https://docs.flutter.dev/development/platform-integration/"
220 @"platform-views#on-the-platform-side-1 for more details.\n"
221 @"If you are not the author of the PlatformView, make sure to call "
222 @"`GeneratedPluginRegistrant.register`."]);
227 if ([factory respondsToSelector:
@selector(createArgsCodec)]) {
228 NSObject<FlutterMessageCodec>* codec = [factory createArgsCodec];
229 if (codec != nil && args[
@"params"] != nil) {
231 params = [codec decode:paramsData.data];
235 NSObject<FlutterPlatformView>* embedded_view = [factory createWithFrame:CGRectZero
236 viewIdentifier:viewId
241 [NSString stringWithFormat:@"platform_view[%lld]", viewId];
242 views_[viewId] = fml::scoped_nsobject<NSObject<FlutterPlatformView>>([embedded_view retain]);
245 initWithEmbeddedView:platform_view
246 platformViewsController:GetWeakPtr()
247 gestureRecognizersBlockingPolicy:gesture_recognizers_blocking_policies_[viewType]]
250 touch_interceptors_[viewId] =
251 fml::scoped_nsobject<FlutterTouchInterceptingView>([touch_interceptor retain]);
255 [clipping_view addSubview:touch_interceptor];
256 root_views_[viewId] = fml::scoped_nsobject<UIView>([clipping_view retain]);
263 int64_t viewId = [arg longLongValue];
265 if (views_.count(viewId) == 0) {
267 message:
@"trying to dispose an unknown"
268 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
272 views_to_dispose_.insert(viewId);
278 NSDictionary<NSString*, id>* args = [call
arguments];
279 int64_t viewId = [args[@"id"] longLongValue];
281 if (views_.count(viewId) == 0) {
283 message:
@"trying to set gesture state for an unknown view"
284 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
296 NSDictionary<NSString*, id>* args = [call
arguments];
297 int64_t viewId = [args[@"id"] longLongValue];
299 if (views_.count(viewId) == 0) {
301 message:
@"trying to set gesture state for an unknown view"
302 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
312 void FlutterPlatformViewsController::RegisterViewFactory(
313 NSObject<FlutterPlatformViewFactory>* factory,
316 std::string idString([factoryId UTF8String]);
317 FML_CHECK(factories_.count(idString) == 0);
318 factories_[idString] =
319 fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>([factory retain]);
320 gesture_recognizers_blocking_policies_[idString] = gestureRecognizerBlockingPolicy;
323 void FlutterPlatformViewsController::BeginFrame(SkISize frame_size) {
325 frame_size_ = frame_size;
328 void FlutterPlatformViewsController::CancelFrame() {
335 bool FlutterPlatformViewsController::HasPlatformViewThisOrNextFrame() {
336 return !composition_order_.empty() || !active_composition_order_.empty();
339 const int FlutterPlatformViewsController::kDefaultMergedLeaseDuration;
341 PostPrerollResult FlutterPlatformViewsController::PostPrerollAction(
342 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {
345 if (!HasPlatformViewThisOrNextFrame()) {
346 return PostPrerollResult::kSuccess;
348 if (!raster_thread_merger->IsMerged()) {
358 return PostPrerollResult::kSkipAndRetryFrame;
364 BeginCATransaction();
365 raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration);
366 return PostPrerollResult::kSuccess;
369 void FlutterPlatformViewsController::EndFrame(
370 bool should_resubmit_frame,
371 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {
372 if (should_resubmit_frame) {
373 raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
377 void FlutterPlatformViewsController::PushFilterToVisitedPlatformViews(
378 const std::shared_ptr<const DlImageFilter>& filter,
379 const SkRect& filter_rect) {
380 for (int64_t
id : visited_platform_views_) {
381 EmbeddedViewParams params = current_composition_params_[id];
382 params.PushImageFilter(filter, filter_rect);
383 current_composition_params_[id] = params;
387 void FlutterPlatformViewsController::PrerollCompositeEmbeddedView(
389 std::unique_ptr<EmbeddedViewParams> params) {
392 FML_DCHECK(!catransaction_added_);
394 SkRect view_bounds = SkRect::Make(frame_size_);
395 std::unique_ptr<EmbedderViewSlice> view;
396 view = std::make_unique<DisplayListEmbedderViewSlice>(view_bounds);
397 slices_.insert_or_assign(view_id, std::move(view));
399 composition_order_.push_back(view_id);
401 if (current_composition_params_.count(view_id) == 1 &&
402 current_composition_params_[view_id] == *params.get()) {
406 current_composition_params_[view_id] = EmbeddedViewParams(*params.get());
407 views_to_recomposite_.insert(view_id);
410 size_t FlutterPlatformViewsController::EmbeddedViewCount() {
411 return composition_order_.size();
414 UIView* FlutterPlatformViewsController::GetPlatformViewByID(int64_t view_id) {
420 if (views_.empty()) {
423 return touch_interceptors_[view_id].get();
426 long FlutterPlatformViewsController::FindFirstResponderPlatformViewId() {
427 for (
auto const& [
id, root_view] : root_views_) {
428 if ((UIView*)(root_view.get()).flt_hasFirstResponderInViewHierarchySubtree) {
435 int FlutterPlatformViewsController::CountClips(
const MutatorsStack& mutators_stack) {
436 std::vector<std::shared_ptr<Mutator>>::const_reverse_iterator iter = mutators_stack.Bottom();
438 while (iter != mutators_stack.Top()) {
439 if ((*iter)->IsClipType()) {
447 void FlutterPlatformViewsController::ClipViewSetMaskView(UIView* clipView) {
448 if (clipView.maskView) {
451 UIView* flutterView = flutter_view_.get();
453 CGRectMake(-clipView.frame.origin.x, -clipView.frame.origin.y,
454 CGRectGetWidth(flutterView.bounds), CGRectGetHeight(flutterView.bounds));
455 clipView.maskView = [mask_view_pool_.get() getMaskViewWithFrame:frame];
460 void FlutterPlatformViewsController::ApplyMutators(
const MutatorsStack& mutators_stack,
461 UIView* embedded_view,
462 const SkRect& bounding_rect) {
463 if (flutter_view_ ==
nullptr) {
466 FML_DCHECK(CATransform3DEqualToTransform(embedded_view.layer.transform, CATransform3DIdentity));
470 SkMatrix transformMatrix;
471 NSMutableArray* blurFilters = [[[NSMutableArray alloc] init] autorelease];
472 FML_DCHECK(!clipView.maskView ||
474 if (clipView.maskView) {
475 [mask_view_pool_.get() insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)];
476 clipView.maskView = nil;
478 CGFloat screenScale = [UIScreen mainScreen].scale;
479 auto iter = mutators_stack.Begin();
480 while (iter != mutators_stack.End()) {
481 switch ((*iter)->GetType()) {
483 transformMatrix.preConcat((*iter)->GetMatrix());
491 ClipViewSetMaskView(clipView);
493 matrix:transformMatrix];
501 ClipViewSetMaskView(clipView);
503 matrix:transformMatrix];
510 ClipViewSetMaskView(clipView);
512 matrix:transformMatrix];
516 embedded_view.alpha = (*iter)->GetAlphaFloat() * embedded_view.alpha;
518 case kBackdropFilter: {
526 filterRect = CGRectApplyAffineTransform(
527 filterRect, CGAffineTransformMakeScale(1 / screenScale, 1 / screenScale));
531 if (CGRectIsNull(CGRectIntersection(filterRect, clipView.frame))) {
534 CGRect intersection = CGRectIntersection(filterRect, clipView.frame);
535 CGRect frameInClipView = [flutter_view_.get() convertRect:intersection toView:clipView];
540 CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x();
541 UIVisualEffectView* visualEffectView = [[[UIVisualEffectView alloc]
542 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]] autorelease];
545 blurRadius:blurRadius
546 visualEffectView:visualEffectView] autorelease];
550 [blurFilters addObject:filter];
567 transformMatrix.postScale(1 / screenScale, 1 / screenScale);
576 transformMatrix.postTranslate(-clipView.frame.origin.x, -clipView.frame.origin.y);
589 void FlutterPlatformViewsController::CompositeWithParams(int64_t view_id,
590 const EmbeddedViewParams& params) {
591 CGRect frame = CGRectMake(0, 0, params.sizePoints().width(), params.sizePoints().height());
593 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
594 FML_DCHECK(CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero));
595 if (non_zero_origin_views_.find(view_id) == non_zero_origin_views_.end() &&
596 !CGPointEqualToPoint([touchInterceptor embeddedView].frame.origin, CGPointZero)) {
597 non_zero_origin_views_.insert(view_id);
599 @"A Embedded PlatformView's origin is not CGPointZero.\n"
601 " View info: \n %@ \n"
602 "A non-zero origin might cause undefined behavior.\n"
603 "See https://github.com/flutter/flutter/issues/109700 for more details.\n"
604 "If you are the author of the PlatformView, please update the implementation of the "
605 "PlatformView to have a (0, 0) origin.\n"
606 "If you have a valid case of using a non-zero origin, "
607 "please leave a comment at https://github.com/flutter/flutter/issues/109700 with details.",
608 @(view_id), [touchInterceptor embeddedView]);
611 touchInterceptor.layer.transform = CATransform3DIdentity;
612 touchInterceptor.frame = frame;
613 touchInterceptor.alpha = 1;
615 const MutatorsStack& mutatorStack = params.mutatorsStack();
616 UIView* clippingView = root_views_[view_id].get();
621 const SkRect& rect = params.finalBoundingRect();
622 CGFloat screenScale = [UIScreen mainScreen].scale;
623 clippingView.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale,
624 rect.width() / screenScale, rect.height() / screenScale);
625 ApplyMutators(mutatorStack, touchInterceptor, rect);
628 DlCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(int64_t view_id) {
630 FML_DCHECK([[NSThread currentThread] isMainThread]);
632 if (views_to_recomposite_.count(view_id) == 0) {
633 return slices_[view_id]->canvas();
635 CompositeWithParams(view_id, current_composition_params_[view_id]);
636 views_to_recomposite_.erase(view_id);
637 return slices_[view_id]->canvas();
640 void FlutterPlatformViewsController::Reset() {
641 for (int64_t view_id : active_composition_order_) {
642 UIView* sub_view = root_views_[view_id].get();
643 [sub_view removeFromSuperview];
646 touch_interceptors_.clear();
648 composition_order_.clear();
649 active_composition_order_.clear();
651 current_composition_params_.clear();
653 views_to_recomposite_.clear();
654 layer_pool_->RecycleLayers();
655 visited_platform_views_.clear();
658 SkRect FlutterPlatformViewsController::GetPlatformViewRect(int64_t view_id) {
660 UIScreen* screen = [UIScreen mainScreen];
661 CGRect platform_view_cgrect = [platform_view convertRect:platform_view.bounds
662 toView:flutter_view_];
663 return SkRect::MakeXYWH(platform_view_cgrect.origin.x * screen.scale,
664 platform_view_cgrect.origin.y * screen.scale,
665 platform_view_cgrect.size.width * screen.scale,
666 platform_view_cgrect.size.height * screen.scale
670 bool FlutterPlatformViewsController::SubmitFrame(GrDirectContext* gr_context,
671 const std::shared_ptr<IOSContext>& ios_context,
672 std::unique_ptr<SurfaceFrame> frame) {
673 TRACE_EVENT0(
"flutter",
"FlutterPlatformViewsController::SubmitFrame");
676 FML_DCHECK([[NSThread currentThread] isMainThread]);
677 if (flutter_view_ ==
nullptr) {
678 return frame->Submit();
683 DlCanvas* background_canvas = frame->Canvas();
686 background_canvas->Flush();
690 DlAutoCanvasRestore save(background_canvas,
true);
693 LayersMap platform_view_layers;
695 auto did_submit =
true;
696 auto num_platform_views = composition_order_.size();
700 for (
size_t i = 0; i < num_platform_views; i++) {
701 int64_t platform_view_id = composition_order_[i];
702 EmbedderViewSlice* slice = slices_[platform_view_id].get();
703 slice->end_recording();
707 for (
size_t j = i + 1; j > 0; j--) {
708 int64_t current_platform_view_id = composition_order_[j - 1];
709 SkRect platform_view_rect = GetPlatformViewRect(current_platform_view_id);
710 std::vector<SkIRect> intersection_rects = slice->region(platform_view_rect).getRects();
711 const SkIRect rounded_in_platform_view_rect = platform_view_rect.roundIn();
722 for (
auto it = intersection_rects.begin(); it != intersection_rects.end(); ) {
725 if (!SkIRect::Intersects(*it, rounded_in_platform_view_rect)) {
726 it = intersection_rects.erase(it);
732 auto allocation_size = intersection_rects.size();
736 auto overlay_id = platform_view_layers[current_platform_view_id].size();
743 if (allocation_size > kMaxLayerAllocations) {
744 SkIRect joined_rect = SkIRect::MakeEmpty();
745 for (
const SkIRect& rect : intersection_rects) {
746 joined_rect.join(rect);
750 intersection_rects.clear();
751 intersection_rects.push_back(joined_rect);
753 for (SkIRect& joined_rect : intersection_rects) {
756 joined_rect.intersect(platform_view_rect.roundOut());
759 background_canvas->ClipRect(SkRect::Make(joined_rect), DlCanvas::ClipOp::kDifference);
761 std::shared_ptr<FlutterPlatformViewLayer> layer =
766 current_platform_view_id,
770 did_submit &= layer->did_submit_last_frame;
771 platform_view_layers[current_platform_view_id].push_back(layer);
775 slice->render_into(background_canvas);
783 RemoveUnusedLayers();
785 BringLayersIntoView(platform_view_layers);
787 layer_pool_->RecycleLayers();
789 did_submit &= frame->Submit();
794 CommitCATransactionIfNeeded();
798 void FlutterPlatformViewsController::BringLayersIntoView(LayersMap layer_map) {
799 FML_DCHECK(flutter_view_);
800 UIView* flutter_view = flutter_view_.get();
802 active_composition_order_.clear();
803 NSMutableArray* desired_platform_subviews = [NSMutableArray array];
804 for (
size_t i = 0; i < composition_order_.size(); i++) {
805 int64_t platform_view_id = composition_order_[i];
806 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_map[platform_view_id];
807 UIView* platform_view_root = root_views_[platform_view_id].get();
808 [desired_platform_subviews addObject:platform_view_root];
809 for (
const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
810 [desired_platform_subviews addObject:layer->overlay_view_wrapper];
812 active_composition_order_.push_back(platform_view_id);
815 NSSet* desired_platform_subviews_set = [NSSet setWithArray:desired_platform_subviews];
816 NSArray* existing_platform_subviews = [flutter_view.subviews
817 filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object,
818 NSDictionary* bindings) {
819 return [desired_platform_subviews_set containsObject:object];
825 if (![desired_platform_subviews isEqualToArray:existing_platform_subviews]) {
826 for (UIView* subview in desired_platform_subviews) {
828 [flutter_view addSubview:subview];
833 std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLayer(
834 GrDirectContext* gr_context,
835 const std::shared_ptr<IOSContext>& ios_context,
836 EmbedderViewSlice* slice,
840 MTLPixelFormat pixel_format) {
841 FML_DCHECK(flutter_view_);
842 std::shared_ptr<FlutterPlatformViewLayer> layer =
843 layer_pool_->GetLayer(gr_context, ios_context, pixel_format);
845 UIView* overlay_view_wrapper = layer->overlay_view_wrapper.get();
846 auto screenScale = [UIScreen mainScreen].scale;
849 overlay_view_wrapper.frame = CGRectMake(rect.x() / screenScale, rect.y() / screenScale,
850 rect.width() / screenScale, rect.height() / screenScale);
852 overlay_view_wrapper.accessibilityIdentifier =
853 [NSString stringWithFormat:@"platform_view[%lld].overlay[%lld]", view_id, overlay_id];
855 UIView* overlay_view = layer->overlay_view.get();
858 overlay_view.frame = [flutter_view_.get() convertRect:flutter_view_.get().bounds
859 toView:overlay_view_wrapper];
861 overlay_view.accessibilityIdentifier =
862 [NSString stringWithFormat:@"platform_view[%lld].overlay_view[%lld]", view_id, overlay_id];
864 std::unique_ptr<SurfaceFrame> frame = layer->surface->AcquireFrame(frame_size_);
869 DlCanvas* overlay_canvas = frame->Canvas();
870 int restore_count = overlay_canvas->GetSaveCount();
871 overlay_canvas->Save();
872 overlay_canvas->ClipRect(SkRect::Make(rect));
873 overlay_canvas->Clear(DlColor::kTransparent());
874 slice->render_into(overlay_canvas);
875 overlay_canvas->RestoreToCount(restore_count);
877 layer->did_submit_last_frame = frame->Submit();
881 void FlutterPlatformViewsController::RemoveUnusedLayers() {
882 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_pool_->GetUnusedLayers();
883 for (
const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
884 [layer->overlay_view_wrapper removeFromSuperview];
887 std::unordered_set<int64_t> composition_order_set;
888 for (int64_t view_id : composition_order_) {
889 composition_order_set.insert(view_id);
892 for (int64_t view_id : active_composition_order_) {
893 if (composition_order_set.find(view_id) == composition_order_set.end()) {
894 UIView* platform_view_root = root_views_[view_id].get();
895 [platform_view_root removeFromSuperview];
900 void FlutterPlatformViewsController::DisposeViews() {
901 if (views_to_dispose_.empty()) {
905 FML_DCHECK([[NSThread currentThread] isMainThread]);
907 std::unordered_set<int64_t> views_to_composite(composition_order_.begin(),
908 composition_order_.end());
909 std::unordered_set<int64_t> views_to_delay_dispose;
910 for (int64_t viewId : views_to_dispose_) {
911 if (views_to_composite.count(viewId)) {
912 views_to_delay_dispose.insert(viewId);
915 UIView* root_view = root_views_[viewId].get();
916 [root_view removeFromSuperview];
917 views_.erase(viewId);
918 touch_interceptors_.erase(viewId);
919 root_views_.erase(viewId);
920 current_composition_params_.erase(viewId);
921 clip_count_.erase(viewId);
922 views_to_recomposite_.erase(viewId);
925 views_to_dispose_ = std::move(views_to_delay_dispose);
928 void FlutterPlatformViewsController::BeginCATransaction() {
929 FML_DCHECK([[NSThread currentThread] isMainThread]);
930 FML_DCHECK(!catransaction_added_);
931 [CATransaction begin];
932 catransaction_added_ =
true;
935 void FlutterPlatformViewsController::CommitCATransactionIfNeeded() {
936 if (catransaction_added_) {
937 FML_DCHECK([[NSThread currentThread] isMainThread]);
938 [CATransaction commit];
939 catransaction_added_ =
false;
943 void FlutterPlatformViewsController::ResetFrameState() {
945 composition_order_.clear();
946 visited_platform_views_.clear();
967 - (instancetype)initWithTarget:(
id)target
969 forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer;
983 - (instancetype)initWithTarget:(
id)target
984 platformViewsController:
985 (fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController;
989 fml::scoped_nsobject<DelayingGestureRecognizer> _delayingRecognizer;
997 - (instancetype)initWithEmbeddedView:(UIView*)embeddedView
998 platformViewsController:
999 (fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController
1000 gestureRecognizersBlockingPolicy:
1002 self = [
super initWithFrame:embeddedView.frame];
1004 self.multipleTouchEnabled = YES;
1006 embeddedView.autoresizingMask =
1007 (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
1009 [
self addSubview:embeddedView];
1013 platformViewsController:std::move(platformViewsController)] autorelease];
1018 forwardingRecognizer:forwardingRecognizer]);
1021 [
self addGestureRecognizer:_delayingRecognizer.get()];
1022 [
self addGestureRecognizer:forwardingRecognizer];
1027 - (UIView*)embeddedView {
1028 return [[_embeddedView retain] autorelease];
1031 - (void)releaseGesture {
1032 _delayingRecognizer.get().state = UIGestureRecognizerStateFailed;
1035 - (void)blockGesture {
1039 _delayingRecognizer.get().state = UIGestureRecognizerStateEnded;
1042 if (_delayingRecognizer.get().touchedEndedWithoutBlocking) {
1046 _delayingRecognizer.get().state = UIGestureRecognizerStateEnded;
1051 _delayingRecognizer.get().shouldEndInNextTouchesEnded = YES;
1062 - (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1065 - (void)touchesMoved:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1068 - (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1071 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
1074 - (void)setFlutterAccessibilityContainer:(NSObject*)flutterAccessibilityContainer {
1078 - (id)accessibilityContainer {
1085 fml::scoped_nsobject<UIGestureRecognizer> _forwardingRecognizer;
1088 - (instancetype)initWithTarget:(
id)target
1090 forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer {
1091 self = [
super initWithTarget:target action:action];
1093 self.delaysTouchesBegan = YES;
1094 self.delaysTouchesEnded = YES;
1095 self.delegate =
self;
1097 self.touchedEndedWithoutBlocking = NO;
1098 _forwardingRecognizer.reset([forwardingRecognizer retain]);
1103 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1104 shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
1107 return otherGestureRecognizer != _forwardingRecognizer.get() && otherGestureRecognizer !=
self;
1110 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1111 shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
1112 return otherGestureRecognizer ==
self;
1115 - (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1116 self.touchedEndedWithoutBlocking = NO;
1117 [
super touchesBegan:touches withEvent:event];
1120 - (void)touchesEnded:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event {
1121 if (
self.shouldEndInNextTouchesEnded) {
1122 self.state = UIGestureRecognizerStateEnded;
1123 self.shouldEndInNextTouchesEnded = NO;
1125 self.touchedEndedWithoutBlocking = YES;
1127 [
super touchesEnded:touches withEvent:event];
1130 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
1131 self.state = UIGestureRecognizerStateFailed;
1153 - (instancetype)initWithTarget:(
id)target
1154 platformViewsController:
1155 (fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController {
1156 self = [
super initWithTarget:target action:nil];
1158 self.delegate =
self;
1159 FML_DCHECK(platformViewsController.get() !=
nullptr);
1166 - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
1174 [_flutterViewController.get() touchesBegan:touches withEvent:event];
1178 - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
1179 [_flutterViewController.get() touchesMoved:touches withEvent:event];
1182 - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
1183 [_flutterViewController.get() touchesEnded:touches withEvent:event];
1190 self.state = UIGestureRecognizerStateFailed;
1195 - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
1204 self.state = UIGestureRecognizerStateFailed;
1209 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1210 shouldRecognizeSimultaneouslyWithGestureRecognizer:
1211 (UIGestureRecognizer*)otherGestureRecognizer {