Skip to content

Commit 387ca2e

Browse files
authored
Add an internal_nodes_canvas to PaintContext. (#6728)
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.
1 parent 22fc020 commit 387ca2e

14 files changed

+147
-14
lines changed

flow/embedded_views.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ class EmbeddedViewParams {
1616
public:
1717
SkPoint offsetPixels;
1818
SkSize sizePoints;
19-
SkISize canvasBaseLayerSize;
2019
};
2120

2221
// This is only used on iOS when running in a non headless mode,
@@ -26,6 +25,12 @@ class ExternalViewEmbedder {
2625
public:
2726
ExternalViewEmbedder() = default;
2827

28+
virtual void SetFrameSize(SkISize frame_size) = 0;
29+
30+
virtual void PrerollCompositeEmbeddedView(int view_id) = 0;
31+
32+
virtual std::vector<SkCanvas*> GetCurrentCanvases() = 0;
33+
2934
// Must be called on the UI thread.
3035
virtual SkCanvas* CompositeEmbeddedView(int view_id,
3136
const EmbeddedViewParams& params) = 0;

flow/layers/layer.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "third_party/skia/include/core/SkPicture.h"
2626
#include "third_party/skia/include/core/SkRRect.h"
2727
#include "third_party/skia/include/core/SkRect.h"
28+
#include "third_party/skia/include/utils/SkNWayCanvas.h"
2829

2930
#if defined(OS_FUCHSIA)
3031

@@ -44,6 +45,7 @@ class ContainerLayer;
4445
struct PrerollContext {
4546
RasterCache* raster_cache;
4647
GrContext* gr_context;
48+
ExternalViewEmbedder* view_embedder;
4749
SkColorSpace* dst_color_space;
4850
SkRect child_paint_bounds;
4951

@@ -64,6 +66,21 @@ class Layer {
6466
virtual void Preroll(PrerollContext* context, const SkMatrix& matrix);
6567

6668
struct PaintContext {
69+
// When splitting the scene into multiple canvases (e.g when embedding
70+
// a platform view on iOS) during the paint traversal we apply the non leaf
71+
// flow layers to all canvases, and leaf layers just to the "current"
72+
// canvas. Applying the non leaf layers to all canvases ensures that when
73+
// we switch a canvas (when painting a PlatformViewLayer) the next canvas
74+
// has the exact same state as the current canvas.
75+
// The internal_nodes_canvas is a SkNWayCanvas which is used by non leaf
76+
// and applies the operations to all canvases.
77+
// The leaf_nodes_canvas is the "current" canvas and is used by leaf
78+
// layers.
79+
SkCanvas* internal_nodes_canvas;
80+
// I'm temporarily leaving the name of this field to be canvas to reduce
81+
// noise in the incremental change. A followup change will rename this
82+
// and use the corrrect canvas in each callsite.
83+
// TODO(amirh) rename canvas to leaf_nodes_canvas.
6784
SkCanvas* canvas;
6885
ExternalViewEmbedder* view_embedder;
6986
const Stopwatch& frame_time;

flow/layers/layer_tree.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "flutter/flow/layers/layer.h"
88
#include "flutter/fml/trace_event.h"
99
#include "third_party/skia/include/core/SkPictureRecorder.h"
10+
#include "third_party/skia/include/utils/SkNWayCanvas.h"
1011

1112
namespace flow {
1213

@@ -28,6 +29,7 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
2829
PrerollContext context = {
2930
ignore_raster_cache ? nullptr : &frame.context().raster_cache(),
3031
frame.gr_context(),
32+
frame.view_embedder(),
3133
color_space,
3234
SkRect::MakeEmpty(),
3335
frame.context().frame_time(),
@@ -66,7 +68,18 @@ void LayerTree::UpdateScene(SceneUpdateContext& context,
6668
void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
6769
bool ignore_raster_cache) const {
6870
TRACE_EVENT0("flutter", "LayerTree::Paint");
71+
SkISize canvas_size = frame.canvas()->getBaseLayerSize();
72+
SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height());
73+
internal_nodes_canvas.addCanvas(frame.canvas());
74+
if (frame.view_embedder() != nullptr) {
75+
auto overlay_canvases = frame.view_embedder()->GetCurrentCanvases();
76+
for (size_t i = 0; i < overlay_canvases.size(); i++) {
77+
internal_nodes_canvas.addCanvas(overlay_canvases[i]);
78+
}
79+
}
80+
6981
Layer::PaintContext context = {
82+
(SkCanvas*)&internal_nodes_canvas,
7083
frame.canvas(),
7184
frame.view_embedder(),
7285
frame.context().frame_time(),
@@ -98,6 +111,7 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
98111
PrerollContext preroll_context{
99112
nullptr, // raster_cache (don't consult the cache)
100113
nullptr, // gr_context (used for the raster cache)
114+
nullptr, // external view embedder
101115
nullptr, // SkColorSpace* dst_color_space
102116
SkRect::MakeEmpty(), // SkRect child_paint_bounds
103117
unused_stopwatch, // frame time (dont care)
@@ -106,7 +120,12 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
106120
false, // checkerboard_offscreen_layers
107121
};
108122

123+
SkISize canvas_size = canvas->getBaseLayerSize();
124+
SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height());
125+
internal_nodes_canvas.addCanvas(canvas);
126+
109127
Layer::PaintContext paint_context = {
128+
(SkCanvas*)&internal_nodes_canvas,
110129
canvas, // canvas
111130
nullptr,
112131
unused_stopwatch, // frame time (dont care)

flow/layers/platform_view_layer.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ void PlatformViewLayer::Preroll(PrerollContext* context,
1414
const SkMatrix& matrix) {
1515
set_paint_bounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(),
1616
size_.height()));
17+
18+
if (context->view_embedder == nullptr) {
19+
FML_LOG(ERROR) << "Trying to embed a platform view but the PrerollContext "
20+
"does not support embedding";
21+
return;
22+
}
23+
context->view_embedder->PrerollCompositeEmbeddedView(view_id_);
1724
}
1825

1926
void PlatformViewLayer::Paint(PaintContext& context) const {
@@ -27,12 +34,9 @@ void PlatformViewLayer::Paint(PaintContext& context) const {
2734
params.offsetPixels =
2835
SkPoint::Make(transform.getTranslateX(), transform.getTranslateY());
2936
params.sizePoints = size_;
30-
params.canvasBaseLayerSize = context.canvas->getBaseLayerSize();
3137

3238
SkCanvas* canvas =
3339
context.view_embedder->CompositeEmbeddedView(view_id_, params);
34-
// TODO(amirh): copy the full canvas state here
35-
canvas->concat(context.canvas->getTotalMatrix());
3640
context.canvas = canvas;
3741
}
3842
} // namespace flow

flow/layers/transform_layer.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ void TransformLayer::Paint(PaintContext& context) const {
3636
TRACE_EVENT0("flutter", "TransformLayer::Paint");
3737
FML_DCHECK(needs_painting());
3838

39-
SkAutoCanvasRestore save(context.canvas, true);
40-
context.canvas->concat(transform_);
39+
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
40+
context.internal_nodes_canvas->concat(transform_);
4141
PaintChildren(context);
4242
}
4343

flow/raster_cache.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,12 @@ void RasterCache::Prepare(PrerollContext* context,
156156
entry.image = Rasterize(context->gr_context, ctm, context->dst_color_space,
157157
checkerboard_images_, layer->paint_bounds(),
158158
[layer, context](SkCanvas* canvas) {
159+
SkISize canvas_size = canvas->getBaseLayerSize();
160+
SkNWayCanvas internal_nodes_canvas(
161+
canvas_size.width(), canvas_size.height());
162+
internal_nodes_canvas.addCanvas(canvas);
159163
Layer::PaintContext paintContext = {
164+
(SkCanvas*)&internal_nodes_canvas,
160165
canvas,
161166
nullptr,
162167
context->frame_time,

flow/scene_update_context.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) {
188188
FML_DCHECK(task.surface);
189189
SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas();
190190
Layer::PaintContext context = {canvas,
191+
canvas,
191192
nullptr,
192193
frame.context().frame_time(),
193194
frame.context().engine_time(),

shell/common/rasterizer.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) {
164164

165165
auto external_view_embedder = surface_->GetExternalViewEmbedder();
166166

167+
// TODO(amirh): uncomment this once external_view_embedder is populated.
168+
// if (external_view_embedder != nullptr) {
169+
// external_view_embedder->SetFrameSize(layer_tree.frame_size());
170+
// }
171+
167172
auto compositor_frame = compositor_context_->AcquireFrame(
168173
surface_->GetContext(), canvas, external_view_embedder,
169174
surface_->GetRootTransformation(), true);

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,34 +128,50 @@
128128
fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>([factory retain]);
129129
}
130130

131+
void FlutterPlatformViewsController::SetFrameSize(SkISize frame_size) {
132+
frame_size_ = frame_size;
133+
}
134+
135+
void FlutterPlatformViewsController::PrerollCompositeEmbeddedView(int view_id) {
136+
EnsureOverlayInitialized(view_id);
137+
composition_frames_[view_id] = (overlays_[view_id]->surface->AcquireFrame(frame_size_));
138+
composition_order_.push_back(view_id);
139+
}
140+
141+
std::vector<SkCanvas*> FlutterPlatformViewsController::GetCurrentCanvases() {
142+
std::vector<SkCanvas*> canvases;
143+
for (size_t i = 0; i < composition_order_.size(); i++) {
144+
int64_t view_id = composition_order_[i];
145+
canvases.push_back(composition_frames_[view_id]->SkiaCanvas());
146+
}
147+
return canvases;
148+
}
149+
131150
SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(
132151
int view_id,
133152
const flow::EmbeddedViewParams& params,
134153
IOSSurface& ios_surface) {
135154
// TODO(amirh): assert that this is running on the platform thread once we support the iOS
136155
// embedded views thread configuration.
137156
// TODO(amirh): do nothing if the params didn't change.
138-
EnsureOverlayInitialized(view_id);
139157
CGFloat screenScale = [[UIScreen mainScreen] scale];
140158
CGRect rect =
141159
CGRectMake(params.offsetPixels.x() / screenScale, params.offsetPixels.y() / screenScale,
142160
params.sizePoints.width(), params.sizePoints.height());
143161

144162
UIView* view = views_[view_id].get();
145163
[view setFrame:rect];
146-
composition_order_.push_back(view_id);
147164

148-
composition_frames_.push_back(
149-
overlays_[view_id]->surface->AcquireFrame(params.canvasBaseLayerSize));
150-
SkCanvas* canvas = composition_frames_.back()->SkiaCanvas();
165+
SkCanvas* canvas = composition_frames_[view_id]->SkiaCanvas();
151166
canvas->clear(SK_ColorTRANSPARENT);
152167
return canvas;
153168
}
154169

155170
bool FlutterPlatformViewsController::Present() {
156171
bool did_submit = true;
157-
for (size_t i = 0; i < composition_frames_.size(); i++) {
158-
did_submit &= composition_frames_[i]->Submit();
172+
for (size_t i = 0; i < composition_order_.size(); i++) {
173+
int64_t view_id = composition_order_[i];
174+
did_submit &= composition_frames_[view_id]->Submit();
159175
}
160176
composition_frames_.clear();
161177
if (composition_order_ == active_composition_order_) {

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ class FlutterPlatformViewsController {
4949

5050
void RegisterViewFactory(NSObject<FlutterPlatformViewFactory>* factory, NSString* factoryId);
5151

52+
void SetFrameSize(SkISize frame_size);
53+
54+
void PrerollCompositeEmbeddedView(int view_id);
55+
56+
std::vector<SkCanvas*> GetCurrentCanvases();
57+
5258
SkCanvas* CompositeEmbeddedView(int view_id,
5359
const flow::EmbeddedViewParams& params,
5460
IOSSurface& surface);
@@ -63,6 +69,7 @@ class FlutterPlatformViewsController {
6369
std::map<std::string, fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>> factories_;
6470
std::map<int64_t, fml::scoped_nsobject<FlutterTouchInterceptingView>> views_;
6571
std::map<int64_t, std::unique_ptr<FlutterPlatformViewLayer>> overlays_;
72+
SkISize frame_size_;
6673

6774
// A vector of embedded view IDs according to their composition order.
6875
// The last ID in this vector belond to the that is composited on top of all others.
@@ -71,7 +78,7 @@ class FlutterPlatformViewsController {
7178
// The latest composition order that was presented in Present().
7279
std::vector<int64_t> active_composition_order_;
7380

74-
std::vector<std::unique_ptr<SurfaceFrame>> composition_frames_;
81+
std::map<int64_t, std::unique_ptr<SurfaceFrame>> composition_frames_;
7582

7683
void OnCreate(FlutterMethodCall* call, FlutterResult& result);
7784
void OnDispose(FlutterMethodCall* call, FlutterResult& result);

0 commit comments

Comments
 (0)