From 9e1f546a85486e40f5bf49d09e621ef3cd631a49 Mon Sep 17 00:00:00 2001 From: Amir Hardon Date: Thu, 1 Nov 2018 17:45:16 -0700 Subject: [PATCH] Add an overlay surface on top of embedded UIViews. (#6726) 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) --- ci/licenses_golden/licenses_flutter | 2 + flow/embedded_views.h | 6 +- flow/layers/clip_path_layer.cc | 8 +- flow/layers/clip_rect_layer.cc | 8 +- flow/layers/clip_rrect_layer.cc | 8 +- flow/layers/layer.cc | 8 +- flow/layers/layer.h | 2 +- flow/layers/layer_tree.cc | 4 +- flow/layers/opacity_layer.cc | 12 +-- flow/layers/performance_overlay_layer.cc | 6 +- flow/layers/physical_shape_layer.cc | 18 ++--- flow/layers/picture_layer.cc | 14 ++-- flow/layers/platform_view_layer.cc | 9 ++- flow/layers/shader_mask_layer.cc | 4 +- flow/layers/texture_layer.cc | 2 +- flow/layers/transform_layer.cc | 4 +- flow/raster_cache.cc | 2 +- shell/platform/darwin/ios/BUILD.gn | 2 + .../ios/framework/Source/FlutterOverlayView.h | 28 +++++++ .../framework/Source/FlutterOverlayView.mm | 78 +++++++++++++++++++ .../framework/Source/FlutterPlatformViews.mm | 54 ++++++++++--- .../Source/FlutterPlatformViews_Internal.h | 26 ++++++- .../ios/framework/Source/FlutterView.mm | 4 +- shell/platform/darwin/ios/ios_surface.h | 6 +- shell/platform/darwin/ios/ios_surface.mm | 4 +- shell/platform/darwin/ios/ios_surface_gl.h | 4 +- shell/platform/darwin/ios/ios_surface_gl.mm | 15 ++-- .../darwin/ios/ios_surface_software.h | 4 +- .../darwin/ios/ios_surface_software.mm | 19 +++-- 29 files changed, 272 insertions(+), 89 deletions(-) create mode 100644 shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h create mode 100644 shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e854c429bbde8..fe8900faa21f0 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -597,6 +597,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatfo FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache_Internal.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 10740f6d0e23d..a36d941ee3476 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -6,6 +6,7 @@ #define FLUTTER_FLOW_EMBEDDED_VIEWS_H_ #include "flutter/fml/memory/ref_counted.h" +#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPoint.h" #include "third_party/skia/include/core/SkSize.h" @@ -15,6 +16,7 @@ class EmbeddedViewParams { public: SkPoint offsetPixels; SkSize sizePoints; + SkISize canvasBaseLayerSize; }; // This is only used on iOS when running in a non headless mode, @@ -25,8 +27,8 @@ class ExternalViewEmbedder { ExternalViewEmbedder() = default; // Must be called on the UI thread. - virtual void CompositeEmbeddedView(int view_id, - const EmbeddedViewParams& params) {} + virtual SkCanvas* CompositeEmbeddedView(int view_id, + const EmbeddedViewParams& params) = 0; virtual ~ExternalViewEmbedder() = default; diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index 3c71823c48503..0726d884472b5 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -50,14 +50,14 @@ void ClipPathLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ClipPathLayer::Paint"); FML_DCHECK(needs_painting()); - SkAutoCanvasRestore save(&context.canvas, true); - context.canvas.clipPath(clip_path_, clip_behavior_ != Clip::hardEdge); + SkAutoCanvasRestore save(context.canvas, true); + context.canvas->clipPath(clip_path_, clip_behavior_ != Clip::hardEdge); if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { - context.canvas.saveLayer(paint_bounds(), nullptr); + context.canvas->saveLayer(paint_bounds(), nullptr); } PaintChildren(context); if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { - context.canvas.restore(); + context.canvas->restore(); } } diff --git a/flow/layers/clip_rect_layer.cc b/flow/layers/clip_rect_layer.cc index 733acfcebd072..aabcf5c3e5cfc 100644 --- a/flow/layers/clip_rect_layer.cc +++ b/flow/layers/clip_rect_layer.cc @@ -41,14 +41,14 @@ void ClipRectLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ClipRectLayer::Paint"); FML_DCHECK(needs_painting()); - SkAutoCanvasRestore save(&context.canvas, true); - context.canvas.clipRect(paint_bounds(), clip_behavior_ != Clip::hardEdge); + SkAutoCanvasRestore save(context.canvas, true); + context.canvas->clipRect(paint_bounds(), clip_behavior_ != Clip::hardEdge); if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { - context.canvas.saveLayer(paint_bounds(), nullptr); + context.canvas->saveLayer(paint_bounds(), nullptr); } PaintChildren(context); if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { - context.canvas.restore(); + context.canvas->restore(); } } diff --git a/flow/layers/clip_rrect_layer.cc b/flow/layers/clip_rrect_layer.cc index 046a0d45404ef..2434e509d0910 100644 --- a/flow/layers/clip_rrect_layer.cc +++ b/flow/layers/clip_rrect_layer.cc @@ -48,14 +48,14 @@ void ClipRRectLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ClipRRectLayer::Paint"); FML_DCHECK(needs_painting()); - SkAutoCanvasRestore save(&context.canvas, true); - context.canvas.clipRRect(clip_rrect_, clip_behavior_ != Clip::hardEdge); + SkAutoCanvasRestore save(context.canvas, true); + context.canvas->clipRRect(clip_rrect_, clip_behavior_ != Clip::hardEdge); if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { - context.canvas.saveLayer(paint_bounds(), nullptr); + context.canvas->saveLayer(paint_bounds(), nullptr); } PaintChildren(context); if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { - context.canvas.restore(); + context.canvas->restore(); } } diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index c1d91872127ab..e629241d6ce8d 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -26,13 +26,13 @@ Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context, const SkRect& bounds, const SkPaint* paint) : paint_context_(paint_context), bounds_(bounds) { - paint_context_.canvas.saveLayer(bounds_, paint); + paint_context_.canvas->saveLayer(bounds_, paint); } Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context, const SkCanvas::SaveLayerRec& layer_rec) : paint_context_(paint_context), bounds_(*layer_rec.fBounds) { - paint_context_.canvas.saveLayer(layer_rec); + paint_context_.canvas->saveLayer(layer_rec); } Layer::AutoSaveLayer Layer::AutoSaveLayer::Create( @@ -50,9 +50,9 @@ Layer::AutoSaveLayer Layer::AutoSaveLayer::Create( Layer::AutoSaveLayer::~AutoSaveLayer() { if (paint_context_.checkerboard_offscreen_layers) { - DrawCheckerboard(&paint_context_.canvas, bounds_); + DrawCheckerboard(paint_context_.canvas, bounds_); } - paint_context_.canvas.restore(); + paint_context_.canvas->restore(); } } // namespace flow diff --git a/flow/layers/layer.h b/flow/layers/layer.h index dbd101d6cc9b8..098ae5f789e07 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -64,7 +64,7 @@ class Layer { virtual void Preroll(PrerollContext* context, const SkMatrix& matrix); struct PaintContext { - SkCanvas& canvas; + SkCanvas* canvas; ExternalViewEmbedder* view_embedder; const Stopwatch& frame_time; const Stopwatch& engine_time; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 6896bb112b6a1..942f5cc9a2060 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -67,7 +67,7 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache) const { TRACE_EVENT0("flutter", "LayerTree::Paint"); Layer::PaintContext context = { - *frame.canvas(), + frame.canvas(), frame.view_embedder(), frame.context().frame_time(), frame.context().engine_time(), @@ -107,7 +107,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { }; Layer::PaintContext paint_context = { - *canvas, // canvas + canvas, // canvas nullptr, unused_stopwatch, // frame time (dont care) unused_stopwatch, // engine time (dont care) diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index ebbced6f605a1..7d658b3726e1b 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -31,20 +31,20 @@ void OpacityLayer::Paint(PaintContext& context) const { SkPaint paint; paint.setAlpha(alpha_); - SkAutoCanvasRestore save(&context.canvas, true); - context.canvas.translate(offset_.fX, offset_.fY); + SkAutoCanvasRestore save(context.canvas, true); + context.canvas->translate(offset_.fX, offset_.fY); #ifndef SUPPORT_FRACTIONAL_TRANSLATION - context.canvas.setMatrix( - RasterCache::GetIntegralTransCTM(context.canvas.getTotalMatrix())); + context.canvas->setMatrix( + RasterCache::GetIntegralTransCTM(context.canvas->getTotalMatrix())); #endif if (layers().size() == 1 && context.raster_cache) { - const SkMatrix& ctm = context.canvas.getTotalMatrix(); + const SkMatrix& ctm = context.canvas->getTotalMatrix(); RasterCacheResult child_cache = context.raster_cache->Get(layers()[0].get(), ctm); if (child_cache.is_valid()) { - child_cache.draw(context.canvas, &paint); + child_cache.draw(*context.canvas, &paint); return; } } diff --git a/flow/layers/performance_overlay_layer.cc b/flow/layers/performance_overlay_layer.cc index 7d871af33b94f..9e014c57a08e5 100644 --- a/flow/layers/performance_overlay_layer.cc +++ b/flow/layers/performance_overlay_layer.cc @@ -73,14 +73,14 @@ void PerformanceOverlayLayer::Paint(PaintContext& context) const { SkScalar y = paint_bounds().y() + padding; SkScalar width = paint_bounds().width() - (padding * 2); SkScalar height = paint_bounds().height() / 2; - SkAutoCanvasRestore save(&context.canvas, true); + SkAutoCanvasRestore save(context.canvas, true); - VisualizeStopWatch(context.canvas, context.frame_time, x, y, width, + VisualizeStopWatch(*context.canvas, context.frame_time, x, y, width, height - padding, options_ & kVisualizeRasterizerStatistics, options_ & kDisplayRasterizerStatistics, "GPU"); - VisualizeStopWatch(context.canvas, context.engine_time, x, y + height, width, + VisualizeStopWatch(*context.canvas, context.engine_time, x, y + height, width, height - padding, options_ & kVisualizeEngineStatistics, options_ & kDisplayEngineStatistics, "UI"); } diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index e10caaa56feed..6490413d62bc9 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -83,7 +83,7 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { FML_DCHECK(needs_painting()); if (elevation_ != 0) { - DrawShadow(&context.canvas, path_, shadow_color_, elevation_, + DrawShadow(context.canvas, path_, shadow_color_, elevation_, SkColorGetA(color_) != 0xff, device_pixel_ratio_); } @@ -91,20 +91,20 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { SkPaint paint; paint.setColor(color_); if (clip_behavior_ != Clip::antiAliasWithSaveLayer) { - context.canvas.drawPath(path_, paint); + context.canvas->drawPath(path_, paint); } - int saveCount = context.canvas.save(); + int saveCount = context.canvas->save(); switch (clip_behavior_) { case Clip::hardEdge: - context.canvas.clipPath(path_, false); + context.canvas->clipPath(path_, false); break; case Clip::antiAlias: - context.canvas.clipPath(path_, true); + context.canvas->clipPath(path_, true); break; case Clip::antiAliasWithSaveLayer: - context.canvas.clipPath(path_, true); - context.canvas.saveLayer(paint_bounds(), nullptr); + context.canvas->clipPath(path_, true); + context.canvas->saveLayer(paint_bounds(), nullptr); break; case Clip::none: break; @@ -115,12 +115,12 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { // (https://github.com/flutter/flutter/issues/18057#issue-328003931) // using saveLayer, we have to call drawPaint instead of drawPath as // anti-aliased drawPath will always have such artifacts. - context.canvas.drawPaint(paint); + context.canvas->drawPaint(paint); } PaintChildren(context); - context.canvas.restoreToCount(saveCount); + context.canvas->restoreToCount(saveCount); } void PhysicalShapeLayer::DrawShadow(SkCanvas* canvas, diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index 9dcef880b7313..412859b689ea9 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -34,22 +34,22 @@ void PictureLayer::Paint(PaintContext& context) const { FML_DCHECK(picture_.get()); FML_DCHECK(needs_painting()); - SkAutoCanvasRestore save(&context.canvas, true); - context.canvas.translate(offset_.x(), offset_.y()); + SkAutoCanvasRestore save(context.canvas, true); + context.canvas->translate(offset_.x(), offset_.y()); #ifndef SUPPORT_FRACTIONAL_TRANSLATION - context.canvas.setMatrix( - RasterCache::GetIntegralTransCTM(context.canvas.getTotalMatrix())); + context.canvas->setMatrix( + RasterCache::GetIntegralTransCTM(context.canvas->getTotalMatrix())); #endif if (context.raster_cache) { - const SkMatrix& ctm = context.canvas.getTotalMatrix(); + const SkMatrix& ctm = context.canvas->getTotalMatrix(); RasterCacheResult result = context.raster_cache->Get(*picture(), ctm); if (result.is_valid()) { - result.draw(context.canvas); + result.draw(*context.canvas); return; } } - context.canvas.drawPicture(picture()); + context.canvas->drawPicture(picture()); } } // namespace flow diff --git a/flow/layers/platform_view_layer.cc b/flow/layers/platform_view_layer.cc index 19057fbfd4b9c..efcddbcc98175 100644 --- a/flow/layers/platform_view_layer.cc +++ b/flow/layers/platform_view_layer.cc @@ -23,11 +23,16 @@ void PlatformViewLayer::Paint(PaintContext& context) const { return; } EmbeddedViewParams params; - SkMatrix transform = context.canvas.getTotalMatrix(); + SkMatrix transform = context.canvas->getTotalMatrix(); params.offsetPixels = SkPoint::Make(transform.getTranslateX(), transform.getTranslateY()); params.sizePoints = size_; + params.canvasBaseLayerSize = context.canvas->getBaseLayerSize(); - context.view_embedder->CompositeEmbeddedView(view_id_, params); + SkCanvas* canvas = + context.view_embedder->CompositeEmbeddedView(view_id_, params); + // TODO(amirh): copy the full canvas state here + canvas->concat(context.canvas->getTotalMatrix()); + context.canvas = canvas; } } // namespace flow diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index 6cb73bbf64855..f87cce48b89ff 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -21,8 +21,8 @@ void ShaderMaskLayer::Paint(PaintContext& context) const { SkPaint paint; paint.setBlendMode(blend_mode_); paint.setShader(shader_); - context.canvas.translate(mask_rect_.left(), mask_rect_.top()); - context.canvas.drawRect( + context.canvas->translate(mask_rect_.left(), mask_rect_.top()); + context.canvas->drawRect( SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()), paint); } diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index 52ebdc37dbcab..cb9f63249b73e 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -23,7 +23,7 @@ void TextureLayer::Paint(PaintContext& context) const { if (!texture) { return; } - texture->Paint(context.canvas, paint_bounds(), freeze_); + texture->Paint(*context.canvas, paint_bounds(), freeze_); } } // namespace flow diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index a70cc299dd9a4..a96e0e27d7560 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -36,8 +36,8 @@ void TransformLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "TransformLayer::Paint"); FML_DCHECK(needs_painting()); - SkAutoCanvasRestore save(&context.canvas, true); - context.canvas.concat(transform_); + SkAutoCanvasRestore save(context.canvas, true); + context.canvas->concat(transform_); PaintChildren(context); } diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index d20c65df5b1ff..a92e1285379a7 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -157,7 +157,7 @@ void RasterCache::Prepare(PrerollContext* context, checkerboard_images_, layer->paint_bounds(), [layer, context](SkCanvas* canvas) { Layer::PaintContext paintContext = { - *canvas, + canvas, nullptr, context->frame_time, context->engine_time, diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 15a14ad82bea4..80c2e31bd05f0 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -57,6 +57,8 @@ shared_library("create_flutter_framework_dylib") { "framework/Source/FlutterHeadlessDartRunner.mm", "framework/Source/FlutterObservatoryPublisher.h", "framework/Source/FlutterObservatoryPublisher.mm", + "framework/Source/FlutterOverlayView.h", + "framework/Source/FlutterOverlayView.mm", "framework/Source/FlutterPlatformPlugin.h", "framework/Source/FlutterPlatformPlugin.mm", "framework/Source/FlutterPlatformViews_Internal.h", diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h new file mode 100644 index 0000000000000..527253fb73648 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h @@ -0,0 +1,28 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_OVERLAY_VIEW_H_ +#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_OVERLAY_VIEW_H_ + +#include + +#include + +#import "FlutterPlatformViews_Internal.h" + +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/platform/darwin/ios/ios_surface.h" + +@interface FlutterOverlayView : UIView + +- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; +- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; + +- (instancetype)init NS_DESIGNATED_INITIALIZER; +- (std::unique_ptr)createSurface; + +@end + +#endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_OVERLAY_VIEW_H_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm new file mode 100644 index 0000000000000..9ed7c71ca9d72 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -0,0 +1,78 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h" + +#include "flutter/common/settings.h" +#include "flutter/common/task_runners.h" +#include "flutter/flow/layers/layer_tree.h" +#include "flutter/fml/platform/darwin/cf_utils.h" +#include "flutter/fml/synchronization/waitable_event.h" +#include "flutter/fml/trace_event.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" +#include "flutter/shell/platform/darwin/ios/ios_surface_software.h" +#include "third_party/skia/include/utils/mac/SkCGUtils.h" + +// This is mostly a duplication of FlutterView. +// TODO(amirh): once GL support is in evaluate if we can merge this with FlutterView. +@implementation FlutterOverlayView + +- (instancetype)initWithFrame:(CGRect)frame { + @throw([NSException exceptionWithName:@"FlutterOverlayView must initWithDelegate" + reason:nil + userInfo:nil]); +} + +- (instancetype)initWithCoder:(NSCoder*)aDecoder { + @throw([NSException exceptionWithName:@"FlutterOverlayView must initWithDelegate" + reason:nil + userInfo:nil]); +} + +- (instancetype)init { + self = [super initWithFrame:CGRectZero]; + + if (self) { + self.layer.opaque = NO; + self.userInteractionEnabled = NO; + } + + return self; +} + +- (void)layoutSubviews { + if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { + CAEAGLLayer* layer = reinterpret_cast(self.layer); + layer.allowsGroupOpacity = NO; + CGFloat screenScale = [UIScreen mainScreen].scale; + layer.contentsScale = screenScale; + layer.rasterizationScale = screenScale; + } + + [super layoutSubviews]; +} + ++ (Class)layerClass { +#if TARGET_IPHONE_SIMULATOR + return [CALayer class]; +#else // TARGET_IPHONE_SIMULATOR + return [CAEAGLLayer class]; +#endif // TARGET_IPHONE_SIMULATOR +} + +- (std::unique_ptr)createSurface { + if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { + // TODO(amirh): create a GL surface. + return nullptr; + } else { + fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); + return std::make_unique(std::move(layer), nullptr); + } +} + +// TODO(amirh): implement drawLayer to suppoer snapshotting. + +@end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 2f4cefa84d5d0..798839fab4d1c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import + +#import "FlutterOverlayView.h" +#import "flutter/shell/platform/darwin/ios/ios_surface.h" + #include #include #include @@ -10,8 +15,6 @@ #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterChannels.h" -#import - namespace shell { void FlutterPlatformViewsController::SetFlutterView(UIView* flutter_view) { @@ -45,7 +48,7 @@ long viewId = [args[@"id"] longValue]; std::string viewType([args[@"viewType"] UTF8String]); - if (views_[viewId] != nil) { + if (views_.count(viewId) != 0) { result([FlutterError errorWithCode:@"recreating_view" message:@"trying to create an already created view" details:[NSString stringWithFormat:@"view id: '%ld'", viewId]]); @@ -84,7 +87,7 @@ NSDictionary* args = [call arguments]; int64_t viewId = [args[@"id"] longLongValue]; - if (views_[viewId] == nil) { + if (views_.count(viewId) == 0) { result([FlutterError errorWithCode:@"unknown_view" message:@"trying to dispose an unknown" details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); @@ -94,6 +97,7 @@ UIView* view = views_[viewId].get(); [view removeFromSuperview]; views_.erase(viewId); + overlays_.erase(viewId); result(nil); } @@ -102,7 +106,7 @@ NSDictionary* args = [call arguments]; int64_t viewId = [args[@"id"] longLongValue]; - if (views_[viewId] == nil) { + if (views_.count(viewId) == 0) { result([FlutterError errorWithCode:@"unknown_view" message:@"trying to set gesture state for an unknown view" details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); @@ -124,25 +128,39 @@ fml::scoped_nsobject>([factory retain]); } -void FlutterPlatformViewsController::CompositeEmbeddedView(int view_id, - const flow::EmbeddedViewParams& params) { +SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView( + int view_id, + const flow::EmbeddedViewParams& params, + IOSSurface& ios_surface) { // TODO(amirh): assert that this is running on the platform thread once we support the iOS // embedded views thread configuration. // TODO(amirh): do nothing if the params didn't change. + EnsureOverlayInitialized(view_id); CGFloat screenScale = [[UIScreen mainScreen] scale]; CGRect rect = CGRectMake(params.offsetPixels.x() / screenScale, params.offsetPixels.y() / screenScale, params.sizePoints.width(), params.sizePoints.height()); - UIView* view = views_[view_id]; + UIView* view = views_[view_id].get(); [view setFrame:rect]; composition_order_.push_back(view_id); + + composition_frames_.push_back( + overlays_[view_id]->surface->AcquireFrame(params.canvasBaseLayerSize)); + SkCanvas* canvas = composition_frames_.back()->SkiaCanvas(); + canvas->clear(SK_ColorTRANSPARENT); + return canvas; } -void FlutterPlatformViewsController::Present() { +bool FlutterPlatformViewsController::Present() { + bool did_submit = true; + for (size_t i = 0; i < composition_frames_.size(); i++) { + did_submit &= composition_frames_[i]->Submit(); + } + composition_frames_.clear(); if (composition_order_ == active_composition_order_) { composition_order_.clear(); - return; + return did_submit; } UIView* flutter_view = flutter_view_.get(); @@ -159,10 +177,26 @@ for (size_t i = 0; i < composition_order_.size(); i++) { int view_id = composition_order_[i]; [flutter_view addSubview:views_[view_id].get()]; + [flutter_view addSubview:overlays_[view_id]->overlay_view.get()]; active_composition_order_.push_back(view_id); } composition_order_.clear(); + return did_submit; +} + +void FlutterPlatformViewsController::EnsureOverlayInitialized(int64_t overlay_id) { + if (overlays_.count(overlay_id) != 0) { + return; + } + FlutterOverlayView* overlay_view = [[FlutterOverlayView alloc] init]; + overlay_view.frame = flutter_view_.get().bounds; + overlay_view.autoresizingMask = + (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + std::unique_ptr ios_surface = overlay_view.createSurface; + std::unique_ptr surface = ios_surface->CreateGPUSurface(); + overlays_[overlay_id] = std::make_unique( + overlay_view, std::move(ios_surface), std::move(surface)); } } // namespace shell diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 3a749a11d0d3f..92d308c244d43 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -26,6 +26,21 @@ namespace shell { +class IOSSurface; + +struct FlutterPlatformViewLayer { + FlutterPlatformViewLayer(UIView* overlay_view, + std::unique_ptr ios_surface, + std::unique_ptr surface) + : overlay_view([overlay_view retain]), + ios_surface(std::move(ios_surface)), + surface(std::move(surface)){}; + + fml::scoped_nsobject overlay_view; + std::unique_ptr ios_surface; + std::unique_ptr surface; +}; + class FlutterPlatformViewsController { public: FlutterPlatformViewsController() = default; @@ -34,9 +49,11 @@ class FlutterPlatformViewsController { void RegisterViewFactory(NSObject* factory, NSString* factoryId); - void CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params); + SkCanvas* CompositeEmbeddedView(int view_id, + const flow::EmbeddedViewParams& params, + IOSSurface& surface); - void Present(); + bool Present(); void OnMethodCall(FlutterMethodCall* call, FlutterResult& result); @@ -45,6 +62,7 @@ class FlutterPlatformViewsController { fml::scoped_nsobject flutter_view_; std::map>> factories_; std::map> views_; + std::map> overlays_; // A vector of embedded view IDs according to their composition order. // The last ID in this vector belond to the that is composited on top of all others. @@ -53,10 +71,14 @@ class FlutterPlatformViewsController { // The latest composition order that was presented in Present(). std::vector active_composition_order_; + std::vector> composition_frames_; + void OnCreate(FlutterMethodCall* call, FlutterResult& result); void OnDispose(FlutterMethodCall* call, FlutterResult& result); void OnAcceptGesture(FlutterMethodCall* call, FlutterResult& result); + void EnsureOverlayInitialized(int64_t overlay_id); + FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewsController); }; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.mm b/shell/platform/darwin/ios/framework/Source/FlutterView.mm index 3909f6367ee2e..b64fe4c2488a2 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -80,11 +80,11 @@ + (Class)layerClass { fml::scoped_nsobject eagl_layer( reinterpret_cast([self.layer retain])); return std::make_unique(std::move(eagl_layer), - *[_delegate platformViewsController]); + [_delegate platformViewsController]); } else { fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); return std::make_unique(std::move(layer), - *[_delegate platformViewsController]); + [_delegate platformViewsController]); } } diff --git a/shell/platform/darwin/ios/ios_surface.h b/shell/platform/darwin/ios/ios_surface.h index f0f835e684342..52711f1e68b6a 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -17,7 +17,7 @@ namespace shell { class IOSSurface { public: - IOSSurface(FlutterPlatformViewsController& platform_views_controller); + IOSSurface(FlutterPlatformViewsController* platform_views_controller); virtual ~IOSSurface(); @@ -30,10 +30,10 @@ class IOSSurface { virtual std::unique_ptr CreateGPUSurface() = 0; protected: - FlutterPlatformViewsController& GetPlatformViewsController(); + FlutterPlatformViewsController* GetPlatformViewsController(); private: - FlutterPlatformViewsController& platform_views_controller_; + FlutterPlatformViewsController* platform_views_controller_; public: FML_DISALLOW_COPY_AND_ASSIGN(IOSSurface); diff --git a/shell/platform/darwin/ios/ios_surface.mm b/shell/platform/darwin/ios/ios_surface.mm index 1a62e70e59b15..ba7bf4f93ed3f 100644 --- a/shell/platform/darwin/ios/ios_surface.mm +++ b/shell/platform/darwin/ios/ios_surface.mm @@ -11,12 +11,12 @@ namespace shell { -IOSSurface::IOSSurface(FlutterPlatformViewsController& platform_views_controller) +IOSSurface::IOSSurface(FlutterPlatformViewsController* platform_views_controller) : platform_views_controller_(platform_views_controller) {} IOSSurface::~IOSSurface() = default; -FlutterPlatformViewsController& IOSSurface::GetPlatformViewsController() { +FlutterPlatformViewsController* IOSSurface::GetPlatformViewsController() { return platform_views_controller_; } } // namespace shell diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index a2765890eb3bd..a6bcfbdf45d46 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -20,7 +20,7 @@ class IOSSurfaceGL : public IOSSurface, public flow::ExternalViewEmbedder { public: IOSSurfaceGL(fml::scoped_nsobject layer, - FlutterPlatformViewsController& platform_views_controller); + FlutterPlatformViewsController* platform_views_controller); ~IOSSurfaceGL() override; @@ -46,7 +46,7 @@ class IOSSurfaceGL : public IOSSurface, flow::ExternalViewEmbedder* GetExternalViewEmbedder() override; // |flow::ExternalViewEmbedder| - void CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override; + SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override; private: IOSGLContext context_; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index b65015e4d56d1..24f2a3af67c1d 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -10,7 +10,7 @@ namespace shell { IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, - FlutterPlatformViewsController& platform_views_controller) + FlutterPlatformViewsController* platform_views_controller) : IOSSurface(platform_views_controller), context_(std::move(layer)) {} IOSSurfaceGL::~IOSSurfaceGL() = default; @@ -59,16 +59,21 @@ return false; } - GetPlatformViewsController().Present(); - return true; + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + if (platform_views_controller == nullptr) { + return true; + } + return platform_views_controller->Present(); } flow::ExternalViewEmbedder* IOSSurfaceGL::GetExternalViewEmbedder() { return this; } -void IOSSurfaceGL::CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) { - GetPlatformViewsController().CompositeEmbeddedView(view_id, params); +SkCanvas* IOSSurfaceGL::CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + return platform_views_controller->CompositeEmbeddedView(view_id, params, *this); } } // namespace shell diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index 6abfeecf0b17c..2e5da95e2b48f 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -20,7 +20,7 @@ class IOSSurfaceSoftware final : public IOSSurface, public flow::ExternalViewEmbedder { public: IOSSurfaceSoftware(fml::scoped_nsobject layer, - FlutterPlatformViewsController& platform_views_controller); + FlutterPlatformViewsController* platform_views_controller); ~IOSSurfaceSoftware() override; @@ -46,7 +46,7 @@ class IOSSurfaceSoftware final : public IOSSurface, flow::ExternalViewEmbedder* GetExternalViewEmbedder() override; // |flow::ExternalViewEmbedder| - void CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override; + SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override; private: fml::scoped_nsobject layer_; diff --git a/shell/platform/darwin/ios/ios_surface_software.mm b/shell/platform/darwin/ios/ios_surface_software.mm index 2c561b78c397b..a35d806729b83 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -16,7 +16,7 @@ namespace shell { IOSSurfaceSoftware::IOSSurfaceSoftware(fml::scoped_nsobject layer, - FlutterPlatformViewsController& platform_views_controller) + FlutterPlatformViewsController* platform_views_controller) : IOSSurface(platform_views_controller), layer_(std::move(layer)) { UpdateStorageSizeIfNecessary(); } @@ -123,17 +123,22 @@ layer_.get().contents = reinterpret_cast(static_cast(pixmap_image)); - GetPlatformViewsController().Present(); - - return true; + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + if (platform_views_controller == nullptr) { + return true; + } + return platform_views_controller->Present(); } flow::ExternalViewEmbedder* IOSSurfaceSoftware::GetExternalViewEmbedder() { return this; } -void IOSSurfaceSoftware::CompositeEmbeddedView(int view_id, - const flow::EmbeddedViewParams& params) { - GetPlatformViewsController().CompositeEmbeddedView(view_id, params); + +SkCanvas* IOSSurfaceSoftware::CompositeEmbeddedView(int view_id, + const flow::EmbeddedViewParams& params) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + return platform_views_controller->CompositeEmbeddedView(view_id, params, *this); } } // namespace shell