Flutter Engine
The Flutter Engine
external_view_embedder.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h"
6#include "flutter/common/constants.h"
7#include "flutter/fml/synchronization/waitable_event.h"
8#include "flutter/fml/trace_event.h"
9
10namespace flutter {
11
13 const AndroidContext& android_context,
14 std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
15 std::shared_ptr<AndroidSurfaceFactory> surface_factory,
16 const TaskRunners& task_runners)
18 android_context_(android_context),
19 jni_facade_(std::move(jni_facade)),
20 surface_factory_(std::move(surface_factory)),
21 surface_pool_(std::make_unique<SurfacePool>()),
22 task_runners_(task_runners) {}
23
24// |ExternalViewEmbedder|
26 int64_t view_id,
27 std::unique_ptr<EmbeddedViewParams> params) {
28 TRACE_EVENT0("flutter",
29 "AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView");
30
31 SkRect view_bounds = SkRect::Make(frame_size_);
32 std::unique_ptr<EmbedderViewSlice> view;
33 view = std::make_unique<DisplayListEmbedderViewSlice>(view_bounds);
34 slices_.insert_or_assign(view_id, std::move(view));
35
36 composition_order_.push_back(view_id);
37 // Update params only if they changed.
38 if (view_params_.count(view_id) == 1 &&
39 view_params_.at(view_id) == *params.get()) {
40 return;
41 }
42 view_params_.insert_or_assign(view_id, EmbeddedViewParams(*params.get()));
43}
44
45// |ExternalViewEmbedder|
47 if (slices_.count(view_id) == 1) {
48 return slices_.at(view_id)->canvas();
49 }
50 return nullptr;
51}
52
54 const EmbeddedViewParams& params = view_params_.at(view_id);
55 // TODO(egarciad): The rect should be computed from the mutator stack.
56 // (Clipping is missing)
57 // https://github.com/flutter/flutter/issues/59821
58 return SkRect::MakeXYWH(params.finalBoundingRect().x(), //
59 params.finalBoundingRect().y(), //
60 params.finalBoundingRect().width(), //
61 params.finalBoundingRect().height() //
62 );
63}
64
65// |ExternalViewEmbedder|
67 int64_t flutter_view_id,
68 GrDirectContext* context,
69 const std::shared_ptr<impeller::AiksContext>& aiks_context,
70 std::unique_ptr<SurfaceFrame> frame) {
71 TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder::SubmitFlutterView");
72 // TODO(dkwingsmt): This class only supports rendering into the implicit view.
73 // Properly support multi-view in the future.
74 FML_DCHECK(flutter_view_id == kFlutterImplicitViewId);
75
76 if (!FrameHasPlatformLayers()) {
77 frame->Submit();
78 return;
79 }
80
81 std::unordered_map<int64_t, SkRect> overlay_layers;
82 DlCanvas* background_canvas = frame->Canvas();
83 auto current_frame_view_count = composition_order_.size();
84
85 // Restore the clip context after exiting this method since it's changed
86 // below.
87 DlAutoCanvasRestore save(background_canvas, /*do_save=*/true);
88
89 for (size_t i = 0; i < current_frame_view_count; i++) {
90 int64_t view_id = composition_order_[i];
91 EmbedderViewSlice* slice = slices_.at(view_id).get();
92 if (slice->canvas() == nullptr) {
93 continue;
94 }
95
96 slice->end_recording();
97
98 SkRect full_joined_rect = SkRect::MakeEmpty();
99
100 // Determinate if Flutter UI intersects with any of the previous
101 // platform views stacked by z position.
102 //
103 // This is done by querying the r-tree that holds the records for the
104 // picture recorder corresponding to the flow layers added after a platform
105 // view layer.
106 for (ssize_t j = i; j >= 0; j--) {
107 int64_t current_view_id = composition_order_[j];
108 SkRect current_view_rect = GetViewRect(current_view_id);
109 // The rect above the `current_view_rect`
110 SkRect partial_joined_rect = SkRect::MakeEmpty();
111 // Each rect corresponds to a native view that renders Flutter UI.
112 std::vector<SkIRect> intersection_rects =
113 slice->region(current_view_rect).getRects();
114
115 // Limit the number of native views, so it doesn't grow forever.
116 //
117 // In this case, the rects are merged into a single one that is the union
118 // of all the rects.
119 for (const SkIRect& rect : intersection_rects) {
120 partial_joined_rect.join(SkRect::Make(rect));
121 }
122 // Get the intersection rect with the `current_view_rect`,
123 partial_joined_rect.intersect(current_view_rect);
124 // Join the `partial_joined_rect` into `full_joined_rect` to get the rect
125 // above the current `slice`
126 full_joined_rect.join(partial_joined_rect);
127 }
128 if (!full_joined_rect.isEmpty()) {
129 // Subpixels in the platform may not align with the canvas subpixels.
130 //
131 // To workaround it, round the floating point bounds and make the rect
132 // slightly larger.
133 //
134 // For example, {0.3, 0.5, 3.1, 4.7} becomes {0, 0, 4, 5}.
135 full_joined_rect.set(full_joined_rect.roundOut());
136 overlay_layers.insert({view_id, full_joined_rect});
137 // Clip the background canvas, so it doesn't contain any of the pixels
138 // drawn on the overlay layer.
139 background_canvas->ClipRect(full_joined_rect,
141 }
142 slice->render_into(background_canvas);
143 }
144
145 // Manually trigger the DlAutoCanvasRestore before we submit the frame
146 save.Restore();
147
148 // Submit the background canvas frame before switching the GL context to
149 // the overlay surfaces.
150 //
151 // Skip a frame if the embedding is switching surfaces, and indicate in
152 // `PostPrerollAction` that this frame must be resubmitted.
153 auto should_submit_current_frame = previous_frame_view_count_ > 0;
154 if (should_submit_current_frame) {
155 frame->Submit();
156 }
157
158 for (int64_t view_id : composition_order_) {
159 SkRect view_rect = GetViewRect(view_id);
160 const EmbeddedViewParams& params = view_params_.at(view_id);
161 // Display the platform view. If it's already displayed, then it's
162 // just positioned and sized.
163 jni_facade_->FlutterViewOnDisplayPlatformView(
164 view_id, //
165 view_rect.x(), //
166 view_rect.y(), //
167 view_rect.width(), //
168 view_rect.height(), //
169 params.sizePoints().width() * device_pixel_ratio_,
170 params.sizePoints().height() * device_pixel_ratio_,
171 params.mutatorsStack() //
172 );
173 std::unordered_map<int64_t, SkRect>::const_iterator overlay =
174 overlay_layers.find(view_id);
175 if (overlay == overlay_layers.end()) {
176 continue;
177 }
178 std::unique_ptr<SurfaceFrame> frame =
179 CreateSurfaceIfNeeded(context, //
180 view_id, //
181 slices_.at(view_id).get(), //
182 overlay->second //
183 );
184 if (should_submit_current_frame) {
185 frame->Submit();
186 }
187 }
188}
189
190// |ExternalViewEmbedder|
191std::unique_ptr<SurfaceFrame>
192AndroidExternalViewEmbedder::CreateSurfaceIfNeeded(GrDirectContext* context,
193 int64_t view_id,
194 EmbedderViewSlice* slice,
195 const SkRect& rect) {
196 std::shared_ptr<OverlayLayer> layer = surface_pool_->GetLayer(
197 context, android_context_, jni_facade_, surface_factory_);
198
199 std::unique_ptr<SurfaceFrame> frame =
200 layer->surface->AcquireFrame(frame_size_);
201 // Display the overlay surface. If it's already displayed, then it's
202 // just positioned and sized.
203 jni_facade_->FlutterViewDisplayOverlaySurface(layer->id, //
204 rect.x(), //
205 rect.y(), //
206 rect.width(), //
207 rect.height() //
208 );
209 DlCanvas* overlay_canvas = frame->Canvas();
210 overlay_canvas->Clear(DlColor::kTransparent());
211 // Offset the picture since its absolute position on the scene is determined
212 // by the position of the overlay view.
213 overlay_canvas->Translate(-rect.x(), -rect.y());
214 slice->render_into(overlay_canvas);
215 return frame;
216}
217
218// |ExternalViewEmbedder|
220 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {
221 if (!FrameHasPlatformLayers()) {
223 }
224 if (!raster_thread_merger->IsMerged()) {
225 // The raster thread merger may be disabled if the rasterizer is being
226 // created or teared down.
227 //
228 // In such cases, the current frame is dropped, and a new frame is attempted
229 // with the same layer tree.
230 //
231 // Eventually, the frame is submitted once this method returns `kSuccess`.
232 // At that point, the raster tasks are handled on the platform thread.
233 CancelFrame();
234 raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
236 }
237 raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration);
238 // Surface switch requires to resubmit the frame.
239 // TODO(egarciad): https://github.com/flutter/flutter/issues/65652
240 if (previous_frame_view_count_ == 0) {
242 }
244}
245
246bool AndroidExternalViewEmbedder::FrameHasPlatformLayers() {
247 return !composition_order_.empty();
248}
249
250// |ExternalViewEmbedder|
252 // On Android, the root surface is created from the on-screen render target.
253 return nullptr;
254}
255
256void AndroidExternalViewEmbedder::Reset() {
257 previous_frame_view_count_ = composition_order_.size();
258
259 composition_order_.clear();
260 slices_.clear();
261}
262
263// |ExternalViewEmbedder|
265 GrDirectContext* context,
266 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {
267 // JNI method must be called on the platform thread.
268 if (raster_thread_merger->IsOnPlatformThread()) {
269 jni_facade_->FlutterViewBeginFrame();
270 }
271}
272
273// |ExternalViewEmbedder|
275 SkISize frame_size,
276 double device_pixel_ratio) {
277 Reset();
278
279 // The surface size changed. Therefore, destroy existing surfaces as
280 // the existing surfaces in the pool can't be recycled.
281 if (frame_size_ != frame_size) {
282 DestroySurfaces();
283 }
284 surface_pool_->SetFrameSize(frame_size);
285
286 frame_size_ = frame_size;
287 device_pixel_ratio_ = device_pixel_ratio;
288}
289
290// |ExternalViewEmbedder|
292 Reset();
293}
294
295// |ExternalViewEmbedder|
297 bool should_resubmit_frame,
298 const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {
299 surface_pool_->RecycleLayers();
300 // JNI method must be called on the platform thread.
301 if (raster_thread_merger->IsOnPlatformThread()) {
302 jni_facade_->FlutterViewEndFrame();
303 }
304}
305
306// |ExternalViewEmbedder|
308 return true;
309}
310
311// |ExternalViewEmbedder|
313 DestroySurfaces();
314}
315
316// |ExternalViewEmbedder|
317void AndroidExternalViewEmbedder::DestroySurfaces() {
318 if (!surface_pool_->HasLayers()) {
319 return;
320 }
323 [&]() {
324 surface_pool_->DestroyLayers(jni_facade_);
325 latch.Signal();
326 });
327 latch.Wait();
328}
329
330} // namespace flutter
Holds state that is shared across Android surfaces.
void EndFrame(bool should_resubmit_frame, const fml::RefPtr< fml::RasterThreadMerger > &raster_thread_merger) override
PostPrerollResult PostPrerollAction(const fml::RefPtr< fml::RasterThreadMerger > &raster_thread_merger) override
void PrerollCompositeEmbeddedView(int64_t view_id, std::unique_ptr< flutter::EmbeddedViewParams > params) override
void SubmitFlutterView(int64_t flutter_view_id, GrDirectContext *context, const std::shared_ptr< impeller::AiksContext > &aiks_context, std::unique_ptr< SurfaceFrame > frame) override
DlCanvas * CompositeEmbeddedView(int64_t view_id) override
void BeginFrame(GrDirectContext *context, const fml::RefPtr< fml::RasterThreadMerger > &raster_thread_merger) override
AndroidExternalViewEmbedder(const AndroidContext &android_context, std::shared_ptr< PlatformViewAndroidJNI > jni_facade, std::shared_ptr< AndroidSurfaceFactory > surface_factory, const TaskRunners &task_runners)
SkRect GetViewRect(int64_t view_id) const
void PrepareFlutterView(SkISize frame_size, double device_pixel_ratio) override
Developer-facing API for rendering anything within the engine.
Definition: dl_canvas.h:38
virtual void ClipRect(const SkRect &rect, ClipOp clip_op=ClipOp::kIntersect, bool is_aa=false)=0
virtual void Translate(SkScalar tx, SkScalar ty)=0
void Clear(DlColor color)
Definition: dl_canvas.h:132
std::vector< SkIRect > getRects(bool deband=true) const
Definition: dl_region.cc:563
virtual void render_into(DlCanvas *canvas)=0
virtual DlCanvas * canvas()=0
virtual void end_recording()=0
DlRegion region(const SkRect &query) const
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
Definition: task_runners.cc:30
void ExtendLeaseTo(size_t lease_term)
void MergeWithLease(size_t lease_term)
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
Definition: task_runner.cc:55
const EmbeddedViewParams * params
TaskRunners task_runners_
double frame
Definition: examples.cpp:31
#define FML_DCHECK(condition)
Definition: logging.h:103
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
constexpr int64_t kFlutterImplicitViewId
Definition: constants.h:35
Definition: ref_ptr.h:256
Definition: SkRect.h:32
Definition: SkSize.h:16
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
bool intersect(const SkRect &r)
Definition: SkRect.cpp:114
constexpr float x() const
Definition: SkRect.h:720
constexpr float y() const
Definition: SkRect.h:727
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
void roundOut(SkIRect *dst) const
Definition: SkRect.h:1241
constexpr float height() const
Definition: SkRect.h:769
constexpr float width() const
Definition: SkRect.h:762
bool isEmpty() const
Definition: SkRect.h:693
void join(const SkRect &r)
Definition: SkRect.cpp:126
void set(const SkIRect &src)
Definition: SkRect.h:849
static constexpr DlColor kTransparent()
Definition: dl_color.h:21
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131