| Flutter iOS Embedder |

Instance Methods | List of all members
flutter::FlutterPlatformViewsController Class Reference

`#import <FlutterPlatformViews_Internal.h>`

## Instance Methods
() | - FlutterPlatformViewsController
() | - ~FlutterPlatformViewsController
(fml::WeakPtr< flutter::FlutterPlatformViewsController >) | - GetWeakPtr
(void) | - SetFlutterView
(void) | - SetFlutterViewController
(UIViewController *) | - getFlutterViewController
(void) | - RegisterViewFactory
(void) | - BeginFrame
(void) | - CancelFrame
(void) | - PrerollCompositeEmbeddedView
(size_t) | - EmbeddedViewCount
(UIView *) | - GetPlatformViewByID
(FlutterTouchInterceptingView *) | - GetFlutterTouchInterceptingViewByID
(PostPrerollResult) | - PostPrerollAction
(void) | - EndFrame
(DlCanvas *) | - CompositeEmbeddedView
(SkRect) | - GetPlatformViewRect
(void) | - Reset
(bool) | - SubmitFrame
(void) | - OnMethodCall
(long) | - FindFirstResponderPlatformViewId
(void) | - PushFilterToVisitedPlatformViews
(void) | - PushVisitedPlatformView

## Detailed Description

Definition at line 203 of file FlutterPlatformViews_Internal.h.

## Constructor & Destructor Documentation

## ◆ FlutterPlatformViewsController

- FlutterPlatformViewsController: |  |  |

Definition at line 28 of file FlutterPlatformViews_Internal.mm.

29 : layer_pool_(std::make_unique<FlutterPlatformViewLayerPool>()),
30 weak_factory_(std::make_unique<fml::WeakPtrFactory<FlutterPlatformViewsController>>(this)) {
31 mask_view_pool_.reset(
32 [[FlutterClippingMaskViewPool alloc] initWithCapacity:kFlutterClippingMaskViewPoolCapacity]);
33 };

References kFlutterClippingMaskViewPoolCapacity.

## ◆ ~FlutterPlatformViewsController

- FlutterPlatformViewsController: |  |  |

## Method Documentation

## ◆ BeginFrame

- (void) FlutterPlatformViewsController: |  | (SkISize) | frame_size |

Definition at line 323 of file FlutterPlatformViews.mm.

323 {
324 ResetFrameState();
325 frame_size_ = frame_size;
326 }

## ◆ CancelFrame

- (void) FlutterPlatformViewsController: |  |  |

Definition at line 328 of file FlutterPlatformViews.mm.

328 {
329 ResetFrameState();
330 }

## ◆ CompositeEmbeddedView

- (DlCanvas *) FlutterPlatformViewsController: |  | (int64_t) | view_id |

Definition at line 628 of file FlutterPlatformViews.mm.

628 {
629 // Any UIKit related code has to run on main thread.
630 FML_DCHECK([[NSThread currentThread] isMainThread]);
631 // Do nothing if the view doesn't need to be composited.
632 if (views_to_recomposite_.count(view_id) == 0) {
633 return slices_[view_id]->canvas();
634 }
635 CompositeWithParams(view_id, current_composition_params_[view_id]);
636 views_to_recomposite_.erase(view_id);
637 return slices_[view_id]->canvas();
638 }

## ◆ EmbeddedViewCount

- (size_t) FlutterPlatformViewsController: |  |  |

Definition at line 410 of file FlutterPlatformViews.mm.

410 {
411 return composition_order_.size();
412 }

## ◆ EndFrame

- (void) FlutterPlatformViewsController: |  | (bool) | should_resubmit_frame
|  | (const fml::RefPtr< fml::RasterThreadMerger > &) | raster_thread_merger

Definition at line 369 of file FlutterPlatformViews.mm.

371 {
372 if (should_resubmit_frame) {
373 raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
374 }
375 }

## ◆ FindFirstResponderPlatformViewId

- (long) FlutterPlatformViewsController: |  |  |

Definition at line 426 of file FlutterPlatformViews.mm.

426 {
427 for (auto const& [id, root_view] : root_views_) {
428 if ((UIView*)(root_view.get()).flt_hasFirstResponderInViewHierarchySubtree) {
429 return id;
430 }
431 }
432 return -1;
433 }

