5#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
7#include <Metal/Metal.h>
9#include "flutter/fml/platform/darwin/scoped_nsobject.h"
10#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h"
11#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
12#import "flutter/shell/platform/darwin/ios/ios_surface.h"
14@implementation UIView (FirstResponder)
16 if (
self.isFirstResponder) {
19 for (UIView* subview in
self.subviews) {
20 if (subview.flt_hasFirstResponderInViewHierarchySubtree) {
37 const SkRect& platformview_boundingrect,
39 SkRect transformed_rect = transform_matrix.
mapRect(clip_rect);
40 return transformed_rect.
contains(platformview_boundingrect);
52 const SkRect& platformview_boundingrect,
68 SkVector corners[] = {{transformed_upper_left_x, transformed_upper_left_y},
69 {transformed_upper_right_x, transformed_upper_right_y},
70 {transformed_lower_right_x, transformed_lower_right_y},
71 {transformed_lower_left_x, transformed_lower_left_y}};
72 transformed_rrect.
setRectRadii(transformed_clip_rect, corners);
73 return transformed_rrect.
contains(platformview_boundingrect);
80std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewLayerPool::GetLayer(
82 const std::shared_ptr<IOSContext>& ios_context,
83 MTLPixelFormat pixel_format) {
84 if (available_layer_index_ >= layers_.size()) {
85 std::shared_ptr<FlutterPlatformViewLayer> layer;
89 bool impeller_enabled = !!ios_context->GetImpellerContext();
90 if (!gr_context && !impeller_enabled) {
95 std::unique_ptr<IOSSurface> ios_surface = IOSSurface::Create(ios_context, ca_layer);
96 std::unique_ptr<Surface>
surface = ios_surface->CreateGPUSurface();
98 layer = std::make_shared<FlutterPlatformViewLayer>(
99 std::move(overlay_view), std::move(overlay_view_wrapper), std::move(ios_surface),
102 CGFloat screenScale = [UIScreen mainScreen].scale;
104 pixelFormat:pixel_format]);
106 pixelFormat:pixel_format]);
109 std::unique_ptr<IOSSurface> ios_surface = IOSSurface::Create(ios_context, ca_layer);
110 std::unique_ptr<Surface>
surface = ios_surface->CreateGPUSurface(gr_context);
112 layer = std::make_shared<FlutterPlatformViewLayer>(
113 std::move(overlay_view), std::move(overlay_view_wrapper), std::move(ios_surface),
115 layer->gr_context = gr_context;
131 layer->overlay_view_wrapper.get().clipsToBounds = YES;
132 [layer->overlay_view_wrapper.get() addSubview:layer->overlay_view];
133 layers_.push_back(layer);
135 std::shared_ptr<FlutterPlatformViewLayer> layer = layers_[available_layer_index_];
136 if (gr_context != layer->gr_context) {
137 layer->gr_context = gr_context;
140 IOSSurface* ios_surface = layer->ios_surface.get();
142 layer->surface = std::move(
surface);
144 available_layer_index_++;
148void FlutterPlatformViewLayerPool::RecycleLayers() {
149 available_layer_index_ = 0;
152std::vector<std::shared_ptr<FlutterPlatformViewLayer>>
153FlutterPlatformViewLayerPool::GetUnusedLayers() {
154 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> results;
155 for (
size_t i = available_layer_index_; i < layers_.size(); i++) {
156 results.push_back(layers_[i]);
161void FlutterPlatformViewsController::SetFlutterView(UIView* flutter_view) {
162 flutter_view_.reset([flutter_view retain]);
165void FlutterPlatformViewsController::SetFlutterViewController(
166 UIViewController<FlutterViewResponder>* flutter_view_controller) {
167 flutter_view_controller_.reset([flutter_view_controller retain]);
170UIViewController<FlutterViewResponder>* FlutterPlatformViewsController::getFlutterViewController() {
171 return flutter_view_controller_.get();
175 if ([[call method] isEqualToString:
@"create"]) {
177 }
else if ([[call method] isEqualToString:
@"dispose"]) {
179 }
else if ([[call method] isEqualToString:
@"acceptGesture"]) {
180 OnAcceptGesture(call,
result);
181 }
else if ([[call method] isEqualToString:
@"rejectGesture"]) {
182 OnRejectGesture(call,
result);
191 int64_t viewId = [args[@"id"] longLongValue];
192 NSString* viewTypeString =
args[@"viewType"];
193 std::string viewType(viewTypeString.UTF8String);
195 if (views_.count(viewId) != 0) {
197 message:
@"trying to create an already created view"
198 details:[NSString stringWithFormat:
@"view id: '%lld'", viewId]]);
201 NSObject<FlutterPlatformViewFactory>* factory = factories_[viewType].get();
202 if (factory == nil) {
204 errorWithCode:
@"unregistered_view_type"
205 message:[NSString stringWithFormat:
@"A UIKitView widget is trying to create a "
206 @"PlatformView with an unregistered type: < %@ >",
208 details:
@"If you are the author of the PlatformView, make sure `registerViewFactory` "
211 @"https://docs.flutter.dev/development/platform-integration/"
212 @"platform-views#on-the-platform-side-1 for more details.\n"
213 @"If you are not the author of the PlatformView, make sure to call "
214 @"`GeneratedPluginRegistrant.register`."]);
219 if ([factory respondsToSelector:@selector(createArgsCodec)]) {
220 NSObject<FlutterMessageCodec>* codec = [factory createArgsCodec];
221 if (codec != nil &&
args[
@"params"] != nil) {
223 params = [codec decode:paramsData.data];
227 NSObject<FlutterPlatformView>* embedded_view = [factory createWithFrame:CGRectZero
228 viewIdentifier:viewId
233 [NSString stringWithFormat:@"platform_view[%lld]", viewId];
237 initWithEmbeddedView:platform_view
238 platformViewsController:GetWeakPtr()
239 gestureRecognizersBlockingPolicy:gesture_recognizers_blocking_policies_[viewType]]
242 touch_interceptors_[viewId] =
247 [clipping_view addSubview:touch_interceptor];
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);
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]]);
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]]);
304void FlutterPlatformViewsController::RegisterViewFactory(
305 NSObject<FlutterPlatformViewFactory>* factory,
308 std::string idString([factoryId UTF8String]);
309 FML_CHECK(factories_.count(idString) == 0);
310 factories_[idString] =
312 gesture_recognizers_blocking_policies_[idString] = gestureRecognizerBlockingPolicy;
315void FlutterPlatformViewsController::BeginFrame(
SkISize frame_size) {
317 frame_size_ = frame_size;
320void FlutterPlatformViewsController::CancelFrame() {
327bool FlutterPlatformViewsController::HasPlatformViewThisOrNextFrame() {
328 return !composition_order_.empty() || !active_composition_order_.empty();
331const int FlutterPlatformViewsController::kDefaultMergedLeaseDuration;
337 if (!HasPlatformViewThisOrNextFrame()) {
338 return PostPrerollResult::kSuccess;
340 if (!raster_thread_merger->IsMerged()) {
350 return PostPrerollResult::kSkipAndRetryFrame;
356 BeginCATransaction();
357 raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration);
358 return PostPrerollResult::kSuccess;
361void FlutterPlatformViewsController::EndFrame(
362 bool should_resubmit_frame,
364 if (should_resubmit_frame) {
365 raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
369void FlutterPlatformViewsController::PushFilterToVisitedPlatformViews(
370 const std::shared_ptr<const DlImageFilter>& filter,
371 const SkRect& filter_rect) {
372 for (int64_t
id : visited_platform_views_) {
375 current_composition_params_[id] =
params;
379void FlutterPlatformViewsController::PrerollCompositeEmbeddedView(
381 std::unique_ptr<EmbeddedViewParams>
params) {
387 std::unique_ptr<EmbedderViewSlice> view;
388 view = std::make_unique<DisplayListEmbedderViewSlice>(view_bounds);
389 slices_.insert_or_assign(view_id, std::move(view));
391 composition_order_.push_back(view_id);
393 if (current_composition_params_.count(view_id) == 1 &&
394 current_composition_params_[view_id] == *
params.get()) {
399 views_to_recomposite_.insert(view_id);
402size_t FlutterPlatformViewsController::EmbeddedViewCount() {
403 return composition_order_.size();
406UIView* FlutterPlatformViewsController::GetPlatformViewByID(int64_t view_id) {
412 if (views_.empty()) {
415 return touch_interceptors_[view_id].get();
418long FlutterPlatformViewsController::FindFirstResponderPlatformViewId() {
419 for (
auto const& [
id, root_view] : root_views_) {
420 if ((UIView*)(root_view.get()).flt_hasFirstResponderInViewHierarchySubtree) {
427int FlutterPlatformViewsController::CountClips(
const MutatorsStack& mutators_stack) {
428 std::vector<std::shared_ptr<Mutator>>::const_reverse_iterator iter = mutators_stack.
Bottom();
430 while (iter != mutators_stack.
Top()) {
431 if ((*iter)->IsClipType()) {
439void FlutterPlatformViewsController::ClipViewSetMaskView(UIView* clipView) {
440 if (clipView.maskView) {
443 UIView* flutterView = flutter_view_.get();
445 CGRectMake(-clipView.frame.origin.x, -clipView.frame.origin.y,
446 CGRectGetWidth(flutterView.bounds), CGRectGetHeight(flutterView.bounds));
447 clipView.maskView = [mask_view_pool_.get() getMaskViewWithFrame:frame];
452void FlutterPlatformViewsController::ApplyMutators(
const MutatorsStack& mutators_stack,
453 UIView* embedded_view,
454 const SkRect& bounding_rect) {
455 if (flutter_view_ ==
nullptr) {
458 FML_DCHECK(CATransform3DEqualToTransform(embedded_view.layer.transform, CATransform3DIdentity));
463 NSMutableArray* blurFilters = [[[NSMutableArray alloc] init] autorelease];
466 if (clipView.maskView) {
467 [mask_view_pool_.get() insertViewToPoolIfNeeded:(FlutterClippingMaskView*)(clipView.maskView)];
468 clipView.maskView = nil;
470 CGFloat screenScale = [UIScreen mainScreen].scale;
471 auto iter = mutators_stack.Begin();
472 while (iter != mutators_stack.End()) {
473 switch ((*iter)->GetType()) {
475 transformMatrix.
preConcat((*iter)->GetMatrix());
483 ClipViewSetMaskView(clipView);
485 matrix:transformMatrix];
493 ClipViewSetMaskView(clipView);
495 matrix:transformMatrix];
502 ClipViewSetMaskView(clipView);
504 matrix:transformMatrix];
508 embedded_view.alpha = (*iter)->GetAlphaFloat() * embedded_view.alpha;
512 if (!canApplyBlurBackdrop || !(*iter)->GetFilterMutation().GetFilter().asBlur()) {
518 filterRect = CGRectApplyAffineTransform(
519 filterRect, CGAffineTransformMakeScale(1 / screenScale, 1 / screenScale));
523 if (CGRectIsNull(CGRectIntersection(filterRect, clipView.frame))) {
526 CGRect intersection = CGRectIntersection(filterRect, clipView.frame);
527 CGRect frameInClipView = [flutter_view_.get() convertRect:intersection toView:clipView];
532 CGFloat blurRadius = (*iter)->GetFilterMutation().GetFilter().asBlur()->sigma_x();
533 UIVisualEffectView* visualEffectView = [[[UIVisualEffectView alloc]
534 initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]] autorelease];
537 blurRadius:blurRadius
538 visualEffectView:visualEffectView] autorelease];
542 [blurFilters addObject:filter];
550 if (canApplyBlurBackdrop) {
551 [clipView applyBlurBackdropFilters:blurFilters];
559 transformMatrix.
postScale(1 / screenScale, 1 / screenScale);
568 transformMatrix.
postTranslate(-clipView.frame.origin.x, -clipView.frame.origin.y);
581void FlutterPlatformViewsController::CompositeWithParams(int64_t view_id,
582 const EmbeddedViewParams&
params) {
583 CGRect
frame = CGRectMake(0, 0,
params.sizePoints().width(),
params.sizePoints().height());
585#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
586 FML_DCHECK(CGPointEqualToPoint([touchInterceptor embeddedView].
frame.origin, CGPointZero));
587 if (non_zero_origin_views_.find(view_id) == non_zero_origin_views_.end() &&
588 !CGPointEqualToPoint([touchInterceptor embeddedView].
frame.origin, CGPointZero)) {
589 non_zero_origin_views_.insert(view_id);
591 @"A Embedded PlatformView's origin is not CGPointZero.\n"
593 " View info: \n %@ \n"
594 "A non-zero origin might cause undefined behavior.\n"
595 "See https://github.com/flutter/flutter/issues/109700 for more details.\n"
596 "If you are the author of the PlatformView, please update the implementation of the "
597 "PlatformView to have a (0, 0) origin.\n"
598 "If you have a valid case of using a non-zero origin, "
599 "please leave a comment at https://github.com/flutter/flutter/issues/109700 with details.",
600 @(view_id), [touchInterceptor embeddedView]);
603 touchInterceptor.layer.transform = CATransform3DIdentity;
604 touchInterceptor.frame =
frame;
605 touchInterceptor.alpha = 1;
607 const MutatorsStack& mutatorStack =
params.mutatorsStack();
608 UIView* clippingView = root_views_[view_id].get();
614 CGFloat screenScale = [UIScreen mainScreen].scale;
615 clippingView.frame = CGRectMake(
rect.x() / screenScale,
rect.y() / screenScale,
616 rect.width() / screenScale,
rect.height() / screenScale);
617 ApplyMutators(mutatorStack, touchInterceptor, rect);
620DlCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(int64_t view_id) {
622 FML_DCHECK([[NSThread currentThread] isMainThread]);
624 if (views_to_recomposite_.count(view_id) == 0) {
625 return slices_[view_id]->canvas();
627 CompositeWithParams(view_id, current_composition_params_[view_id]);
628 views_to_recomposite_.erase(view_id);
629 return slices_[view_id]->canvas();
632void FlutterPlatformViewsController::Reset() {
633 for (int64_t view_id : active_composition_order_) {
634 UIView* sub_view = root_views_[view_id].get();
635 [sub_view removeFromSuperview];
638 touch_interceptors_.clear();
640 composition_order_.clear();
641 active_composition_order_.clear();
643 current_composition_params_.clear();
645 views_to_recomposite_.clear();
646 layer_pool_->RecycleLayers();
647 visited_platform_views_.clear();
650SkRect FlutterPlatformViewsController::GetPlatformViewRect(int64_t view_id) {
652 UIScreen* screen = [UIScreen mainScreen];
653 CGRect platform_view_cgrect = [platform_view convertRect:platform_view.bounds
654 toView:flutter_view_];
656 platform_view_cgrect.origin.y * screen.scale,
657 platform_view_cgrect.size.width * screen.scale,
658 platform_view_cgrect.size.height * screen.scale
663 const std::shared_ptr<IOSContext>& ios_context,
664 std::unique_ptr<SurfaceFrame>
frame) {
665 TRACE_EVENT0(
"flutter",
"FlutterPlatformViewsController::SubmitFrame");
668 FML_DCHECK([[NSThread currentThread] isMainThread]);
669 if (flutter_view_ ==
nullptr) {
670 return frame->Submit();
678 background_canvas->
Flush();
685 LayersMap platform_view_layers;
687 auto did_submit =
true;
688 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];
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::vector<SkIRect> intersection_rects = slice->
region(platform_view_rect).
getRects();
703 const SkIRect rounded_in_platform_view_rect = platform_view_rect.
roundIn();
714 for (
auto it = intersection_rects.begin(); it != intersection_rects.end(); ) {
718 it = intersection_rects.erase(it);
724 auto allocation_size = intersection_rects.size();
728 auto overlay_id = platform_view_layers[current_platform_view_id].size();
735 if (allocation_size > kMaxLayerAllocations) {
737 for (
const SkIRect& rect : intersection_rects) {
738 joined_rect.
join(rect);
742 intersection_rects.clear();
743 intersection_rects.push_back(joined_rect);
745 for (
SkIRect& joined_rect : intersection_rects) {
748 joined_rect.intersect(platform_view_rect.
roundOut());
753 std::shared_ptr<FlutterPlatformViewLayer> layer =
758 current_platform_view_id,
762 did_submit &= layer->did_submit_last_frame;
763 platform_view_layers[current_platform_view_id].push_back(layer);
775 RemoveUnusedLayers();
777 BringLayersIntoView(platform_view_layers);
779 layer_pool_->RecycleLayers();
781 did_submit &=
frame->Submit();
786 CommitCATransactionIfNeeded();
790void FlutterPlatformViewsController::BringLayersIntoView(LayersMap layer_map) {
792 UIView* flutter_view = flutter_view_.get();
794 active_composition_order_.clear();
795 NSMutableArray* desired_platform_subviews = [NSMutableArray array];
796 for (
size_t i = 0; i < composition_order_.size(); i++) {
797 int64_t platform_view_id = composition_order_[i];
798 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_map[platform_view_id];
799 UIView* platform_view_root = root_views_[platform_view_id].get();
800 [desired_platform_subviews addObject:platform_view_root];
801 for (
const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
802 [desired_platform_subviews addObject:layer->overlay_view_wrapper];
804 active_composition_order_.push_back(platform_view_id);
807 NSSet* desired_platform_subviews_set = [NSSet setWithArray:desired_platform_subviews];
808 NSArray* existing_platform_subviews = [flutter_view.subviews
809 filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object,
810 NSDictionary* bindings) {
811 return [desired_platform_subviews_set containsObject:object];
817 if (![desired_platform_subviews isEqualToArray:existing_platform_subviews]) {
818 for (UIView* subview in desired_platform_subviews) {
820 [flutter_view addSubview:subview];
825std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLayer(
827 const std::shared_ptr<IOSContext>& ios_context,
828 EmbedderViewSlice* slice,
832 MTLPixelFormat pixel_format) {
834 std::shared_ptr<FlutterPlatformViewLayer> layer =
835 layer_pool_->GetLayer(gr_context, ios_context, pixel_format);
837 UIView* overlay_view_wrapper = layer->overlay_view_wrapper.get();
838 auto screenScale = [UIScreen mainScreen].scale;
841 overlay_view_wrapper.frame = CGRectMake(
rect.x() / screenScale,
rect.y() / screenScale,
842 rect.width() / screenScale,
rect.height() / screenScale);
844 overlay_view_wrapper.accessibilityIdentifier =
845 [NSString stringWithFormat:@"platform_view[%lld].overlay[%lld]", view_id, overlay_id];
847 UIView* overlay_view = layer->overlay_view.get();
850 overlay_view.frame = [flutter_view_.get() convertRect:flutter_view_.get().bounds
851 toView:overlay_view_wrapper];
853 overlay_view.accessibilityIdentifier =
854 [NSString stringWithFormat:@"platform_view[%lld].overlay_view[%lld]", view_id, overlay_id];
856 std::unique_ptr<SurfaceFrame>
frame = layer->surface->AcquireFrame(frame_size_);
861 DlCanvas* overlay_canvas =
frame->Canvas();
862 int restore_count = overlay_canvas->GetSaveCount();
863 overlay_canvas->Save();
865 overlay_canvas->Clear(DlColor::kTransparent());
866 slice->render_into(overlay_canvas);
867 overlay_canvas->RestoreToCount(restore_count);
869 layer->did_submit_last_frame =
frame->Submit();
873void FlutterPlatformViewsController::RemoveUnusedLayers() {
874 std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_pool_->GetUnusedLayers();
875 for (
const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
876 [layer->overlay_view_wrapper removeFromSuperview];
879 std::unordered_set<int64_t> composition_order_set;
880 for (int64_t view_id : composition_order_) {
881 composition_order_set.insert(view_id);
884 for (int64_t view_id : active_composition_order_) {
885 if (composition_order_set.find(view_id) == composition_order_set.end()) {
886 UIView* platform_view_root = root_views_[view_id].get();
887 [platform_view_root removeFromSuperview];
892void FlutterPlatformViewsController::DisposeViews() {
893 if (views_to_dispose_.empty()) {
897 FML_DCHECK([[NSThread currentThread] isMainThread]);
899 std::unordered_set<int64_t> views_to_composite(composition_order_.begin(),
900 composition_order_.end());
901 std::unordered_set<int64_t> views_to_delay_dispose;
902 for (int64_t viewId : views_to_dispose_) {
903 if (views_to_composite.count(viewId)) {
904 views_to_delay_dispose.insert(viewId);
907 UIView* root_view = root_views_[viewId].get();
908 [root_view removeFromSuperview];
909 views_.erase(viewId);
910 touch_interceptors_.erase(viewId);
911 root_views_.erase(viewId);
912 current_composition_params_.erase(viewId);
913 clip_count_.erase(viewId);
914 views_to_recomposite_.erase(viewId);
917 views_to_dispose_ = std::move(views_to_delay_dispose);
920void FlutterPlatformViewsController::BeginCATransaction() {
921 FML_DCHECK([[NSThread currentThread] isMainThread]);
923 [CATransaction begin];
924 catransaction_added_ =
true;
927void FlutterPlatformViewsController::CommitCATransactionIfNeeded() {
928 if (catransaction_added_) {
929 FML_DCHECK([[NSThread currentThread] isMainThread]);
930 [CATransaction commit];
931 catransaction_added_ =
false;
935void FlutterPlatformViewsController::ResetFrameState() {
937 composition_order_.clear();
938 visited_platform_views_.clear();
959- (instancetype)initWithTarget:(
id)target
961 forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer;
975- (instancetype)initWithTarget:(
id)target
976 platformViewsController:
977 (
fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController;
989- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
990 platformViewsController:
991 (
fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController
992 gestureRecognizersBlockingPolicy:
994 self = [
super initWithFrame:embeddedView.frame];
996 self.multipleTouchEnabled = YES;
998 embeddedView.autoresizingMask =
999 (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
1001 [
self addSubview:embeddedView];
1005 platformViewsController:std::move(platformViewsController)] autorelease];
1010 forwardingRecognizer:forwardingRecognizer]);
1013 [
self addGestureRecognizer:_delayingRecognizer.get()];
1014 [
self addGestureRecognizer:forwardingRecognizer];
1019- (UIView*)embeddedView {
1020 return [[_embeddedView retain] autorelease];
1023- (void)releaseGesture {
1024 _delayingRecognizer.get().state = UIGestureRecognizerStateFailed;
1027- (void)blockGesture {
1031 _delayingRecognizer.get().state = UIGestureRecognizerStateEnded;
1034 if (_delayingRecognizer.get().touchedEndedWithoutBlocking) {
1038 _delayingRecognizer.get().state = UIGestureRecognizerStateEnded;
1043 _delayingRecognizer.get().shouldEndInNextTouchesEnded = YES;
1054- (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(
UIEvent*)event {
1057- (void)touchesMoved:(NSSet<UITouch*>*)touches withEvent:(
UIEvent*)event {
1060- (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(
UIEvent*)event {
1063- (void)touchesEnded:(NSSet*)touches withEvent:(
UIEvent*)event {
1066- (void)setFlutterAccessibilityContainer:(NSObject*)flutterAccessibilityContainer {
1070- (
id)accessibilityContainer {
1080- (instancetype)initWithTarget:(
id)target
1082 forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer {
1083 self = [
super initWithTarget:target action:action];
1085 self.delaysTouchesBegan = YES;
1086 self.delaysTouchesEnded = YES;
1088 self.shouldEndInNextTouchesEnded = NO;
1089 self.touchedEndedWithoutBlocking = NO;
1090 _forwardingRecognizer.
reset([forwardingRecognizer retain]);
1095- (
BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1096 shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
1099 return otherGestureRecognizer != _forwardingRecognizer.get() && otherGestureRecognizer !=
self;
1102- (
BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1103 shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
1104 return otherGestureRecognizer ==
self;
1107- (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(
UIEvent*)event {
1108 self.touchedEndedWithoutBlocking = NO;
1109 [
super touchesBegan:touches withEvent:event];
1112- (void)touchesEnded:(NSSet<UITouch*>*)touches withEvent:(
UIEvent*)event {
1113 if (
self.shouldEndInNextTouchesEnded) {
1114 self.state = UIGestureRecognizerStateEnded;
1115 self.shouldEndInNextTouchesEnded = NO;
1117 self.touchedEndedWithoutBlocking = YES;
1119 [
super touchesEnded:touches withEvent:event];
1122- (void)touchesCancelled:(NSSet*)touches withEvent:(
UIEvent*)event {
1123 self.state = UIGestureRecognizerStateFailed;
1145- (instancetype)initWithTarget:(
id)target
1146 platformViewsController:
1147 (
fml::WeakPtr<
flutter::FlutterPlatformViewsController>)platformViewsController {
1148 self = [
super initWithTarget:target action:nil];
1151 FML_DCHECK(platformViewsController.get() !=
nullptr);
1158- (void)touchesBegan:(NSSet*)touches withEvent:(
UIEvent*)event {
1166 [_flutterViewController.get() touchesBegan:touches withEvent:event];
1170- (void)touchesMoved:(NSSet*)touches withEvent:(
UIEvent*)event {
1171 [_flutterViewController.get() touchesMoved:touches withEvent:event];
1174- (void)touchesEnded:(NSSet*)touches withEvent:(
UIEvent*)event {
1175 [_flutterViewController.get() touchesEnded:touches withEvent:event];
1182 self.state = UIGestureRecognizerStateFailed;
1187- (void)touchesCancelled:(NSSet*)touches withEvent:(
UIEvent*)event {
1193 [_flutterViewController.get() forceTouchesCancelled:touches];
1196 self.state = UIGestureRecognizerStateFailed;
1201- (
BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
1202 shouldRecognizeSimultaneouslyWithGestureRecognizer:
1203 (UIGestureRecognizer*)otherGestureRecognizer {
void(^ FlutterResult)(id _Nullable result)
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
FlutterPlatformViewGestureRecognizersBlockingPolicy
@ FlutterPlatformViewGestureRecognizersBlockingPolicyEager
@ FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded
BOOL flt_hasFirstResponderInViewHierarchySubtree
SkScalar mapRadius(SkScalar radius) const
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
SkMatrix & postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
SkMatrix & preConcat(const SkMatrix &other)
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
const SkRect & rect() const
SkVector radii(Corner corner) const
@ kUpperLeft_Corner
index of top-left corner radii
@ kLowerRight_Corner
index of bottom-right corner radii
@ kUpperRight_Corner
index of top-right corner radii
@ kLowerLeft_Corner
index of bottom-left corner radii
void setRectRadii(const SkRect &rect, const SkVector radii[4])
bool contains(const SkRect &rect) const
Developer-facing API for rendering anything within the engine.
virtual void ClipRect(const SkRect &rect, ClipOp clip_op=ClipOp::kIntersect, bool is_aa=false)=0
std::vector< SkIRect > getRects(bool deband=true) const
void PushImageFilter(const std::shared_ptr< const DlImageFilter > &filter, const SkRect &filter_rect)
virtual void render_into(DlCanvas *canvas)=0
virtual void end_recording()=0
DlRegion region(const SkRect &query) const
virtual std::unique_ptr< Surface > CreateGPUSurface(GrDirectContext *gr_context=nullptr)=0
void reset(NST *object=Traits::InvalidValue(), scoped_policy::OwnershipPolicy policy=scoped_policy::OwnershipPolicy::kAssume)
const EmbeddedViewParams * params
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static constexpr char kTransform[]
#define FML_CHECK(condition)
#define FML_DCHECK(condition)
bool shouldEndInNextTouchesEnded
bool touchedEndedWithoutBlocking
std::shared_ptr< flutter::FlutterPlatformViewsController > _platformViewsController
sk_sp< SkBlender > blender SkRect rect
BOOL canApplyBlurBackdrop
void ResetAnchor(CALayer *layer)
CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix &matrix)
CGRect GetCGRectFromSkRect(const SkRect &clipSkRect)
static bool Intersects(const SkIRect &a, const SkIRect &b)
void join(const SkIRect &r)
static constexpr SkIRect MakeEmpty()
constexpr float y() const
constexpr float x() const
static SkRect Make(const SkISize &size)
void roundIn(SkIRect *dst) const
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
bool contains(SkScalar x, SkScalar y) const
void roundOut(SkIRect *dst) const
#define TRACE_EVENT0(category_group, name)