| 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< 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(
34 [[FlutterClippingMaskViewPool alloc] initWithCapacity:kFlutterClippingMaskViewPoolCapacity]);
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 {
186 result(FlutterMethodNotImplemented);
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:

- 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: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