## ◆ GetFlutterTouchInterceptingViewByID

- (FlutterTouchInterceptingView *) FlutterPlatformViewsController: |  | (int64_t) | view_id |

Definition at line 418 of file FlutterPlatformViews.mm.

419 {
420 if (views_.empty()) {
421 return nil;
422 }
423 return touch_interceptors_[view_id].get();
424 }

Referenced by GetPlatformViewByID.

## ◆ getFlutterViewController

- (UIViewController *) FlutterPlatformViewsController: |  |  |

Definition at line 178 of file FlutterPlatformViews.mm.

178 {
179 return flutter_view_controller_.get();
180 }

## ◆ GetPlatformViewByID

- (UIView *) FlutterPlatformViewsController: |  | (int64_t) | view_id |

Definition at line 414 of file FlutterPlatformViews.mm.

414 {
415 return [GetFlutterTouchInterceptingViewByID(view_id) embeddedView];
416 }

References FlutterTouchInterceptingView::embeddedView, and GetFlutterTouchInterceptingViewByID.

## ◆ GetPlatformViewRect

- (SkRect) FlutterPlatformViewsController: |  | (int64_t) | view_id |

Definition at line 658 of file FlutterPlatformViews.mm.

658 {
659 UIView* platform_view = GetPlatformViewByID(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 //
667 );
668 }

References platform_view.

## ◆ GetWeakPtr

- (WeakPtr<) flutter: |  |  |

Definition at line 37 of file FlutterPlatformViews_Internal.mm.

37 {
38 return weak_factory_->GetWeakPtr();
39 }

## ◆ OnMethodCall

- (void) FlutterPlatformViewsController: |  | (FlutterMethodCall *) | call
|  | (FlutterResult) | result

Definition at line 182 of file FlutterPlatformViews.mm.

182 {
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);
191 } else {
192 result(FlutterMethodNotImplemented);
193 }
194 }

References FlutterMethodNotImplemented.

## ◆ PostPrerollAction

- (PostPrerollResult) FlutterPlatformViewsController: |  | (const fml::RefPtr< fml::RasterThreadMerger > &) | raster_thread_merger |

Definition at line 341 of file FlutterPlatformViews.mm.

342 {
343 // TODO(cyanglaz): https://github.com/flutter/flutter/issues/56474
344 // Rename `has_platform_view` to `view_mutated` when the above issue is resolved.
345 if (!HasPlatformViewThisOrNextFrame()) {
346 return PostPrerollResult::kSuccess;
347 }
348 if (!raster_thread_merger->IsMerged()) {
349 // The raster thread merger may be disabled if the rasterizer is being
350 // created or teared down.
351 //
352 // In such cases, the current frame is dropped, and a new frame is attempted
353 // with the same layer tree.
354 //
355 // Eventually, the frame is submitted once this method returns `kSuccess`.
356 // At that point, the raster tasks are handled on the platform thread.
357 CancelFrame();
358 return PostPrerollResult::kSkipAndRetryFrame;
359 }
360 // If the post preroll action is successful, we will display platform views in the current frame.
361 // In order to sync the rendering of the platform views (quartz) with skia's rendering,
362 // We need to begin an explicit CATransaction. This transaction needs to be submitted
363 // after the current frame is submitted.
364 BeginCATransaction();
365 raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration);
366 return PostPrerollResult::kSuccess;
367 }

## ◆ PrerollCompositeEmbeddedView

- (void) FlutterPlatformViewsController: |  | (int64_t) | view_id
|  | (std::unique_ptr< flutter::EmbeddedViewParams >) | params

Definition at line 387 of file FlutterPlatformViews.mm.

389 {
390 // All the CATransactions should be committed by the end of the last frame,
391 // so catransaction_added_ must be false.
392 FML_DCHECK(!catransaction_added_);
393
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));
398
399 composition_order_.push_back(view_id);
400
401 if (current_composition_params_.count(view_id) == 1 &&
402 current_composition_params_[view_id] == *params.get()) {
403 // Do nothing if the params didn't change.
404 return;
405 }
406 current_composition_params_[view_id] = EmbeddedViewParams(*params.get());
407 views_to_recomposite_.insert(view_id);
408 }

