Flutter iOS Embedder
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 200 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(
33 };

References kFlutterClippingMaskViewPoolCapacity.

◆ ~FlutterPlatformViewsController

- FlutterPlatformViewsController:

Method Documentation

◆ BeginFrame

- (void) FlutterPlatformViewsController: (SkISize)  frame_size

Definition at line 317 of file FlutterPlatformViews.mm.

317  {
318  ResetFrameState();
319  frame_size_ = frame_size;
320 }

◆ CancelFrame

- (void) FlutterPlatformViewsController:

Definition at line 322 of file FlutterPlatformViews.mm.

322  {
323  ResetFrameState();
324 }

◆ CompositeEmbeddedView

- (DlCanvas *) FlutterPlatformViewsController: (int64_t)  view_id

Definition at line 622 of file FlutterPlatformViews.mm.

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

◆ EmbeddedViewCount

- (size_t) FlutterPlatformViewsController:

Definition at line 404 of file FlutterPlatformViews.mm.

404  {
405  return composition_order_.size();
406 }

◆ EndFrame

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

Definition at line 363 of file FlutterPlatformViews.mm.

365  {
366  if (should_resubmit_frame) {
367  raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
368  }
369 }

◆ FindFirstResponderPlatformViewId

- (long) FlutterPlatformViewsController:

Definition at line 420 of file FlutterPlatformViews.mm.

420  {
421  for (auto const& [id, root_view] : root_views_) {
422  if ((UIView*)(root_view.get()).flt_hasFirstResponderInViewHierarchySubtree) {
423  return id;
424  }
425  }
426  return -1;
427 }

References id.

◆ GetFlutterTouchInterceptingViewByID

- (FlutterTouchInterceptingView *) FlutterPlatformViewsController: (int64_t)  view_id

Definition at line 412 of file FlutterPlatformViews.mm.

413  {
414  if (views_.empty()) {
415  return nil;
416  }
417  return touch_interceptors_[view_id].get();
418 }

Referenced by GetPlatformViewByID.

◆ getFlutterViewController

- (UIViewController *) FlutterPlatformViewsController:

Definition at line 172 of file FlutterPlatformViews.mm.

172  {
173  return flutter_view_controller_.get();
174 }

◆ GetPlatformViewByID

- (UIView *) FlutterPlatformViewsController: (int64_t)  view_id

Definition at line 408 of file FlutterPlatformViews.mm.

408  {
409  return [GetFlutterTouchInterceptingViewByID(view_id) embeddedView];
410 }

References FlutterTouchInterceptingView::embeddedView, and GetFlutterTouchInterceptingViewByID.

◆ GetPlatformViewRect

- (SkRect) FlutterPlatformViewsController: (int64_t)  view_id

Definition at line 652 of file FlutterPlatformViews.mm.

652  {
653  UIView* platform_view = GetPlatformViewByID(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 //
661  );
662 }

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 176 of file FlutterPlatformViews.mm.

176  {
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);
185  } else {
187  }
188 }

References FlutterMethodNotImplemented.

◆ PostPrerollAction

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

Definition at line 335 of file FlutterPlatformViews.mm.

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

◆ PrerollCompositeEmbeddedView

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

Definition at line 381 of file FlutterPlatformViews.mm.

383  {
384  // All the CATransactions should be committed by the end of the last frame,
385  // so catransaction_added_ must be false.
386  FML_DCHECK(!catransaction_added_);
387 
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));
392 
393  composition_order_.push_back(view_id);
394 
395  if (current_composition_params_.count(view_id) == 1 &&
396  current_composition_params_[view_id] == *params.get()) {
397  // Do nothing if the params didn't change.
398  return;
399  }
400  current_composition_params_[view_id] = EmbeddedViewParams(*params.get());
401  views_to_recomposite_.insert(view_id);
402 }

◆ PushFilterToVisitedPlatformViews

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

Definition at line 371 of file FlutterPlatformViews.mm.

373  {
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;
378  }
379 }

◆ PushVisitedPlatformView

- (void) FlutterPlatformViewsController: (int64_t)  view_id

Definition at line 275 of file FlutterPlatformViews_Internal.h.

275 { visited_platform_views_.push_back(view_id); }

◆ RegisterViewFactory

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

Definition at line 306 of file FlutterPlatformViews.mm.

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

◆ Reset

- (void) FlutterPlatformViewsController:

Definition at line 634 of file FlutterPlatformViews.mm.

634  {
635  for (int64_t view_id : active_composition_order_) {
636  UIView* sub_view = root_views_[view_id].get();
637  [sub_view removeFromSuperview];
638  }
639  root_views_.clear();
640  touch_interceptors_.clear();
641  views_.clear();
642  composition_order_.clear();
643  active_composition_order_.clear();
644  slices_.clear();
645  current_composition_params_.clear();
646  clip_count_.clear();
647  views_to_recomposite_.clear();
648  layer_pool_->RecycleLayers();
649  visited_platform_views_.clear();
650 }

◆ SetFlutterView

- (void) FlutterPlatformViewsController: (UIView *)  flutter_view

Definition at line 163 of file FlutterPlatformViews.mm.

163  {
164  flutter_view_.reset([flutter_view retain]);
165 }

◆ SetFlutterViewController

