|
| 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_2.h" |
| 6 | +#include "flow/view_slicer.h" |
| 7 | +#include "flutter/common/constants.h" |
| 8 | +#include "flutter/fml/synchronization/waitable_event.h" |
| 9 | +#include "flutter/fml/trace_event.h" |
| 10 | +#include "fml/make_copyable.h" |
| 11 | + |
| 12 | +namespace flutter { |
| 13 | + |
| 14 | +AndroidExternalViewEmbedder2::AndroidExternalViewEmbedder2( |
| 15 | + const AndroidContext& android_context, |
| 16 | + std::shared_ptr<PlatformViewAndroidJNI> jni_facade, |
| 17 | + std::shared_ptr<AndroidSurfaceFactory> surface_factory, |
| 18 | + const TaskRunners& task_runners) |
| 19 | + : ExternalViewEmbedder(), |
| 20 | + android_context_(android_context), |
| 21 | + jni_facade_(std::move(jni_facade)), |
| 22 | + surface_factory_(std::move(surface_factory)), |
| 23 | + surface_pool_( |
| 24 | + std::make_unique<SurfacePool>(/*use_new_surface_methods=*/true)), |
| 25 | + task_runners_(task_runners) {} |
| 26 | + |
| 27 | +// |ExternalViewEmbedder| |
| 28 | +void AndroidExternalViewEmbedder2::PrerollCompositeEmbeddedView( |
| 29 | + int64_t view_id, |
| 30 | + std::unique_ptr<EmbeddedViewParams> params) { |
| 31 | + TRACE_EVENT0("flutter", |
| 32 | + "AndroidExternalViewEmbedder2::PrerollCompositeEmbeddedView"); |
| 33 | + |
| 34 | + SkRect view_bounds = SkRect::Make(frame_size_); |
| 35 | + std::unique_ptr<EmbedderViewSlice> view; |
| 36 | + view = std::make_unique<DisplayListEmbedderViewSlice>(view_bounds); |
| 37 | + slices_.insert_or_assign(view_id, std::move(view)); |
| 38 | + |
| 39 | + composition_order_.push_back(view_id); |
| 40 | + // Update params only if they changed. |
| 41 | + if (view_params_.count(view_id) == 1 && |
| 42 | + view_params_.at(view_id) == *params.get()) { |
| 43 | + return; |
| 44 | + } |
| 45 | + view_params_.insert_or_assign(view_id, EmbeddedViewParams(*params.get())); |
| 46 | +} |
| 47 | + |
| 48 | +// |ExternalViewEmbedder| |
| 49 | +DlCanvas* AndroidExternalViewEmbedder2::CompositeEmbeddedView(int64_t view_id) { |
| 50 | + if (slices_.count(view_id) == 1) { |
| 51 | + return slices_.at(view_id)->canvas(); |
| 52 | + } |
| 53 | + return nullptr; |
| 54 | +} |
| 55 | + |
| 56 | +SkRect AndroidExternalViewEmbedder2::GetViewRect( |
| 57 | + int64_t view_id, |
| 58 | + const std::unordered_map<int64_t, EmbeddedViewParams>& view_params) { |
| 59 | + const EmbeddedViewParams& params = view_params.at(view_id); |
| 60 | + // https://github.com/flutter/flutter/issues/59821 |
| 61 | + return SkRect::MakeXYWH(params.finalBoundingRect().x(), // |
| 62 | + params.finalBoundingRect().y(), // |
| 63 | + params.finalBoundingRect().width(), // |
| 64 | + params.finalBoundingRect().height() // |
| 65 | + ); |
| 66 | +} |
| 67 | + |
| 68 | +// |ExternalViewEmbedder| |
| 69 | +void AndroidExternalViewEmbedder2::SubmitFlutterView( |
| 70 | + int64_t flutter_view_id, |
| 71 | + GrDirectContext* context, |
| 72 | + const std::shared_ptr<impeller::AiksContext>& aiks_context, |
| 73 | + std::unique_ptr<SurfaceFrame> frame) { |
| 74 | + TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder2::SubmitFlutterView"); |
| 75 | + |
| 76 | + if (!FrameHasPlatformLayers()) { |
| 77 | + frame->Submit(); |
| 78 | + jni_facade_->applyTransaction(); |
| 79 | + return; |
| 80 | + } |
| 81 | + |
| 82 | + std::unordered_map<int64_t, SkRect> view_rects; |
| 83 | + for (auto platform_id : composition_order_) { |
| 84 | + view_rects[platform_id] = GetViewRect(platform_id, view_params_); |
| 85 | + } |
| 86 | + |
| 87 | + std::unordered_map<int64_t, SkRect> overlay_layers = |
| 88 | + SliceViews(frame->Canvas(), // |
| 89 | + composition_order_, // |
| 90 | + slices_, // |
| 91 | + view_rects // |
| 92 | + ); |
| 93 | + |
| 94 | + // Create Overlay frame. |
| 95 | + surface_pool_->TrimLayers(); |
| 96 | + std::unique_ptr<SurfaceFrame> overlay_frame; |
| 97 | + if (surface_pool_->HasLayers()) { |
| 98 | + for (int64_t view_id : composition_order_) { |
| 99 | + std::unordered_map<int64_t, SkRect>::const_iterator overlay = |
| 100 | + overlay_layers.find(view_id); |
| 101 | + |
| 102 | + if (overlay == overlay_layers.end()) { |
| 103 | + continue; |
| 104 | + } |
| 105 | + if (overlay_frame == nullptr) { |
| 106 | + std::shared_ptr<OverlayLayer> layer = surface_pool_->GetLayer( |
| 107 | + context, android_context_, jni_facade_, surface_factory_); |
| 108 | + overlay_frame = layer->surface->AcquireFrame(frame_size_); |
| 109 | + } |
| 110 | + |
| 111 | + DlCanvas* overlay_canvas = overlay_frame->Canvas(); |
| 112 | + int restore_count = overlay_canvas->GetSaveCount(); |
| 113 | + overlay_canvas->Save(); |
| 114 | + overlay_canvas->ClipRect(overlay->second); |
| 115 | + overlay_canvas->Clear(DlColor::kTransparent()); |
| 116 | + slices_[view_id]->render_into(overlay_canvas); |
| 117 | + overlay_canvas->RestoreToCount(restore_count); |
| 118 | + } |
| 119 | + } |
| 120 | + if (overlay_frame != nullptr) { |
| 121 | + overlay_frame->set_submit_info({.frame_boundary = false}); |
| 122 | + overlay_frame->Submit(); |
| 123 | + } |
| 124 | + frame->Submit(); |
| 125 | + |
| 126 | + task_runners_.GetPlatformTaskRunner()->PostTask(fml::MakeCopyable( |
| 127 | + [&, composition_order = composition_order_, view_params = view_params_, |
| 128 | + jni_facade = jni_facade_, device_pixel_ratio = device_pixel_ratio_, |
| 129 | + slices = std::move(slices_)]() -> void { |
| 130 | + jni_facade->swapTransaction(); |
| 131 | + for (int64_t view_id : composition_order) { |
| 132 | + SkRect view_rect = GetViewRect(view_id, view_params); |
| 133 | + const EmbeddedViewParams& params = view_params.at(view_id); |
| 134 | + // Display the platform view. If it's already displayed, then it's |
| 135 | + // just positioned and sized. |
| 136 | + jni_facade->FlutterViewOnDisplayPlatformView( |
| 137 | + view_id, // |
| 138 | + view_rect.x(), // |
| 139 | + view_rect.y(), // |
| 140 | + view_rect.width(), // |
| 141 | + view_rect.height(), // |
| 142 | + params.sizePoints().width() * device_pixel_ratio, |
| 143 | + params.sizePoints().height() * device_pixel_ratio, |
| 144 | + params.mutatorsStack() // |
| 145 | + ); |
| 146 | + } |
| 147 | + if (!surface_pool_->HasLayers()) { |
| 148 | + surface_pool_->GetLayer(context, android_context_, jni_facade_, |
| 149 | + surface_factory_); |
| 150 | + } |
| 151 | + jni_facade->FlutterViewEndFrame(); |
| 152 | + })); |
| 153 | +} |
| 154 | + |
| 155 | +// |ExternalViewEmbedder| |
| 156 | +std::unique_ptr<SurfaceFrame> |
| 157 | +AndroidExternalViewEmbedder2::CreateSurfaceIfNeeded(GrDirectContext* context, |
| 158 | + int64_t view_id, |
| 159 | + EmbedderViewSlice* slice, |
| 160 | + const SkRect& rect) { |
| 161 | + std::shared_ptr<OverlayLayer> layer = surface_pool_->GetLayer( |
| 162 | + context, android_context_, jni_facade_, surface_factory_); |
| 163 | + |
| 164 | + std::unique_ptr<SurfaceFrame> frame = |
| 165 | + layer->surface->AcquireFrame(frame_size_); |
| 166 | + |
| 167 | + DlCanvas* overlay_canvas = frame->Canvas(); |
| 168 | + overlay_canvas->Clear(DlColor::kTransparent()); |
| 169 | + // Offset the picture since its absolute position on the scene is determined |
| 170 | + // by the position of the overlay view. |
| 171 | + slice->render_into(overlay_canvas); |
| 172 | + return frame; |
| 173 | +} |
| 174 | + |
| 175 | +// |ExternalViewEmbedder| |
| 176 | +PostPrerollResult AndroidExternalViewEmbedder2::PostPrerollAction( |
| 177 | + const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) { |
| 178 | + return PostPrerollResult::kSuccess; |
| 179 | +} |
| 180 | + |
| 181 | +bool AndroidExternalViewEmbedder2::FrameHasPlatformLayers() { |
| 182 | + return !composition_order_.empty(); |
| 183 | +} |
| 184 | + |
| 185 | +// |ExternalViewEmbedder| |
| 186 | +DlCanvas* AndroidExternalViewEmbedder2::GetRootCanvas() { |
| 187 | + // On Android, the root surface is created from the on-screen render target. |
| 188 | + return nullptr; |
| 189 | +} |
| 190 | + |
| 191 | +void AndroidExternalViewEmbedder2::Reset() { |
| 192 | + previous_frame_view_count_ = composition_order_.size(); |
| 193 | + |
| 194 | + composition_order_.clear(); |
| 195 | + slices_.clear(); |
| 196 | +} |
| 197 | + |
| 198 | +// |ExternalViewEmbedder| |
| 199 | +void AndroidExternalViewEmbedder2::BeginFrame( |
| 200 | + GrDirectContext* context, |
| 201 | + const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {} |
| 202 | + |
| 203 | +// |ExternalViewEmbedder| |
| 204 | +void AndroidExternalViewEmbedder2::PrepareFlutterView( |
| 205 | + SkISize frame_size, |
| 206 | + double device_pixel_ratio) { |
| 207 | + Reset(); |
| 208 | + |
| 209 | + // The surface size changed. Therefore, destroy existing surfaces as |
| 210 | + // the existing surfaces in the pool can't be recycled. |
| 211 | + if (frame_size_ != frame_size) { |
| 212 | + DestroySurfaces(); |
| 213 | + } |
| 214 | + surface_pool_->SetFrameSize(frame_size); |
| 215 | + |
| 216 | + frame_size_ = frame_size; |
| 217 | + device_pixel_ratio_ = device_pixel_ratio; |
| 218 | +} |
| 219 | + |
| 220 | +// |ExternalViewEmbedder| |
| 221 | +void AndroidExternalViewEmbedder2::CancelFrame() { |
| 222 | + Reset(); |
| 223 | +} |
| 224 | + |
| 225 | +// |ExternalViewEmbedder| |
| 226 | +void AndroidExternalViewEmbedder2::EndFrame( |
| 227 | + bool should_resubmit_frame, |
| 228 | + const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger) {} |
| 229 | + |
| 230 | +// |ExternalViewEmbedder| |
| 231 | +bool AndroidExternalViewEmbedder2::SupportsDynamicThreadMerging() { |
| 232 | + return false; |
| 233 | +} |
| 234 | + |
| 235 | +// |ExternalViewEmbedder| |
| 236 | +void AndroidExternalViewEmbedder2::Teardown() { |
| 237 | + DestroySurfaces(); |
| 238 | +} |
| 239 | + |
| 240 | +// |ExternalViewEmbedder| |
| 241 | +void AndroidExternalViewEmbedder2::DestroySurfaces() { |
| 242 | + if (!surface_pool_->HasLayers()) { |
| 243 | + return; |
| 244 | + } |
| 245 | + fml::AutoResetWaitableEvent latch; |
| 246 | + fml::TaskRunner::RunNowOrPostTask(task_runners_.GetPlatformTaskRunner(), |
| 247 | + [&]() { |
| 248 | + surface_pool_->DestroyLayers(jni_facade_); |
| 249 | + latch.Signal(); |
| 250 | + }); |
| 251 | + latch.Wait(); |
| 252 | +} |
| 253 | + |
| 254 | +} // namespace flutter |
0 commit comments