## ◆ PushFilterToVisitedPlatformViews

- (void) FlutterPlatformViewsController: |  | (const std::shared_ptr< const DlImageFilter > &) | filter
|  | (const SkRect &) | filter_rect

Definition at line 377 of file FlutterPlatformViews.mm.

379 {
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;
384 }
385 }

## ◆ PushVisitedPlatformView

- (void) FlutterPlatformViewsController: |  | (int64_t) | view_id |

Definition at line 278 of file FlutterPlatformViews_Internal.h.

278 { visited_platform_views_.push_back(view_id); }

## ◆ RegisterViewFactory

- (void) FlutterPlatformViewsController: |  | (NSObject< FlutterPlatformViewFactory > *) | factory
|  | (NSString *) | factoryId
|  | (FlutterPlatformViewGestureRecognizersBlockingPolicy) | gestureRecognizerBlockingPolicy

Definition at line 312 of file FlutterPlatformViews.mm.

315 {
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;
321 }

## ◆ Reset

- (void) FlutterPlatformViewsController: |  |  |

Definition at line 640 of file FlutterPlatformViews.mm.

640 {
641 for (int64_t view_id : active_composition_order_) {
642 UIView* sub_view = root_views_[view_id].get();
643 [sub_view removeFromSuperview];
644 }
645 root_views_.clear();
646 touch_interceptors_.clear();
647 views_.clear();
648 composition_order_.clear();
649 active_composition_order_.clear();
650 slices_.clear();
651 current_composition_params_.clear();
652 clip_count_.clear();
653 views_to_recomposite_.clear();
654 layer_pool_->RecycleLayers();
655 visited_platform_views_.clear();
656 }

## ◆ SetFlutterView

- (void) FlutterPlatformViewsController: |  | (UIView *) | flutter_view |

Definition at line 169 of file FlutterPlatformViews.mm.

169 {
170 flutter_view_.reset([flutter_view retain]);
171 }

## ◆ SetFlutterViewController

- (void) FlutterPlatformViewsController: |  | (UIViewController *) | flutter_view_controller |

Definition at line 173 of file FlutterPlatformViews.mm.

174 {
175 flutter_view_controller_.reset([flutter_view_controller retain]);
176 }

## ◆ SubmitFrame

- (bool) FlutterPlatformViewsController: |  | (GrDirectContext *) | gr_context
|  | (const std::shared_ptr< IOSContext > &) | ios_context
|  | (std::unique_ptr< SurfaceFrame >) | frame

Definition at line 670 of file FlutterPlatformViews.mm.

