未验证 提交 70f6d18b 编写于 作者: E Emmanuel Garcia 提交者: GitHub

Revert "Implement unobstructed Platform Views on iOS (#17049)" (#17233)

This reverts commit 2627634b.
上级 bba1a3cc
......@@ -6,13 +6,10 @@
namespace flutter {
bool ExternalViewEmbedder::SubmitFrame(GrContext* context,
SkCanvas* background_canvas) {
bool ExternalViewEmbedder::SubmitFrame(GrContext* context) {
return false;
};
void ExternalViewEmbedder::FinishFrame(){};
void MutatorsStack::PushClipRect(const SkRect& rect) {
std::shared_ptr<Mutator> element = std::make_shared<Mutator>(rect);
vector_.push_back(element);
......
......@@ -248,10 +248,7 @@ class ExternalViewEmbedder {
// Must be called on the UI thread.
virtual SkCanvas* CompositeEmbeddedView(int view_id) = 0;
virtual bool SubmitFrame(GrContext* context, SkCanvas* background_canvas);
// This is called after submitting the embedder frame and the surface frame.
virtual void FinishFrame();
virtual bool SubmitFrame(GrContext* context);
FML_DISALLOW_COPY_AND_ASSIGN(ExternalViewEmbedder);
......
......@@ -59,7 +59,7 @@ void PictureLayer::Paint(PaintContext& context) const {
return;
}
}
picture()->playback(context.leaf_nodes_canvas);
context.leaf_nodes_canvas->drawPicture(picture());
}
} // namespace flutter
......@@ -94,6 +94,9 @@ TEST_F(PictureLayerTest, SimplePicture) {
1, MockCanvas::SetMatrixData{RasterCache::GetIntegralTransCTM(
layer_offset_matrix)}},
#endif
MockCanvas::DrawCall{
1, MockCanvas::DrawPictureData{mock_picture->serialize(), SkPaint(),
SkMatrix()}},
MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}});
EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls);
}
......
......@@ -342,17 +342,9 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
if (raster_status == RasterStatus::kFailed) {
return raster_status;
}
frame->Submit();
if (external_view_embedder != nullptr) {
external_view_embedder->SubmitFrame(surface_->GetContext(),
root_surface_canvas);
// The external view embedder may mutate the root surface canvas while
// submitting the frame.
// Therefore, submit the final frame after asking the external view
// embedder to submit the frame.
frame->Submit();
external_view_embedder->FinishFrame();
} else {
frame->Submit();
external_view_embedder->SubmitFrame(surface_->GetContext());
}
FireNextFrameCallbackIfPresent();
......
......@@ -8,77 +8,16 @@
#import "flutter/shell/platform/darwin/ios/ios_surface.h"
#import "flutter/shell/platform/darwin/ios/ios_surface_gl.h"
#include <list>
#include <map>
#include <memory>
#include <string>
#include "FlutterPlatformViews_Internal.h"
#include "flutter/flow/rtree.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/persistent_cache.h"
#include "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
namespace flutter {
std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewLayerPool::GetLayer(
GrContext* gr_context,
std::shared_ptr<IOSContext> ios_context) {
if (available_layer_index_ >= layers_.size()) {
std::shared_ptr<FlutterPlatformViewLayer> layer;
if (!gr_context) {
fml::scoped_nsobject<FlutterOverlayView> overlay_view([[FlutterOverlayView alloc] init]);
overlay_view.get().autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
std::unique_ptr<IOSSurface> ios_surface =
[overlay_view.get() createSurface:std::move(ios_context)];
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
layer = std::make_shared<FlutterPlatformViewLayer>(
std::move(overlay_view), std::move(ios_surface), std::move(surface));
} else {
CGFloat screenScale = [UIScreen mainScreen].scale;
fml::scoped_nsobject<FlutterOverlayView> overlay_view(
[[FlutterOverlayView alloc] initWithContentsScale:screenScale]);
overlay_view.get().autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
std::unique_ptr<IOSSurface> ios_surface =
[overlay_view.get() createSurface:std::move(ios_context)];
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
layer = std::make_shared<FlutterPlatformViewLayer>(
std::move(overlay_view), std::move(ios_surface), std::move(surface));
layer->gr_context = gr_context;
}
layers_.push_back(layer);
}
auto layer = layers_[available_layer_index_];
if (gr_context != layer->gr_context) {
layer->gr_context = gr_context;
// The overlay already exists, but the GrContext was changed so we need to recreate
// the rendering surface with the new GrContext.
IOSSurface* ios_surface = layer->ios_surface.get();
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
layer->surface = std::move(surface);
}
available_layer_index_++;
return layer;
}
void FlutterPlatformViewLayerPool::RecycleLayers() {
available_layer_index_ = 0;
}
std::vector<std::shared_ptr<FlutterPlatformViewLayer>>
FlutterPlatformViewLayerPool::GetUnusedLayers() {
std::vector<std::shared_ptr<FlutterPlatformViewLayer>> results;
for (size_t i = available_layer_index_; i < layers_.size(); i++) {
results.push_back(layers_[i]);
}
return results;
}
void FlutterPlatformViewsController::SetFlutterView(UIView* flutter_view) {
flutter_view_.reset([flutter_view retain]);
}
......@@ -144,9 +83,6 @@ void FlutterPlatformViewsController::OnCreate(FlutterMethodCall* call, FlutterRe
NSObject<FlutterPlatformView>* embedded_view = [factory createWithFrame:CGRectZero
viewIdentifier:viewId
arguments:params];
// Set a unique view identifier, so the platform view can be identified in unit tests.
[embedded_view view].accessibilityIdentifier =
[NSString stringWithFormat:@"platform_view[%ld]", viewId];
views_[viewId] = fml::scoped_nsobject<NSObject<FlutterPlatformView>>([embedded_view retain]);
FlutterTouchInterceptingView* touch_interceptor = [[[FlutterTouchInterceptingView alloc]
......@@ -260,11 +196,8 @@ void FlutterPlatformViewsController::PrerollCompositeEmbeddedView(
int view_id,
std::unique_ptr<EmbeddedViewParams> params) {
picture_recorders_[view_id] = std::make_unique<SkPictureRecorder>();
auto rtree_factory = RTreeFactory();
platform_view_rtrees_[view_id] = rtree_factory.getInstance();
picture_recorders_[view_id]->beginRecording(SkRect::Make(frame_size_), &rtree_factory);
picture_recorders_[view_id]->beginRecording(SkRect::Make(frame_size_));
picture_recorders_[view_id]->getRecordingCanvas()->clear(SK_ColorTRANSPARENT);
composition_order_.push_back(view_id);
if (current_composition_params_.count(view_id) == 1 &&
......@@ -428,182 +361,77 @@ void FlutterPlatformViewsController::Reset() {
composition_order_.clear();
active_composition_order_.clear();
picture_recorders_.clear();
platform_view_rtrees_.clear();
current_composition_params_.clear();
clip_count_.clear();
views_to_recomposite_.clear();
layer_pool_->RecycleLayers();
}
SkRect FlutterPlatformViewsController::GetPlatformViewRect(int view_id) {
UIView* platform_view = [views_[view_id].get() view];
UIScreen* screen = [UIScreen mainScreen];
CGRect platform_view_cgrect = [platform_view convertRect:platform_view.bounds
toView:flutter_view_];
return SkRect::MakeXYWH(platform_view_cgrect.origin.x * screen.scale, //
platform_view_cgrect.origin.y * screen.scale, //
platform_view_cgrect.size.width * screen.scale, //
platform_view_cgrect.size.height * screen.scale //
);
}
bool FlutterPlatformViewsController::SubmitFrame(GrContext* gr_context,
std::shared_ptr<IOSContext> ios_context,
SkCanvas* background_canvas) {
std::shared_ptr<IOSContext> ios_context) {
DisposeViews();
// Clipping the background canvas before drawing the picture recorders requires to
// save and restore the clip context.
SkAutoCanvasRestore save(background_canvas, /*doSave=*/true);
// Maps a platform view id to a vector of `FlutterPlatformViewLayer`.
LayersMap platform_view_layers;
auto did_submit = true;
auto num_platform_views = composition_order_.size();
for (size_t i = 0; i < num_platform_views; i++) {
int64_t platform_view_id = composition_order_[i];
sk_sp<RTree> rtree = platform_view_rtrees_[platform_view_id];
sk_sp<SkPicture> picture = picture_recorders_[platform_view_id]->finishRecordingAsPicture();
// Check if the current picture contains overlays that intersect with the
// current platform view or any of the previous platform views.
for (size_t j = i + 1; j > 0; j--) {
int64_t current_platform_view_id = composition_order_[j - 1];
SkRect platform_view_rect = GetPlatformViewRect(current_platform_view_id);
std::list<SkRect> intersection_rects =
rtree->searchNonOverlappingDrawnRects(platform_view_rect);
auto allocation_size = intersection_rects.size();
// For testing purposes, the overlay id is used to find the overlay view.
// This is the index of the layer for the current platform view.
auto overlay_id = platform_view_layers[current_platform_view_id].size();
// If the max number of allocations per platform view is exceeded,
// then join all the rects into a single one.
//
// TODO(egarciad): Consider making this configurable.
// https://github.com/flutter/flutter/issues/52510
if (allocation_size > kMaxLayerAllocations) {
SkRect joined_rect;
for (const SkRect& rect : intersection_rects) {
joined_rect.join(rect);
}
// Replace the rects in the intersection rects list for a single rect that is
// the union of all the rects in the list.
intersection_rects.clear();
intersection_rects.push_back(joined_rect);
}
for (SkRect& joined_rect : intersection_rects) {
// Get the intersection rect between the current rect
// and the platform view rect.
joined_rect.intersect(platform_view_rect);
// Clip the background canvas, so it doesn't contain any of the pixels drawn
// on the overlay layer.
background_canvas->clipRect(joined_rect, SkClipOp::kDifference);
// Get a new host layer.
auto layer = GetLayer(gr_context, //
ios_context, //
picture, //
joined_rect, //
current_platform_view_id, //
overlay_id //
);
did_submit &= layer->did_submit_last_frame;
platform_view_layers[current_platform_view_id].push_back(layer);
overlay_id++;
}
}
background_canvas->drawPicture(picture);
}
// If a layer was allocated in the previous frame, but it's not used in the current frame,
// then it can be removed from the scene.
RemoveUnusedLayers();
// Organize the layers by their z indexes.
BringLayersIntoView(platform_view_layers);
// Mark all layers as available, so they can be used in the next frame.
layer_pool_->RecycleLayers();
// Reset the composition order, so next frame starts empty.
composition_order_.clear();
return did_submit;
}
void FlutterPlatformViewsController::BringLayersIntoView(LayersMap layer_map) {
bool did_submit = true;
for (int64_t view_id : composition_order_) {
EnsureOverlayInitialized(view_id, ios_context, gr_context);
auto frame = overlays_[view_id]->surface->AcquireFrame(frame_size_);
// If frame is null, AcquireFrame already printed out an error message.
if (frame) {
SkCanvas* canvas = frame->SkiaCanvas();
canvas->drawPicture(picture_recorders_[view_id]->finishRecordingAsPicture());
canvas->flush();
did_submit &= frame->Submit();
}
}
picture_recorders_.clear();
if (composition_order_ == active_composition_order_) {
composition_order_.clear();
return did_submit;
}
DetachUnusedLayers();
active_composition_order_.clear();
UIView* flutter_view = flutter_view_.get();
auto zIndex = 0;
for (size_t i = 0; i < composition_order_.size(); i++) {
int64_t platform_view_id = composition_order_[i];
std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_map[platform_view_id];
UIView* platform_view_root = root_views_[platform_view_id].get();
if (platform_view_root.superview != flutter_view) {
[flutter_view addSubview:platform_view_root];
for (size_t i = 0; i < composition_order_.size(); i++) {
int view_id = composition_order_[i];
// We added a chain of super views to the platform view to handle clipping.
// The `platform_view_root` is the view at the top of the chain which is a direct subview of the
// `FlutterView`.
UIView* platform_view_root = root_views_[view_id].get();
UIView* overlay = overlays_[view_id]->overlay_view;
FML_CHECK(platform_view_root.superview == overlay.superview);
if (platform_view_root.superview == flutter_view) {
[flutter_view bringSubviewToFront:platform_view_root];
[flutter_view bringSubviewToFront:overlay];
} else {
platform_view_root.layer.zPosition = zIndex++;
}
for (const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
if ([layer->overlay_view superview] != flutter_view) {
[flutter_view addSubview:layer->overlay_view];
} else {
layer->overlay_view.get().layer.zPosition = zIndex++;
}
[flutter_view addSubview:platform_view_root];
[flutter_view addSubview:overlay];
overlay.frame = flutter_view.bounds;
}
active_composition_order_.push_back(platform_view_id);
}
}
std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLayer(
GrContext* gr_context,
std::shared_ptr<IOSContext> ios_context,
sk_sp<SkPicture> picture,
SkRect rect,
int64_t view_id,
int64_t overlay_id) {
auto layer = layer_pool_->GetLayer(gr_context, ios_context);
auto screenScale = [UIScreen mainScreen].scale;
// Set the size of the overlay UIView.
layer->overlay_view.get().frame = CGRectMake(rect.x() / screenScale, //
rect.y() / screenScale, //
rect.width() / screenScale, //
rect.height() / screenScale //
);
// Set a unique view identifier, so the overlay can be identified in unit tests.
layer->overlay_view.get().accessibilityIdentifier =
[NSString stringWithFormat:@"platform_view[%lld].overlay[%lld]", view_id, overlay_id];
std::unique_ptr<SurfaceFrame> frame =
layer->surface->AcquireFrame(SkISize::Make(rect.width(), rect.height()));
// If frame is null, AcquireFrame already printed out an error message.
if (!frame) {
return layer;
}
auto overlay_canvas = frame->SkiaCanvas();
overlay_canvas->clear(SK_ColorTRANSPARENT);
// Offset the picture since its absolute position on the scene is determined
// by the position of the overlay view.
overlay_canvas->translate(-rect.x(), -rect.y());
overlay_canvas->drawPicture(picture);
layer->did_submit_last_frame = frame->Submit();
return layer;
}
void FlutterPlatformViewsController::RemoveUnusedLayers() {
auto layers = layer_pool_->GetUnusedLayers();
for (const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
[layer->overlay_view removeFromSuperview];
active_composition_order_.push_back(view_id);
}
composition_order_.clear();
return did_submit;
}
void FlutterPlatformViewsController::DetachUnusedLayers() {
std::unordered_set<int64_t> composition_order_set;
for (int64_t view_id : composition_order_) {
composition_order_set.insert(view_id);
}
// Remove unused platform views.
for (int64_t view_id : active_composition_order_) {
if (composition_order_set.find(view_id) == composition_order_set.end()) {
if (root_views_.find(view_id) == root_views_.end()) {
continue;
}
// We added a chain of super views to the platform view to handle clipping.
// The `platform_view_root` is the view at the top of the chain which is a direct subview of
// the `FlutterView`.
UIView* platform_view_root = root_views_[view_id].get();
[platform_view_root removeFromSuperview];
[overlays_[view_id]->overlay_view.get() removeFromSuperview];
}
}
}
......@@ -630,6 +458,56 @@ void FlutterPlatformViewsController::DisposeViews() {
views_to_dispose_.clear();
}
void FlutterPlatformViewsController::EnsureOverlayInitialized(
int64_t overlay_id,
std::shared_ptr<IOSContext> ios_context,
GrContext* gr_context) {
FML_DCHECK(flutter_view_);
auto overlay_it = overlays_.find(overlay_id);
if (!gr_context) {
if (overlays_.count(overlay_id) != 0) {
return;
}
fml::scoped_nsobject<FlutterOverlayView> overlay_view([[FlutterOverlayView alloc] init]);
overlay_view.get().frame = flutter_view_.get().bounds;
overlay_view.get().autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
std::unique_ptr<IOSSurface> ios_surface =
[overlay_view.get() createSurface:std::move(ios_context)];
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
overlays_[overlay_id] = std::make_unique<FlutterPlatformViewLayer>(
std::move(overlay_view), std::move(ios_surface), std::move(surface));
return;
}
if (overlay_it != overlays_.end()) {
FlutterPlatformViewLayer* overlay = overlay_it->second.get();
if (gr_context != overlay->gr_context) {
overlay->gr_context = gr_context;
// The overlay already exists, but the GrContext was changed so we need to recreate
// the rendering surface with the new GrContext.
IOSSurface* ios_surface = overlay_it->second->ios_surface.get();
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
overlay_it->second->surface = std::move(surface);
}
return;
}
auto contentsScale = flutter_view_.get().layer.contentsScale;
fml::scoped_nsobject<FlutterOverlayView> overlay_view(
[[FlutterOverlayView alloc] initWithContentsScale:contentsScale]);
overlay_view.get().frame = flutter_view_.get().bounds;
overlay_view.get().autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
std::unique_ptr<IOSSurface> ios_surface =
[overlay_view.get() createSurface:std::move(ios_context)];
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
overlays_[overlay_id] = std::make_unique<FlutterPlatformViewLayer>(
std::move(overlay_view), std::move(ios_surface), std::move(surface));
overlays_[overlay_id]->gr_context = gr_context;
}
} // namespace flutter
// This recognizers delays touch events from being dispatched to the responder chain until it failed
......
......@@ -6,7 +6,6 @@
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_
#include "flutter/flow/embedded_views.h"
#include "flutter/flow/rtree.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
......@@ -69,52 +68,12 @@ struct FlutterPlatformViewLayer {
std::unique_ptr<IOSSurface> ios_surface;
std::unique_ptr<Surface> surface;
// Whether a frame for this layer was submitted.
bool did_submit_last_frame;
// The GrContext that is currently used by the overlay surfaces.
// We track this to know when the GrContext for the Flutter app has changed
// so we can update the overlay with the new context.
GrContext* gr_context;
};
// This class isn't thread safe.
class FlutterPlatformViewLayerPool {
public:
FlutterPlatformViewLayerPool() = default;
~FlutterPlatformViewLayerPool() = default;
// Gets a layer from the pool if available, or allocates a new one.
// Finally, it marks the layer as used. That is, it increments `available_layer_index_`.
std::shared_ptr<FlutterPlatformViewLayer> GetLayer(GrContext* gr_context,
std::shared_ptr<IOSContext> ios_context);
// Gets the layers in the pool that aren't currently used.
// This method doesn't mark the layers as unused.
std::vector<std::shared_ptr<FlutterPlatformViewLayer>> GetUnusedLayers();
// Marks the layers in the pool as available for reuse.
void RecycleLayers();
private:
// The index of the entry in the layers_ vector that determines the beginning of the unused
// layers. For example, consider the following vector:
// _____
// | 0 |
/// |---|
/// | 1 | <-- available_layer_index_
/// |---|
/// | 2 |
/// |---|
///
/// This indicates that entries starting from 1 can be reused meanwhile the entry at position 0
/// cannot be reused.
size_t available_layer_index_ = 0;
std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers_;
FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewLayerPool);
};
class FlutterPlatformViewsController {
public:
FlutterPlatformViewsController();
......@@ -150,37 +109,14 @@ class FlutterPlatformViewsController {
SkCanvas* CompositeEmbeddedView(int view_id);
// The rect of the platform view at index view_id. This rect has been translated into the
// host view coordinate system. Units are device screen pixels.
SkRect GetPlatformViewRect(int view_id);
// Discards all platform views instances and auxiliary resources.
void Reset();
bool SubmitFrame(GrContext* gr_context,
std::shared_ptr<IOSContext> ios_context,
SkCanvas* background_canvas);
bool SubmitFrame(GrContext* gr_context, std::shared_ptr<IOSContext> ios_context);
void OnMethodCall(FlutterMethodCall* call, FlutterResult& result);
private:
static const size_t kMaxLayerAllocations = 2;
using LayersMap = std::map<int64_t, std::vector<std::shared_ptr<FlutterPlatformViewLayer>>>;
// The pool of reusable view layers. The pool allows to recycle layer in each frame.
std::unique_ptr<FlutterPlatformViewLayerPool> layer_pool_;
// The platform view's R-tree keyed off the view id, which contains any subsequent
// draw operation until the next platform view or the last leaf node in the layer tree.
//
// The R-trees are deleted by the FlutterPlatformViewsController.reset().
std::map<int64_t, sk_sp<RTree>> platform_view_rtrees_;
// The platform view's picture recorder keyed off the view id, which contains any subsequent
// operation until the next platform view or the end of the last leaf node in the layer tree.
std::map<int64_t, std::unique_ptr<SkPictureRecorder>> picture_recorders_;
fml::scoped_nsobject<FlutterMethodChannel> channel_;
fml::scoped_nsobject<UIView> flutter_view_;
fml::scoped_nsobject<UIViewController> flutter_view_controller_;
......@@ -227,12 +163,19 @@ class FlutterPlatformViewsController {
std::map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>
gesture_recognizers_blocking_policies;
std::map<int64_t, std::unique_ptr<SkPictureRecorder>> picture_recorders_;
void OnCreate(FlutterMethodCall* call, FlutterResult& result);
void OnDispose(FlutterMethodCall* call, FlutterResult& result);
void OnAcceptGesture(FlutterMethodCall* call, FlutterResult& result);
void OnRejectGesture(FlutterMethodCall* call, FlutterResult& result);
void DetachUnusedLayers();
// Dispose the views in `views_to_dispose_`.
void DisposeViews();
void EnsureOverlayInitialized(int64_t overlay_id,
std::shared_ptr<IOSContext> ios_context,
GrContext* gr_context);
// This will return true after pre-roll if any of the embedded views
// have mutated for last layer tree.
......@@ -272,20 +215,6 @@ class FlutterPlatformViewsController {
void ApplyMutators(const MutatorsStack& mutators_stack, UIView* embedded_view);
void CompositeWithParams(int view_id, const EmbeddedViewParams& params);
// Allocates a new FlutterPlatformViewLayer if needed, draws the pixels within the rect from
// the picture on the layer's canvas.
std::shared_ptr<FlutterPlatformViewLayer> GetLayer(GrContext* gr_context,
std::shared_ptr<IOSContext> ios_context,
sk_sp<SkPicture> picture,
SkRect rect,
int64_t view_id,
int64_t overlay_id);
// Removes overlay views and platform views that aren't needed in the current frame.
void RemoveUnusedLayers();
// Appends the overlay views and platform view and sets their z index based on the composition
// order.
void BringLayersIntoView(LayersMap layer_map);
FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewsController);
};
......
......@@ -20,8 +20,7 @@ FlutterPlatformViewLayer::FlutterPlatformViewLayer(fml::scoped_nsobject<UIView>
FlutterPlatformViewLayer::~FlutterPlatformViewLayer() = default;
FlutterPlatformViewsController::FlutterPlatformViewsController()
: layer_pool_(std::make_unique<FlutterPlatformViewLayerPool>()){};
FlutterPlatformViewsController::FlutterPlatformViewsController() = default;
FlutterPlatformViewsController::~FlutterPlatformViewsController() = default;
......
......@@ -77,10 +77,7 @@ class IOSSurface : public ExternalViewEmbedder {
SkCanvas* CompositeEmbeddedView(int view_id) override;
// |ExternalViewEmbedder|
bool SubmitFrame(GrContext* context, SkCanvas* background_canvas) override;
// |ExternalViewEmbedder|
void FinishFrame() override;
bool SubmitFrame(GrContext* context) override;
public:
FML_DISALLOW_COPY_AND_ASSIGN(IOSSurface);
......
......@@ -132,18 +132,12 @@ SkCanvas* IOSSurface::CompositeEmbeddedView(int view_id) {
}
// |ExternalViewEmbedder|
bool IOSSurface::SubmitFrame(GrContext* context, SkCanvas* background_canvas) {
bool IOSSurface::SubmitFrame(GrContext* context) {
TRACE_EVENT0("flutter", "IOSSurface::SubmitFrame");
FML_CHECK(platform_views_controller_ != nullptr);
bool submitted =
platform_views_controller_->SubmitFrame(std::move(context), ios_context_, background_canvas);
return submitted;
}
// |ExternalViewEmbedder|
void IOSSurface::FinishFrame() {
TRACE_EVENT0("flutter", "IOSSurface::DidSubmitFrame");
bool submitted = platform_views_controller_->SubmitFrame(std::move(context), ios_context_);
[CATransaction commit];
return submitted;
}
} // namespace flutter
......@@ -129,8 +129,7 @@ static FlutterBackingStoreConfig MakeBackingStoreConfig(
}
// |ExternalViewEmbedder|
bool EmbedderExternalViewEmbedder::SubmitFrame(GrContext* context,
SkCanvas* background_canvas) {
bool EmbedderExternalViewEmbedder::SubmitFrame(GrContext* context) {
auto [matched_render_targets, pending_keys] =
render_target_cache_.GetExistingTargetsInCache(pending_views_);
......@@ -266,7 +265,4 @@ bool EmbedderExternalViewEmbedder::SubmitFrame(GrContext* context,
return true;
}
// |ExternalViewEmbedder|
void EmbedderExternalViewEmbedder::FinishFrame() {}
} // namespace flutter
......@@ -89,10 +89,7 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder {
SkCanvas* CompositeEmbeddedView(int view_id) override;
// |ExternalViewEmbedder|
bool SubmitFrame(GrContext* context, SkCanvas* background_canvas) override;
// |ExternalViewEmbedder|
void FinishFrame() override;
bool SubmitFrame(GrContext* context) override;
// |ExternalViewEmbedder|
SkCanvas* GetRootCanvas() override;
......
......@@ -43,7 +43,6 @@
3DEF491A23C3BE6500184216 /* golden_platform_view_transform_iPhone 8_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 3DE09E9123C010BD006C9851 /* golden_platform_view_transform_iPhone 8_simulator.png */; };
59A97FD8236A49D300B4C066 /* golden_platform_view_multiple_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 59A97FD7236A49D300B4C066 /* golden_platform_view_multiple_iPhone SE_simulator.png */; };
59A97FDA236B984300B4C066 /* golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 59A97FD9236B984300B4C066 /* golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png */; };
6402EBD124147BDA00987DCB /* UnobstructedPlatformViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6402EBD024147BDA00987DCB /* UnobstructedPlatformViewTests.m */; };
6816DB9E231750ED00A51400 /* GoldenPlatformViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DB9D231750ED00A51400 /* GoldenPlatformViewTests.m */; };
6816DBA12317573300A51400 /* GoldenImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DBA02317573300A51400 /* GoldenImage.m */; };
6816DBA42318358200A51400 /* PlatformViewGoldenTestManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6816DBA32318358200A51400 /* PlatformViewGoldenTestManager.m */; };
......@@ -150,7 +149,6 @@
3DE09E9223C010BD006C9851 /* golden_platform_view_cliprect_iPhone 8_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprect_iPhone 8_simulator.png"; sourceTree = "<group>"; };
59A97FD7236A49D300B4C066 /* golden_platform_view_multiple_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_multiple_iPhone SE_simulator.png"; sourceTree = "<group>"; };
59A97FD9236B984300B4C066 /* golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_multiple_background_foreground_iPhone SE_simulator.png"; sourceTree = "<group>"; };
6402EBD024147BDA00987DCB /* UnobstructedPlatformViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UnobstructedPlatformViewTests.m; sourceTree = "<group>"; };
6816DB9C231750ED00A51400 /* GoldenPlatformViewTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GoldenPlatformViewTests.h; sourceTree = "<group>"; };
6816DB9D231750ED00A51400 /* GoldenPlatformViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoldenPlatformViewTests.m; sourceTree = "<group>"; };
6816DB9F2317573300A51400 /* GoldenImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GoldenImage.h; sourceTree = "<group>"; };
......@@ -247,7 +245,6 @@
248D76ED22E388380012F0C1 /* ScenariosUITests */ = {
isa = PBXGroup;
children = (
6402EBD024147BDA00987DCB /* UnobstructedPlatformViewTests.m */,
0D14A3FD239743190013D873 /* golden_platform_view_rotate_iPhone SE_simulator.png */,
3DE09E8B23C010BC006C9851 /* golden_platform_view_clippath_iPhone 8_simulator.png */,
3DE09E9223C010BD006C9851 /* golden_platform_view_cliprect_iPhone 8_simulator.png */,
......@@ -491,7 +488,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6402EBD124147BDA00987DCB /* UnobstructedPlatformViewTests.m in Sources */,
68A5B63423EB71D300BDBCDB /* PlatformViewGestureRecognizerTests.m in Sources */,
6816DBA12317573300A51400 /* GoldenImage.m in Sources */,
6816DB9E231750ED00A51400 /* GoldenPlatformViewTests.m in Sources */,
......
......@@ -29,13 +29,6 @@
// the launchArgsMap should match the one in the `PlatformVieGoldenTestManager`.
NSDictionary<NSString*, NSString*>* launchArgsMap = @{
@"--platform-view" : @"platform_view",
@"--platform-view-no-overlay-intersection" : @"platform_view_no_overlay_intersection",
@"--platform-view-two-intersecting-overlays" : @"platform_view_two_intersecting_overlays",
@"--platform-view-partial-intersection" : @"platform_view_partial_intersection",
@"--platform-view-one-overlay-two-intersecting-overlays" :
@"platform_view_one_overlay_two_intersecting_overlays",
@"--platform-view-multiple-without-overlays" : @"platform_view_multiple_without_overlays",
@"--platform-view-max-overlays" : @"platform_view_max_overlays",
@"--platform-view-multiple" : @"platform_view_multiple",
@"--platform-view-multiple-background-foreground" :
@"platform_view_multiple_background_foreground",
......
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <XCTest/XCTest.h>
@interface UnobstructedPlatformViewTests : XCTestCase
@end
@implementation UnobstructedPlatformViewTests
- (void)setUp {
self.continueAfterFailure = NO;
}
// A is the layer, which z index is higher than the platform view.
// +--------+
// | PV | +---+
// +--------+ | A |
// +---+
- (void)testNoOverlay {
XCUIApplication* app = [[XCUIApplication alloc] init];
app.launchArguments = @[ @"--platform-view-no-overlay-intersection" ];
[app launch];
XCUIElement* platform_view = app.textViews[@"platform_view[0]"];
XCTAssertTrue(platform_view.exists);
XCTAssertEqual(platform_view.frame.origin.x, 25);
XCTAssertEqual(platform_view.frame.origin.y, 25);
XCTAssertEqual(platform_view.frame.size.width, 250);
XCTAssertEqual(platform_view.frame.size.height, 250);
XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
XCTAssertFalse(overlay.exists);
}
// A is the layer above the platform view.
// +-----------------+
// | PV +---+ |
// | | A | |
// | +---+ |
// +-----------------+
- (void)testOneOverlay {
XCUIApplication* app = [[XCUIApplication alloc] init];
app.launchArguments = @[ @"--platform-view" ];
[app launch];
XCUIElement* platform_view = app.textViews[@"platform_view[0]"];
XCTAssertTrue(platform_view.exists);
XCTAssertEqual(platform_view.frame.origin.x, 25);
XCTAssertEqual(platform_view.frame.origin.y, 25);
XCTAssertEqual(platform_view.frame.size.width, 250);
XCTAssertEqual(platform_view.frame.size.height, 250);
XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
XCTAssertTrue(overlay.exists);
XCTAssertEqual(overlay.frame.origin.x, 150);
XCTAssertEqual(overlay.frame.origin.y, 150);
XCTAssertEqual(overlay.frame.size.width, 50);
XCTAssertEqual(overlay.frame.size.height, 50);
}
// A is the layer above the platform view.
// +-----------------+
// | PV +---+ |
// +-----------| A |-+
// +---+
- (void)testOneOverlayPartialIntersection {
XCUIApplication* app = [[XCUIApplication alloc] init];
app.launchArguments = @[ @"--platform-view-partial-intersection" ];
[app launch];
XCUIElement* platform_view = app.textViews[@"platform_view[0]"];
XCTAssertTrue(platform_view.exists);
XCTAssertEqual(platform_view.frame.origin.x, 25);
XCTAssertEqual(platform_view.frame.origin.y, 25);
XCTAssertEqual(platform_view.frame.size.width, 250);
XCTAssertEqual(platform_view.frame.size.height, 250);
XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
XCTAssertTrue(overlay.exists);
XCTAssertEqual(overlay.frame.origin.x, 200);
XCTAssertEqual(overlay.frame.origin.y, 250);
XCTAssertEqual(overlay.frame.size.width, 50);
// Half the height of the overlay.
XCTAssertEqual(overlay.frame.size.height, 25);
}
// A and B are the layers above the platform view.
// +--------------------+
// | PV +------------+ |
// | | B +-----+ | |
// | +---| A |-+ |
// +----------| |---+
// +-----+
- (void)testTwoIntersectingOverlays {
XCUIApplication* app = [[XCUIApplication alloc] init];
app.launchArguments = @[ @"--platform-view-two-intersecting-overlays" ];
[app launch];
XCUIElement* platform_view = app.textViews[@"platform_view[0]"];
XCTAssertTrue(platform_view.exists);
XCTAssertEqual(platform_view.frame.origin.x, 25);
XCTAssertEqual(platform_view.frame.origin.y, 25);
XCTAssertEqual(platform_view.frame.size.width, 250);
XCTAssertEqual(platform_view.frame.size.height, 250);
XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
XCTAssertTrue(overlay.exists);
XCTAssertEqual(overlay.frame.origin.x, 150);
XCTAssertEqual(overlay.frame.origin.y, 150);
XCTAssertEqual(overlay.frame.size.width, 75);
XCTAssertEqual(overlay.frame.size.height, 75);
XCTAssertFalse(app.otherElements[@"platform_view[0].overlay[1]"].exists);
}
// A, B, and C are the layers above the platform view.
// +-------------------------+
// | PV +-----------+ |
// | +---+ | B +-----+ | |
// | | C | +---| A |-+ |
// | +---+ +-----+ |
// +-------------------------+
- (void)testOneOverlayAndTwoIntersectingOverlays {
XCUIApplication* app = [[XCUIApplication alloc] init];
app.launchArguments = @[ @"--platform-view-one-overlay-two-intersecting-overlays" ];
[app launch];
XCUIElement* platform_view = app.textViews[@"platform_view[0]"];
XCTAssertTrue(platform_view.exists);
XCTAssertEqual(platform_view.frame.origin.x, 25);
XCTAssertEqual(platform_view.frame.origin.y, 25);
XCTAssertEqual(platform_view.frame.size.width, 250);
XCTAssertEqual(platform_view.frame.size.height, 250);
XCUIElement* overlay1 = app.otherElements[@"platform_view[0].overlay[0]"];
XCTAssertTrue(overlay1.exists);
XCTAssertEqual(overlay1.frame.origin.x, 150);
XCTAssertEqual(overlay1.frame.origin.y, 150);
XCTAssertEqual(overlay1.frame.size.width, 75);
XCTAssertEqual(overlay1.frame.size.height, 75);
XCUIElement* overlay2 = app.otherElements[@"platform_view[0].overlay[1]"];
XCTAssertTrue(overlay2.exists);
XCTAssertEqual(overlay2.frame.origin.x, 75);
XCTAssertEqual(overlay2.frame.origin.y, 225);
XCTAssertEqual(overlay2.frame.size.width, 50);
XCTAssertEqual(overlay2.frame.size.height, 50);
}
// A is the layer, which z index is higher than the platform view.
// +--------+
// | PV | +---+
// +--------+ | A |
// +--------+ +---+
// | PV |
// +--------+
- (void)testMultiplePlatformViewsWithoutOverlays {
XCUIApplication* app = [[XCUIApplication alloc] init];
app.launchArguments = @[ @"--platform-view-multiple-without-overlays" ];
[app launch];
XCUIElement* platform_view1 = app.textViews[@"platform_view[0]"];
XCTAssertTrue(platform_view1.exists);
XCTAssertEqual(platform_view1.frame.origin.x, 25);
XCTAssertEqual(platform_view1.frame.origin.y, 325);
XCTAssertEqual(platform_view1.frame.size.width, 250);
XCTAssertEqual(platform_view1.frame.size.height, 250);
XCUIElement* platform_view2 = app.textViews[@"platform_view[1]"];
XCTAssertTrue(platform_view2.exists);
XCTAssertEqual(platform_view2.frame.origin.x, 25);
XCTAssertEqual(platform_view2.frame.origin.y, 25);
XCTAssertEqual(platform_view2.frame.size.width, 250);
XCTAssertEqual(platform_view2.frame.size.height, 250);
XCTAssertFalse(app.otherElements[@"platform_view[0].overlay[0]"].exists);
XCTAssertFalse(app.otherElements[@"platform_view[1].overlay[0]"].exists);
}
// A is the layer above both platform view.
// +------------+
// | PV +----+ |
// +-----| A |-+
// +-----| |-+
// | PV +----+ |
// +------------+
- (void)testMultiplePlatformViewsWithOverlays {
XCUIApplication* app = [[XCUIApplication alloc] init];
app.launchArguments = @[ @"--platform-view-multiple-background-foreground" ];
[app launch];
XCUIElement* platform_view1 = app.textViews[@"platform_view[8]"];
XCTAssertTrue(platform_view1.exists);
XCTAssertEqual(platform_view1.frame.origin.x, 25);
XCTAssertEqual(platform_view1.frame.origin.y, 325);
XCTAssertEqual(platform_view1.frame.size.width, 250);
XCTAssertEqual(platform_view1.frame.size.height, 250);
XCUIElement* platform_view2 = app.textViews[@"platform_view[9]"];
XCTAssertTrue(platform_view2.exists);
XCTAssertEqual(platform_view2.frame.origin.x, 25);
XCTAssertEqual(platform_view2.frame.origin.y, 25);
XCTAssertEqual(platform_view2.frame.size.width, 250);
XCTAssertEqual(platform_view2.frame.size.height, 250);
XCUIElement* overlay1 = app.otherElements[@"platform_view[8].overlay[0]"];
XCTAssertTrue(overlay1.exists);
XCTAssertEqual(overlay1.frame.origin.x, 25);
XCTAssertEqual(overlay1.frame.origin.y, 325);
XCTAssertEqual(overlay1.frame.size.width, 225);
XCTAssertEqual(overlay1.frame.size.height, 175);
XCUIElement* overlay2 = app.otherElements[@"platform_view[9].overlay[0]"];
XCTAssertTrue(overlay2.exists);
XCTAssertEqual(overlay2.frame.origin.x, 25);
XCTAssertEqual(overlay2.frame.origin.y, 25);
XCTAssertEqual(overlay2.frame.size.width, 225);
XCTAssertEqual(overlay2.frame.size.height, 250);
}
// More then two overlays are merged into a single layer.
// +---------------------+
// | +---+ +---+ +---+ |
// | | A | | B | | C | |
// | +---+ +---+ +---+ |
// | +-------+ |
// +-| D |-----------+
// +-------+
- (void)testPlatformViewsMaxOverlays {
XCUIApplication* app = [[XCUIApplication alloc] init];
app.launchArguments = @[ @"--platform-view-max-overlays" ];
[app launch];
XCUIElement* platform_view = app.textViews[@"platform_view[0]"];
XCTAssertTrue(platform_view.exists);
XCTAssertEqual(platform_view.frame.origin.x, 25);
XCTAssertEqual(platform_view.frame.origin.y, 25);
XCTAssertEqual(platform_view.frame.size.width, 250);
XCTAssertEqual(platform_view.frame.size.height, 250);
XCUIElement* overlay = app.otherElements[@"platform_view[0].overlay[0]"];
XCTAssertTrue(overlay.exists);
XCTAssertEqual(overlay.frame.origin.x, 75);
XCTAssertEqual(overlay.frame.origin.y, 85);
XCTAssertEqual(overlay.frame.size.width, 150);
XCTAssertEqual(overlay.frame.size.height, 190);
XCTAssertFalse(app.otherElements[@"platform_view[0].overlay[1]"].exists);
}
@end
......@@ -19,12 +19,6 @@ import 'src/touches_scenario.dart';
Map<String, Scenario> _scenarios = <String, Scenario>{
'animated_color_square': AnimatedColorSquareScenario(window),
'platform_view': PlatformViewScenario(window, 'Hello from Scenarios (Platform View)', id: 0),
'platform_view_no_overlay_intersection': PlatformViewNoOverlayIntersectionScenario(window, 'Hello from Scenarios (Platform View)', id: 0),
'platform_view_partial_intersection': PlatformViewPartialIntersectionScenario(window, 'Hello from Scenarios (Platform View)', id: 0),
'platform_view_two_intersecting_overlays': PlatformViewTwoIntersectingOverlaysScenario(window, 'Hello from Scenarios (Platform View)', id: 0),
'platform_view_one_overlay_two_intersecting_overlays': PlatformViewOneOverlayTwoIntersectingOverlaysScenario(window, 'Hello from Scenarios (Platform View)', id: 0),
'platform_view_multiple_without_overlays': MultiPlatformViewWithoutOverlaysScenario(window, 'Hello from Scenarios (Platform View)', id: 0),
'platform_view_max_overlays': PlatformViewMaxOverlaysScenario(window, 'Hello from Scenarios (Platform View)', id: 0),
'platform_view_cliprect': PlatformViewClipRectScenario(window, 'PlatformViewClipRect', id: 1),
'platform_view_cliprrect': PlatformViewClipRRectScenario(window, 'PlatformViewClipRRect', id: 2),
'platform_view_clippath': PlatformViewClipPathScenario(window, 'PlatformViewClipPath', id: 3),
......
......@@ -48,224 +48,6 @@ class PlatformViewScenario extends Scenario with _BasePlatformViewScenarioMixin
}
}
/// A simple platform view with overlay that doesn't intersect with the platform view.
class PlatformViewNoOverlayIntersectionScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Creates the PlatformView scenario.
///
/// The [window] parameter must not be null.
PlatformViewNoOverlayIntersectionScenario(Window window, String text, {int id = 0})
: assert(window != null),
super(window) {
createPlatformView(window, text, id);
}
@override
void onBeginFrame(Duration duration) {
final SceneBuilder builder = SceneBuilder();
builder.pushOffset(0, 0);
finishBuilderByAddingPlatformViewAndPicture(
builder,
0,
overlayOffset: const Offset(150, 350),
);
}
}
/// A simple platform view with an overlay that partially intersects with the platform view.
class PlatformViewPartialIntersectionScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Creates the PlatformView scenario.
///
/// The [window] parameter must not be null.
PlatformViewPartialIntersectionScenario(Window window, String text, {int id = 0})
: assert(window != null),
super(window) {
createPlatformView(window, text, id);
}
@override
void onBeginFrame(Duration duration) {
final SceneBuilder builder = SceneBuilder();
builder.pushOffset(0, 0);
finishBuilderByAddingPlatformViewAndPicture(
builder,
0,
overlayOffset: const Offset(150, 250),
);
}
}
/// A simple platform view with two overlays that intersect with each other and the platform view.
class PlatformViewTwoIntersectingOverlaysScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Creates the PlatformView scenario.
///
/// The [window] parameter must not be null.
PlatformViewTwoIntersectingOverlaysScenario(Window window, String text, {int id = 0})
: assert(window != null),
super(window) {
createPlatformView(window, text, id);
}
@override
void onBeginFrame(Duration duration) {
final SceneBuilder builder = SceneBuilder();
builder.pushOffset(0, 0);
_addPlatformViewtoScene(builder, 0, 500, 500);
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawCircle(
const Offset(50, 50),
50,
Paint()..color = const Color(0xFFABCDEF),
);
canvas.drawCircle(
const Offset(100, 100),
50,
Paint()..color = const Color(0xFFABCDEF),
);
final Picture picture = recorder.endRecording();
builder.addPicture(const Offset(300, 300), picture);
final Scene scene = builder.build();
window.render(scene);
scene.dispose();
}
}
/// A simple platform view with one overlay and two overlays that intersect with each other and the platform view.
class PlatformViewOneOverlayTwoIntersectingOverlaysScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Creates the PlatformView scenario.
///
/// The [window] parameter must not be null.
PlatformViewOneOverlayTwoIntersectingOverlaysScenario(Window window, String text, {int id = 0})
: assert(window != null),
super(window) {
createPlatformView(window, text, id);
}
@override
void onBeginFrame(Duration duration) {
final SceneBuilder builder = SceneBuilder();
builder.pushOffset(0, 0);
_addPlatformViewtoScene(builder, 0, 500, 500);
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawCircle(
const Offset(50, 50),
50,
Paint()..color = const Color(0xFFABCDEF),
);
canvas.drawCircle(
const Offset(100, 100),
50,
Paint()..color = const Color(0xFFABCDEF),
);
canvas.drawCircle(
const Offset(-100, 200),
50,
Paint()..color = const Color(0xFFABCDEF),
);
final Picture picture = recorder.endRecording();
builder.addPicture(const Offset(300, 300), picture);
final Scene scene = builder.build();
window.render(scene);
scene.dispose();
}
}
/// Two platform views without an overlay intersecting either platform view.
class MultiPlatformViewWithoutOverlaysScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Creates the PlatformView scenario.
///
/// The [window] parameter must not be null.
MultiPlatformViewWithoutOverlaysScenario(Window window, String text, {int id = 0})
: assert(window != null),
super(window) {
createPlatformView(window, text, id);
}
@override
void onBeginFrame(Duration duration) {
final SceneBuilder builder = SceneBuilder();
builder.pushOffset(0, 0);
builder.pushOffset(0, 600);
_addPlatformViewtoScene(builder, 0, 500, 500);
builder.pop();
_addPlatformViewtoScene(builder, 1, 500, 500);
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawRect(
const Rect.fromLTRB(0, 0, 100, 1000),
Paint()..color = const Color(0xFFFF0000),
);
final Picture picture = recorder.endRecording();
builder.addPicture(const Offset(580, 0), picture);
builder.pop();
final Scene scene = builder.build();
window.render(scene);
scene.dispose();
}
}
/// A simple platform view with too many overlays result in a single native view.
class PlatformViewMaxOverlaysScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Creates the PlatformView scenario.
///
/// The [window] parameter must not be null.
PlatformViewMaxOverlaysScenario(Window window, String text, {int id = 0})
: assert(window != null),
super(window) {
createPlatformView(window, text, id);
}
@override
void onBeginFrame(Duration duration) {
final SceneBuilder builder = SceneBuilder();
builder.pushOffset(0, 0);
_addPlatformViewtoScene(builder, 0, 500, 500);
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawCircle(
const Offset(50, 50),
50,
Paint()..color = const Color(0xFFABCDEF),
);
canvas.drawCircle(
const Offset(100, 100),
50,
Paint()..color = const Color(0xFFABCDEF),
);
canvas.drawCircle(
const Offset(-100, 200),
50,
Paint()..color = const Color(0xFFABCDEF),
);
canvas.drawCircle(
const Offset(-100, -80),
50,
Paint()..color = const Color(0xFFABCDEF),
);
final Picture picture = recorder.endRecording();
builder.addPicture(const Offset(300, 300), picture);
final Scene scene = builder.build();
window.render(scene);
scene.dispose();
}
}
/// Builds a scene with 2 platform views.
class MultiPlatformViewScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Creates the PlatformView scenario.
......@@ -642,17 +424,12 @@ mixin _BasePlatformViewScenarioMixin on Scenario {
}
// Add a platform view and a picture to the scene, then finish the `sceneBuilder`.
void finishBuilderByAddingPlatformViewAndPicture(
SceneBuilder sceneBuilder,
int viewId, {
Offset overlayOffset,
}) {
overlayOffset ??= const Offset(50, 50);
void finishBuilderByAddingPlatformViewAndPicture(SceneBuilder sceneBuilder, int viewId) {
_addPlatformViewtoScene(sceneBuilder, viewId, 500, 500);
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawCircle(
overlayOffset,
const Offset(50, 50),
50,
Paint()..color = const Color(0xFFABCDEF),
);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册