- (void) FlutterPlatformViewsController: (UIViewController *)  flutter_view_controller

Definition at line 167 of file FlutterPlatformViews.mm.

168  {
169  flutter_view_controller_.reset([flutter_view_controller retain]);
170 }

◆ SubmitFrame

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

Definition at line 664 of file FlutterPlatformViews.mm.

666  {
667  TRACE_EVENT0("flutter", "FlutterPlatformViewsController::SubmitFrame");
668 
669  // Any UIKit related code has to run on main thread.
670  FML_DCHECK([[NSThread currentThread] isMainThread]);
671  if (flutter_view_ == nullptr) {
672  return frame->Submit();
673  }
674 
675  DisposeViews();
676 
677  DlCanvas* background_canvas = frame->Canvas();
678 
679  // Resolve all pending GPU operations before allocating a new surface.
680  background_canvas->Flush();
681 
682  // Clipping the background canvas before drawing the picture recorders requires
683  // saving and restoring the clip context.
684  DlAutoCanvasRestore save(background_canvas, /*doSave=*/true);
685 
686  // Maps a platform view id to a vector of `FlutterPlatformViewLayer`.
687  LayersMap platform_view_layers;
688 
689  auto did_submit = true;
690  auto num_platform_views = composition_order_.size();
691 
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();
696 
697  // Check if the current picture contains overlays that intersect with the
698  // current platform view or any of the previous platform views.
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();
705 
706  // For testing purposes, the overlay id is used to find the overlay view.
707  // This is the index of the layer for the current platform view.
708  auto overlay_id = platform_view_layers[current_platform_view_id].size();
709 
710  // If the max number of allocations per platform view is exceeded,
711  // then join all the rects into a single one.
712  //
713  // TODO(egarciad): Consider making this configurable.
714  // https://github.com/flutter/flutter/issues/52510
715  if (allocation_size > kMaxLayerAllocations) {
716  SkRect joined_rect = SkRect::MakeEmpty();
717  for (const SkRect& rect : intersection_rects) {
718  joined_rect.join(rect);
719  }
720  // Replace the rects in the intersection rects list for a single rect that is
721  // the union of all the rects in the list.
722  intersection_rects.clear();
723  intersection_rects.push_back(joined_rect);
724  }
725  for (SkRect& joined_rect : intersection_rects) {
726  // Get the intersection rect between the current rect
727  // and the platform view rect.
728  joined_rect.intersect(platform_view_rect);
729  // Subpixels in the platform may not align with the canvas subpixels.
730  // To workaround it, round the floating point bounds and make the rect slightly larger.
731  // For example, {0.3, 0.5, 3.1, 4.7} becomes {0, 0, 4, 5}.
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()));
734  // Clip the background canvas, so it doesn't contain any of the pixels drawn
735  // on the overlay layer.
736  background_canvas->ClipRect(joined_rect, DlCanvas::ClipOp::kDifference);
737  // Get a new host layer.
738  std::shared_ptr<FlutterPlatformViewLayer> layer = GetLayer(gr_context, //
739  ios_context, //
740  slice, //
741  joined_rect, //
742  current_platform_view_id, //
743  overlay_id //
744  );
745  did_submit &= layer->did_submit_last_frame;
746  platform_view_layers[current_platform_view_id].push_back(layer);
747  overlay_id++;
748  }
749  }
750  slice->render_into(background_canvas);
751  }
752 
753  // Manually trigger the SkAutoCanvasRestore before we submit the frame
754  save.Restore();
755 
756  // If a layer was allocated in the previous frame, but it's not used in the current frame,
757  // then it can be removed from the scene.
758  RemoveUnusedLayers();
759  // Organize the layers by their z indexes.
760  BringLayersIntoView(platform_view_layers);
761  // Mark all layers as available, so they can be used in the next frame.
762  layer_pool_->RecycleLayers();
763 
764  did_submit &= frame->Submit();
765 
766  // If the frame is submitted with embedded platform views,
767  // there should be a |[CATransaction begin]| call in this frame prior to all the drawing.
768  // If that case, we need to commit the transaction.
769  CommitCATransactionIfNeeded();
770  return did_submit;
771 }

The documentation for this class was generated from the following files:
-[flutter::FlutterPlatformViewsController GetPlatformViewByID]
UIView * GetPlatformViewByID(int64_t view_id)
Definition: FlutterPlatformViews.mm:408
FlutterMethodNotImplemented
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
kFlutterClippingMaskViewPoolCapacity
static const NSUInteger kFlutterClippingMaskViewPoolCapacity
Definition: FlutterPlatformViews_Internal.mm:12
-[flutter::FlutterPlatformViewsController GetPlatformViewRect]
SkRect GetPlatformViewRect(int64_t view_id)
Definition: FlutterPlatformViews.mm:652
platform_view
std::unique_ptr< flutter::PlatformViewIOS > platform_view
Definition: FlutterEnginePlatformViewTest.mm:61
FlutterClippingMaskViewPool
Definition: FlutterPlatformViews_Internal.h:59
id
int32_t id
Definition: SemanticsObjectTestMocks.h:20
-[flutter::FlutterPlatformViewsController CancelFrame]
void CancelFrame()
Definition: FlutterPlatformViews.mm:322