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< FlutterViewResponder > *) - 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 205 of file FlutterPlatformViews_Internal.h.

Constructor & Destructor Documentation

◆ FlutterPlatformViewsController

- FlutterPlatformViewsController:

Definition at line 30 of file FlutterPlatformViews_Internal.mm.

31  : layer_pool_(std::make_unique<FlutterPlatformViewLayerPool>()),
32  weak_factory_(std::make_unique<fml::WeakPtrFactory<FlutterPlatformViewsController>>(this)) {
33  mask_view_pool_.reset(
35 };

References kFlutterClippingMaskViewPoolCapacity.

◆ ~FlutterPlatformViewsController

- FlutterPlatformViewsController:

Method Documentation

◆ BeginFrame

- (void) FlutterPlatformViewsController: (SkISize)  frame_size

Definition at line 314 of file FlutterPlatformViews.mm.

314  {
315  ResetFrameState();
316  frame_size_ = frame_size;
317 }

◆ CancelFrame

- (void) FlutterPlatformViewsController:

Definition at line 319 of file FlutterPlatformViews.mm.

319  {
320  ResetFrameState();
321 }

◆ CompositeEmbeddedView

- (DlCanvas *) FlutterPlatformViewsController: (int64_t)  view_id

Definition at line 618 of file FlutterPlatformViews.mm.

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

◆ EmbeddedViewCount

- (size_t) FlutterPlatformViewsController:

Definition at line 401 of file FlutterPlatformViews.mm.

401  {
402  return composition_order_.size();
403 }

◆ EndFrame

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

Definition at line 360 of file FlutterPlatformViews.mm.

362  {
363  if (should_resubmit_frame) {
364  raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
365  }
366 }

◆ FindFirstResponderPlatformViewId

- (long) FlutterPlatformViewsController:

Definition at line 417 of file FlutterPlatformViews.mm.

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

◆ GetFlutterTouchInterceptingViewByID

- (FlutterTouchInterceptingView *) FlutterPlatformViewsController: (int64_t)  view_id

Definition at line 409 of file FlutterPlatformViews.mm.

410  {
411  if (views_.empty()) {
412  return nil;
413  }
414  return touch_interceptors_[view_id].get();
415 }

Referenced by GetPlatformViewByID.

◆ getFlutterViewController

- (UIViewController< FlutterViewResponder > *) 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 405 of file FlutterPlatformViews.mm.

405  {
406  return [GetFlutterTouchInterceptingViewByID(view_id) embeddedView];
407 }

References FlutterTouchInterceptingView::embeddedView, and GetFlutterTouchInterceptingViewByID.

◆ GetPlatformViewRect

- (SkRect) FlutterPlatformViewsController: (int64_t)  view_id

Definition at line 648 of file FlutterPlatformViews.mm.

648  {
649  UIView* platform_view = GetPlatformViewByID(view_id);
650  UIScreen* screen = [UIScreen mainScreen];
651  CGRect platform_view_cgrect = [platform_view convertRect:platform_view.bounds
652  toView:flutter_view_];
653  return SkRect::MakeXYWH(platform_view_cgrect.origin.x * screen.scale, //
654  platform_view_cgrect.origin.y * screen.scale, //
655  platform_view_cgrect.size.width * screen.scale, //
656  platform_view_cgrect.size.height * screen.scale //
657  );
658 }

References platform_view.

◆ GetWeakPtr

- (WeakPtr<) flutter:

Definition at line 39 of file FlutterPlatformViews_Internal.mm.

39  {
40  return weak_factory_->GetWeakPtr();
41 }

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

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

◆ PrerollCompositeEmbeddedView

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

Definition at line 378 of file FlutterPlatformViews.mm.

380  {
381  // All the CATransactions should be committed by the end of the last frame,
382  // so catransaction_added_ must be false.
383  FML_DCHECK(!catransaction_added_);
384 
385  SkRect view_bounds = SkRect::Make(frame_size_);
386  std::unique_ptr<EmbedderViewSlice> view;
387  view = std::make_unique<DisplayListEmbedderViewSlice>(view_bounds);
388  slices_.insert_or_assign(view_id, std::move(view));
389 
390  composition_order_.push_back(view_id);
391 
392  if (current_composition_params_.count(view_id) == 1 &&
393  current_composition_params_[view_id] == *params.get()) {
394  // Do nothing if the params didn't change.
395  return;
396  }
397  current_composition_params_[view_id] = EmbeddedViewParams(*params.get());
398  views_to_recomposite_.insert(view_id);
399 }

◆ PushFilterToVisitedPlatformViews

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

Definition at line 368 of file FlutterPlatformViews.mm.

370  {
371  for (int64_t id : visited_platform_views_) {
372  EmbeddedViewParams params = current_composition_params_[id];
373  params.PushImageFilter(filter, filter_rect);
374  current_composition_params_[id] = params;
375  }
376 }

◆ PushVisitedPlatformView

- (void) FlutterPlatformViewsController: (int64_t)  view_id

Definition at line 284 of file FlutterPlatformViews_Internal.h.

284 { visited_platform_views_.push_back(view_id); }

◆ RegisterViewFactory

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

Definition at line 304 of file FlutterPlatformViews.mm.

307  {
308  std::string idString([factoryId UTF8String]);
309  FML_CHECK(factories_.count(idString) == 0);
310  factories_[idString] = fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>(factory);
311  gesture_recognizers_blocking_policies_[idString] = gestureRecognizerBlockingPolicy;
312 }

◆ Reset

- (void) FlutterPlatformViewsController:

Definition at line 630 of file FlutterPlatformViews.mm.

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

◆ SetFlutterView

- (void) FlutterPlatformViewsController: (UIView *)  flutter_view

Definition at line 163 of file FlutterPlatformViews.mm.

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

◆ SetFlutterViewController

- (void) FlutterPlatformViewsController: (UIViewController< FlutterViewResponder > *)  flutter_view_controller

Definition at line 167 of file FlutterPlatformViews.mm.

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

◆ SubmitFrame

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

Definition at line 660 of file FlutterPlatformViews.mm.

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

The documentation for this class was generated from the following files:
-[flutter::FlutterPlatformViewsController GetPlatformViewByID]
UIView * GetPlatformViewByID(int64_t view_id)
Definition: FlutterPlatformViews.mm:405
FlutterMethodNotImplemented
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
-[flutter::FlutterPlatformViewsController GetPlatformViewRect]
SkRect GetPlatformViewRect(int64_t view_id)
Definition: FlutterPlatformViews.mm:648
platform_view
std::unique_ptr< flutter::PlatformViewIOS > platform_view
Definition: FlutterEnginePlatformViewTest.mm:65
kFlutterClippingMaskViewPoolCapacity
static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity
Definition: FlutterPlatformViews_Internal.mm:14
FlutterClippingMaskViewPool
Definition: FlutterPlatformViews_Internal.h:62
FlutterView
Definition: FlutterView.h:34
-[flutter::FlutterPlatformViewsController CancelFrame]
void CancelFrame()
Definition: FlutterPlatformViews.mm:319