Handing a UIView refererence directly to the engine makes it challenging
for plugin authors to retain a controller for that UIView (e.g the
controller that talks over the platform channel) for as long as the
embedded view is needed.
We instead make the factory return a FlutterPlatformView which is a
wrapper around the UIView that the engine retains as long as the
platform view instance is needed. This allows plugin authors to keep
their control logic in the FlutterPlatformView and know that the engine
is responsible for retaining the reference.
When we visit a PlatformViewLayer during the paint traversal it replaces
the PaintContext's canvas with a new one that is painted ontop of the
embedded view.
We need to make sure that operations applied by parent layers are also
applied to the new canvas.
To achieve this we collect all the canvases in a SkNWayCanvas and use
this canvas by non leaf nodes. Leaf nodes still paint only to the "current"
canvas.
This PR moves the overlay canvas creation from the paint phase to the
preroll phase, collects them into a SkNWayCanvas and set it in
PaintContext.
To keep this PR focused, I only used the internal_nodes_canvas in the
tranform_layer.
Will followup with a PR that changes all internal layers to use the
internal_nodes_canvas.
When the flag is true, we currently use a single thread configuration,
and disabled the raster cache for opacity layers.
The flag's name is 'io.flutter_embedded_views_preview'.
We are currently clearing the offscreen surface before rasterizing, but
as we draw the image snapshot of the offscreen surface into the onscreen
surface transparent pixels are blended with the current contents of the onscreen surface instead of replacing them. This is
particularly noticeable when embedding platform views.
The overlay surfaces are going to be the same IOSSurface implementation
with the platform views controller set to null (so these are surfaces
that don't support embedding platform views to them).
* Adds a FlutterOverlayView which is a UIView that's showing an
overlay surface.
* Creates an overlay surface for each embedded UIView (done in
FlutterPlatformViewsController).
* Changes CompositeEmbeddedView to return a new canvas.
* Makes the PlatformViewLayer replace the PaintContext's canvas with
the canvas for the overlay view.
* Changed canvas in PaintContext to be a pointer so it can be changed.
TBD in following PRs:
* Copy the current canvas state when replacing a canvas in PaintContext.
* Make FlutterOverlayView work with a GL backend (currently it only
works with software rendering)
Also tracks the order of embedded views from frame to frame, and only
removes and reattaches subviews if there is a structural change to the
UIView hierarchy.
This PR breaks PlatformViewsController's construction dependency on FlutterView,
which allows making FlutterEngine its owner instead of
FlutterViewController.
Also renamed the FlutterScreenshotDelegate to FlutterViewEngineDelegate
which is FlutterView's delegate to the engine, and expanded it to
provide a view embedder.
This allows the framework to decide whether and when a touch event
sequence arrives to the embedded view. Which gives the framework the
ability to manage hit testing and gesture disambiguation for embedded
UIViews.
We achieve this by wrapping each embedded UIView with another UIView that has
a custom UIGestureRecognizer that delays touch events from being
delivered, and another UIGestureRecognizer that makes sure to let
Flutter know of events that are hit tested to the embedded view.
The platform views embedding is still WIP, and until we dynamically
merge the gpu and platform threads based on the presence of an embedded
view in the scene fetching the view embedder is not thread safe.
This PR essentially disables iOS platform views embedding, we will
re-enable once dynamic thread merging is supported.
For flow to manipulate the embedded UIViews during the paint traversal
it needs some hook in PaintContext.
This PR introduces a ViewEmbeder interface that is implemented by the
iOS PlatformViewsController and plumbs it into PaintContext.
The ViewEmbedder interface is mainly a place holder at this point, as
this PR is focused on just the plumbing.
* Create FlutterEngine to manage a Shell to support maintaining execution state across instances of FlutterViewControllers
* Refactor PlatformViewIOS to support adding or removing a FlutterViewController dynamically
* Refactor FlutterDartHeadlessCodeRunner to implement FlutterEngine
* Refactor FlutterViewController to accept a FlutterEngine at initialization or to create one for backwards compatibility; any Shell related responsibilities are now passed through to the Engine instance
* Remove FlutterNavigationController (unused)
* Update all public Objective C doc comments to be consistent and formatable
* Add public documentation to all public headers
Adds a FlutterPlatformViewFactory protocol - a simple factory protocol to be implemented by plugins
that exposes a UIView for embedding in Flutter apps.
* Adds a FlutterPlatformView protocol, which is used to associate a
dispose callback with a `UIView` created by a FlutterPlatformViewFactory.
* Exposes a registerViewFactory method in FlutterPluginRegistrar.
* Implements the `flutter/platform_views` system channel on iOS, allowing
Dart code to ask for creation/destruction of UIViews.
TL;DR: Offscreen surface is created on the render thread and device to host
transfer performed there before task completion on the UI thread.
While attempting to snapshot layer trees, the engine was attempting to use the
IO thread context. The reasoning was that this would be safe to do because any
textures uploaded to the GPU as a result of async texture upload would have
originated from this context and hence the handles would be valid in either
context. As it turns out, while the handles are valid, Skia does not support
this use-case because cross-context images transfer ownership of the image from
one context to another. So, when we made the hop from the UI thread to the IO
thread (for snapshotting), if either the UI or GPU threads released the last
reference to the texture backed image, the image would be invalid. This led to
such images being absent from the layer tree snapshot.
Simply referencing the images as they are being used on the IO thread is not
sufficient because accessing images on one context after their ownership has
already been transferred to another is not safe behavior (from Skia's
perspective, the handles are still valid in the sharegroup).
To work around these issues, it was decided that an offscreen render target
would be created on the render thread. The color attachment of this render
target could then be transferred as a cross context image to the IO thread for
the device to host tranfer.
Again, this is currently not quite possible because the only way to create
cross context images is from encoded data. Till Skia exposes the functionality
to create cross-context images from textures in one context, we do a device to
host transfer on the GPU thread. The side effect of this is that this is now
part of the frame workload (image compression, which dominate the wall time,
is still done of the IO thread).
A minor side effect of this patch is that the GPU latch needs to be waited on
before the UI thread tasks can be completed before shell initialization.
According to the iOS docs, implementing
`- (id)insertDictationResultPlaceholder`
```Implementation of this method is optional but can be done when you want to provide a specific rectangle for the placeholder animation while the dictation results are being processed. ```
If you do not implement this method, UIKit will insert a default placeholder of 10 whitespace characters. By overriding this, no placeholder text will be inserted. If you implement the `insertDictationResultPlaceholder`, you must implement
`- (void)removeDictationResultPlaceholder:(id)placeholder willInsertResult:(BOOL)willInsertResult`