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 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(
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 {
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:
-[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