672 {
673 TRACE_EVENT0("flutter", "FlutterPlatformViewsController::SubmitFrame");
674
675 // Any UIKit related code has to run on main thread.
676 FML_DCHECK([[NSThread currentThread] isMainThread]);
677 if (flutter_view_ == nullptr) {
678 return frame->Submit();
679 }
680
681 DisposeViews();
682
683 DlCanvas* background_canvas = frame->Canvas();
684
685 // Resolve all pending GPU operations before allocating a new surface.
686 background_canvas->Flush();
687
688 // Clipping the background canvas before drawing the picture recorders requires
689 // saving and restoring the clip context.
690 DlAutoCanvasRestore save(background_canvas, /*do_save=*/true);
691
692 // Maps a platform view id to a vector of `FlutterPlatformViewLayer`.
693 LayersMap platform_view_layers;
694
695 auto did_submit = true;
696 auto num_platform_views = composition_order_.size();
697
698 // TODO(hellohuanlin) this double for-loop is expensive with wasted computations.
699 // See: https://github.com/flutter/flutter/issues/145802
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();
704
705 // Check if the current picture contains overlays that intersect with the
706 // current platform view or any of the previous platform views.
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();
712 // Ignore intersections of single width/height on the edge of the platform view.
713 // This is to address the following performance issue when interleaving adjacent
714 // platform views and layers:
715 // Since we `roundOut` both platform view rects and the layer rects, as long as
716 // the coordinate is fractional, there will be an intersection of a single pixel width
717 // (or height) after rounding out, even if they do not intersect before rounding out.
718 // We have to round out both platform view rect and the layer rect.
719 // Rounding in platform view rect will result in missing pixel on the intersection edge.
720 // Rounding in layer rect will result in missing pixel on the edge of the layer on top
721 // of the platform view.
722 for (auto it = intersection_rects.begin(); it != intersection_rects.end(); /*no-op*/) {
723 // If intersection_rect does not intersect with the *rounded in* platform
724 // view rect, then the intersection must be a single pixel width (or height) on edge.
725 if (!SkIRect::Intersects(*it, rounded_in_platform_view_rect)) {
726 it = intersection_rects.erase(it);
727 } else {
728 ++it;
729 }
730 }
731
732 auto allocation_size = intersection_rects.size();
733
734 // For testing purposes, the overlay id is used to find the overlay view.
735 // This is the index of the layer for the current platform view.
736 auto overlay_id = platform_view_layers[current_platform_view_id].size();
737
738 // If the max number of allocations per platform view is exceeded,
739 // then join all the rects into a single one.
740 //
741 // TODO(egarciad): Consider making this configurable.
742 // https://github.com/flutter/flutter/issues/52510
743 if (allocation_size > kMaxLayerAllocations) {
744 SkIRect joined_rect = SkIRect::MakeEmpty();
745 for (const SkIRect& rect : intersection_rects) {
746 joined_rect.join(rect);
747 }
748 // Replace the rects in the intersection rects list for a single rect that is
749 // the union of all the rects in the list.
750 intersection_rects.clear();
751 intersection_rects.push_back(joined_rect);
752 }
753 for (SkIRect& joined_rect : intersection_rects) {
754 // Get the intersection rect between the current rect
755 // and the platform view rect.
756 joined_rect.intersect(platform_view_rect.roundOut());
757 // Clip the background canvas, so it doesn't contain any of the pixels drawn
758 // on the overlay layer.
759 background_canvas->ClipRect(SkRect::Make(joined_rect), DlCanvas::ClipOp::kDifference);
760 // Get a new host layer.
761 std::shared_ptr<FlutterPlatformViewLayer> layer =
762 GetLayer(gr_context, //
763 ios_context, //
764 slice, //
765 joined_rect, //
766 current_platform_view_id, //
767 overlay_id, //
768 ((FlutterView*)flutter_view_.get()).pixelFormat //
769 );
770 did_submit &= layer->did_submit_last_frame;
771 platform_view_layers[current_platform_view_id].push_back(layer);
772 overlay_id++;
773 }
774 }
775 slice->render_into(background_canvas);
776 }
777
778 // Manually trigger the SkAutoCanvasRestore before we submit the frame
779 save.Restore();
780
781 // If a layer was allocated in the previous frame, but it's not used in the current frame,
782 // then it can be removed from the scene.
783 RemoveUnusedLayers();
784 // Organize the layers by their z indexes.
785 BringLayersIntoView(platform_view_layers);
786 // Mark all layers as available, so they can be used in the next frame.
787 layer_pool_->RecycleLayers();
788
789 did_submit &= frame->Submit();
790
791 // If the frame is submitted with embedded platform views,
792 // there should be a |[CATransaction begin]| call in this frame prior to all the drawing.
793 // If that case, we need to commit the transaction.
794 CommitCATransactionIfNeeded();
795 return did_submit;
796 }

The documentation for this class was generated from the following files:

- shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h
- shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
- shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm

-[flutter::FlutterPlatformViewsController GetPlatformViewByID]
UIView * GetPlatformViewByID(int64_t view_id)
Definition: FlutterPlatformViews.mm:414
FlutterMethodNotImplemented
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
-[flutter::FlutterPlatformViewsController GetPlatformViewRect]
SkRect GetPlatformViewRect(int64_t view_id)
Definition: FlutterPlatformViews.mm:658
platform_view
std::unique_ptr< flutter::PlatformViewIOS > platform_view
Definition: FlutterEnginePlatformViewTest.mm:61
kFlutterClippingMaskViewPoolCapacity
static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity
Definition: FlutterPlatformViews_Internal.mm:12
FlutterClippingMaskViewPool
Definition: FlutterPlatformViews_Internal.h:60
FlutterView
Definition: FlutterView.h:39
-[flutter::FlutterPlatformViewsController CancelFrame]
void CancelFrame()
Definition: FlutterPlatformViews.mm:328