mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Implement external view embedder on Android (flutter/engine#19033)
The external view embedder allows to embed Android views in a Flutter app.
This commit is contained in:
parent
0e8db3a1de
commit
202c1af268
@ -74,7 +74,6 @@ group("flutter") {
|
||||
"//flutter/lib/ui:ui_unittests",
|
||||
"//flutter/runtime:runtime_unittests",
|
||||
"//flutter/shell/common:shell_unittests",
|
||||
"//flutter/shell/platform/android/external_view_embedder:android_external_view_embedder_unittests",
|
||||
"//flutter/shell/platform/embedder:embedder_unittests",
|
||||
"//flutter/testing:testing_unittests",
|
||||
"//flutter/third_party/txt:txt_unittests",
|
||||
@ -85,6 +84,8 @@ group("flutter") {
|
||||
"//flutter/fml:fml_benchmarks",
|
||||
"//flutter/lib/ui:ui_benchmarks",
|
||||
"//flutter/shell/common:shell_benchmarks",
|
||||
"//flutter/shell/platform/android/external_view_embedder:android_external_view_embedder_unittests",
|
||||
"//flutter/shell/platform/android/jni:jni_unittests",
|
||||
"//flutter/third_party/txt:txt_benchmarks",
|
||||
]
|
||||
}
|
||||
|
||||
@ -645,8 +645,6 @@ FILE: ../../../flutter/shell/gpu/gpu_surface_vulkan.h
|
||||
FILE: ../../../flutter/shell/gpu/gpu_surface_vulkan_delegate.cc
|
||||
FILE: ../../../flutter/shell/gpu/gpu_surface_vulkan_delegate.h
|
||||
FILE: ../../../flutter/shell/platform/android/AndroidManifest.xml
|
||||
FILE: ../../../flutter/shell/platform/android/android_context.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_context.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_context_gl.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_context_gl.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_environment_gl.cc
|
||||
@ -654,12 +652,8 @@ FILE: ../../../flutter/shell/platform/android/android_environment_gl.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_exports.lst
|
||||
FILE: ../../../flutter/shell/platform/android/android_external_texture_gl.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_external_texture_gl.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_native_window.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_native_window.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_shell_holder.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_surface.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_surface.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_surface_gl.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_surface_gl.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_surface_software.cc
|
||||
@ -668,9 +662,14 @@ FILE: ../../../flutter/shell/platform/android/android_surface_vulkan.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_surface_vulkan.h
|
||||
FILE: ../../../flutter/shell/platform/android/apk_asset_provider.cc
|
||||
FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h
|
||||
FILE: ../../../flutter/shell/platform/android/context/android_context.cc
|
||||
FILE: ../../../flutter/shell/platform/android/context/android_context.h
|
||||
FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder.cc
|
||||
FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder.h
|
||||
FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc
|
||||
FILE: ../../../flutter/shell/platform/android/external_view_embedder/surface_pool.cc
|
||||
FILE: ../../../flutter/shell/platform/android/external_view_embedder/surface_pool.h
|
||||
FILE: ../../../flutter/shell/platform/android/external_view_embedder/surface_pool_unittests.cc
|
||||
FILE: ../../../flutter/shell/platform/android/flutter_main.cc
|
||||
FILE: ../../../flutter/shell/platform/android/flutter_main.h
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/Log.java
|
||||
@ -786,6 +785,8 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArgument
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java
|
||||
FILE: ../../../flutter/shell/platform/android/jni/jni_mock.h
|
||||
FILE: ../../../flutter/shell/platform/android/jni/jni_mock_unittest.cc
|
||||
FILE: ../../../flutter/shell/platform/android/jni/platform_view_android_jni.cc
|
||||
FILE: ../../../flutter/shell/platform/android/jni/platform_view_android_jni.h
|
||||
FILE: ../../../flutter/shell/platform/android/library_loader.cc
|
||||
@ -796,6 +797,12 @@ FILE: ../../../flutter/shell/platform/android/platform_view_android.h
|
||||
FILE: ../../../flutter/shell/platform/android/platform_view_android_jni_impl.cc
|
||||
FILE: ../../../flutter/shell/platform/android/platform_view_android_jni_impl.h
|
||||
FILE: ../../../flutter/shell/platform/android/robolectric.properties
|
||||
FILE: ../../../flutter/shell/platform/android/surface/android_native_window.cc
|
||||
FILE: ../../../flutter/shell/platform/android/surface/android_native_window.h
|
||||
FILE: ../../../flutter/shell/platform/android/surface/android_surface.cc
|
||||
FILE: ../../../flutter/shell/platform/android/surface/android_surface.h
|
||||
FILE: ../../../flutter/shell/platform/android/surface/android_surface_mock.cc
|
||||
FILE: ../../../flutter/shell/platform/android/surface/android_surface_mock.h
|
||||
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.cc
|
||||
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.h
|
||||
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/basic_message_channel_unittests.cc
|
||||
|
||||
@ -227,9 +227,11 @@ class ExternalViewEmbedder {
|
||||
// sets the stage for the next pre-roll.
|
||||
virtual void CancelFrame() = 0;
|
||||
|
||||
virtual void BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio) = 0;
|
||||
virtual void BeginFrame(
|
||||
SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio,
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) = 0;
|
||||
|
||||
virtual void PrerollCompositeEmbeddedView(
|
||||
int view_id,
|
||||
|
||||
@ -28,12 +28,15 @@ void RasterThreadMerger::MergeWithLease(size_t lease_term) {
|
||||
}
|
||||
}
|
||||
|
||||
bool RasterThreadMerger::IsOnRasterizingThread() {
|
||||
const auto current_queue_id = MessageLoop::GetCurrentTaskQueueId();
|
||||
bool RasterThreadMerger::IsOnPlatformThread() const {
|
||||
return MessageLoop::GetCurrentTaskQueueId() == platform_queue_id_;
|
||||
}
|
||||
|
||||
bool RasterThreadMerger::IsOnRasterizingThread() const {
|
||||
if (is_merged_) {
|
||||
return current_queue_id == platform_queue_id_;
|
||||
return IsOnPlatformThread();
|
||||
} else {
|
||||
return current_queue_id == gpu_queue_id_;
|
||||
return !IsOnPlatformThread();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -44,7 +44,10 @@ class RasterThreadMerger
|
||||
// Returns true if the current thread owns rasterizing.
|
||||
// When the threads are merged, platform thread owns rasterizing.
|
||||
// When un-merged, raster thread owns rasterizing.
|
||||
bool IsOnRasterizingThread();
|
||||
bool IsOnRasterizingThread() const;
|
||||
|
||||
// Returns true if the current thread is the platform thread.
|
||||
bool IsOnPlatformThread() const;
|
||||
|
||||
private:
|
||||
static const int kLeaseNotSet;
|
||||
|
||||
@ -92,12 +92,14 @@ TEST(RasterThreadMerger, IsNotOnRasterizingThread) {
|
||||
|
||||
loop1->GetTaskRunner()->PostTask([&]() {
|
||||
ASSERT_FALSE(raster_thread_merger_->IsOnRasterizingThread());
|
||||
ASSERT_TRUE(raster_thread_merger_->IsOnPlatformThread());
|
||||
ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
|
||||
pre_merge.CountDown();
|
||||
});
|
||||
|
||||
loop2->GetTaskRunner()->PostTask([&]() {
|
||||
ASSERT_TRUE(raster_thread_merger_->IsOnRasterizingThread());
|
||||
ASSERT_FALSE(raster_thread_merger_->IsOnPlatformThread());
|
||||
ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid2);
|
||||
pre_merge.CountDown();
|
||||
});
|
||||
@ -108,6 +110,7 @@ TEST(RasterThreadMerger, IsNotOnRasterizingThread) {
|
||||
|
||||
loop1->GetTaskRunner()->PostTask([&]() {
|
||||
ASSERT_TRUE(raster_thread_merger_->IsOnRasterizingThread());
|
||||
ASSERT_TRUE(raster_thread_merger_->IsOnPlatformThread());
|
||||
ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
|
||||
post_merge.CountDown();
|
||||
});
|
||||
@ -116,6 +119,7 @@ TEST(RasterThreadMerger, IsNotOnRasterizingThread) {
|
||||
// this will be false since this is going to be run
|
||||
// on loop1 really.
|
||||
ASSERT_TRUE(raster_thread_merger_->IsOnRasterizingThread());
|
||||
ASSERT_TRUE(raster_thread_merger_->IsOnPlatformThread());
|
||||
ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
|
||||
post_merge.CountDown();
|
||||
});
|
||||
@ -126,12 +130,14 @@ TEST(RasterThreadMerger, IsNotOnRasterizingThread) {
|
||||
|
||||
loop1->GetTaskRunner()->PostTask([&]() {
|
||||
ASSERT_FALSE(raster_thread_merger_->IsOnRasterizingThread());
|
||||
ASSERT_TRUE(raster_thread_merger_->IsOnPlatformThread());
|
||||
ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid1);
|
||||
post_unmerge.CountDown();
|
||||
});
|
||||
|
||||
loop2->GetTaskRunner()->PostTask([&]() {
|
||||
ASSERT_TRUE(raster_thread_merger_->IsOnRasterizingThread());
|
||||
ASSERT_FALSE(raster_thread_merger_->IsOnPlatformThread());
|
||||
ASSERT_EQ(fml::MessageLoop::GetCurrentTaskQueueId(), qid2);
|
||||
post_unmerge.CountDown();
|
||||
});
|
||||
|
||||
@ -391,9 +391,9 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
|
||||
|
||||
SkCanvas* embedder_root_canvas = nullptr;
|
||||
if (external_view_embedder != nullptr) {
|
||||
external_view_embedder->BeginFrame(layer_tree.frame_size(),
|
||||
surface_->GetContext(),
|
||||
layer_tree.device_pixel_ratio());
|
||||
external_view_embedder->BeginFrame(
|
||||
layer_tree.frame_size(), surface_->GetContext(),
|
||||
layer_tree.device_pixel_ratio(), raster_thread_merger_);
|
||||
embedder_root_canvas = external_view_embedder->GetRootCanvas();
|
||||
}
|
||||
|
||||
|
||||
@ -6,9 +6,11 @@ namespace flutter {
|
||||
void ShellTestExternalViewEmbedder::CancelFrame() {}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void ShellTestExternalViewEmbedder::BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio) {}
|
||||
void ShellTestExternalViewEmbedder::BeginFrame(
|
||||
SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio,
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void ShellTestExternalViewEmbedder::PrerollCompositeEmbeddedView(
|
||||
|
||||
@ -29,9 +29,11 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder {
|
||||
void CancelFrame() override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio) override;
|
||||
void BeginFrame(
|
||||
SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio,
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void PrerollCompositeEmbeddedView(
|
||||
|
||||
@ -23,20 +23,14 @@ shared_library("flutter_shell_native") {
|
||||
|
||||
sources = [
|
||||
"$root_build_dir/flutter_icu/icudtl.o",
|
||||
"android_context.cc",
|
||||
"android_context.h",
|
||||
"android_context_gl.cc",
|
||||
"android_context_gl.h",
|
||||
"android_environment_gl.cc",
|
||||
"android_environment_gl.h",
|
||||
"android_external_texture_gl.cc",
|
||||
"android_external_texture_gl.h",
|
||||
"android_native_window.cc",
|
||||
"android_native_window.h",
|
||||
"android_shell_holder.cc",
|
||||
"android_shell_holder.h",
|
||||
"android_surface.cc",
|
||||
"android_surface.h",
|
||||
"android_surface_gl.cc",
|
||||
"android_surface_gl.h",
|
||||
"android_surface_software.cc",
|
||||
@ -67,8 +61,11 @@ shared_library("flutter_shell_native") {
|
||||
"//flutter/runtime",
|
||||
"//flutter/runtime:libdart",
|
||||
"//flutter/shell/common",
|
||||
"//flutter/shell/platform/android/context",
|
||||
"//flutter/shell/platform/android/external_view_embedder",
|
||||
"//flutter/shell/platform/android/jni",
|
||||
"//flutter/shell/platform/android/surface",
|
||||
"//flutter/shell/platform/android/surface:native_window",
|
||||
"//third_party/skia",
|
||||
]
|
||||
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#include "flutter/shell/platform/android/android_context.h"
|
||||
|
||||
#include "flutter/shell/platform/android/android_context_gl.h"
|
||||
#include "flutter/shell/platform/android/android_environment_gl.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
std::shared_ptr<AndroidContext> CreateContextGL() {
|
||||
auto context_gl = std::make_shared<AndroidContextGL>(
|
||||
AndroidRenderingAPI::kOpenGLES,
|
||||
fml::MakeRefCounted<AndroidEnvironmentGL>());
|
||||
FML_CHECK(context_gl->IsValid()) << "Could not create an Android context GL.";
|
||||
return context_gl;
|
||||
}
|
||||
|
||||
AndroidContext::AndroidContext(AndroidRenderingAPI rendering_api)
|
||||
: rendering_api_(rendering_api) {}
|
||||
|
||||
AndroidContext::~AndroidContext() = default;
|
||||
|
||||
AndroidRenderingAPI AndroidContext::RenderingApi() const {
|
||||
return rendering_api_;
|
||||
}
|
||||
|
||||
std::shared_ptr<AndroidContext> AndroidContext::Create(
|
||||
AndroidRenderingAPI rendering_api) {
|
||||
if (rendering_api == AndroidRenderingAPI::kOpenGLES) {
|
||||
return CreateContextGL();
|
||||
}
|
||||
return std::make_shared<AndroidContext>(rendering_api);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@ -9,9 +9,9 @@
|
||||
#include "flutter/fml/memory/ref_counted.h"
|
||||
#include "flutter/fml/memory/ref_ptr.h"
|
||||
#include "flutter/shell/common/platform_view.h"
|
||||
#include "flutter/shell/platform/android/android_context.h"
|
||||
#include "flutter/shell/platform/android/android_environment_gl.h"
|
||||
#include "flutter/shell/platform/android/android_native_window.h"
|
||||
#include "flutter/shell/platform/android/context/android_context.h"
|
||||
#include "flutter/shell/platform/android/surface/android_native_window.h"
|
||||
#include "third_party/skia/include/core/SkSize.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
#include "flutter/fml/make_copyable.h"
|
||||
#include "flutter/fml/message_loop.h"
|
||||
#include "flutter/fml/platform/android/jni_util.h"
|
||||
#include "flutter/shell/common/rasterizer.h"
|
||||
#include "flutter/shell/platform/android/platform_view_android.h"
|
||||
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#include "flutter/shell/platform/android/android_surface.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "flutter/shell/platform/android/android_surface_gl.h"
|
||||
#include "flutter/shell/platform/android/android_surface_software.h"
|
||||
#if SHELL_ENABLE_VULKAN
|
||||
#include "flutter/shell/platform/android/android_surface_vulkan.h"
|
||||
#endif // SHELL_ENABLE_VULKAN
|
||||
|
||||
namespace flutter {
|
||||
|
||||
std::unique_ptr<AndroidSurface> AndroidSurface::Create(
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
|
||||
std::unique_ptr<AndroidSurface> surface;
|
||||
switch (android_context->RenderingApi()) {
|
||||
case AndroidRenderingAPI::kSoftware:
|
||||
surface = std::make_unique<AndroidSurfaceSoftware>(jni_facade);
|
||||
break;
|
||||
case AndroidRenderingAPI::kOpenGLES:
|
||||
surface = std::make_unique<AndroidSurfaceGL>(android_context, jni_facade);
|
||||
break;
|
||||
case AndroidRenderingAPI::kVulkan:
|
||||
#if SHELL_ENABLE_VULKAN
|
||||
surface = std::make_unique<AndroidSurfaceVulkan>(jni_facade);
|
||||
#endif // SHELL_ENABLE_VULKAN
|
||||
break;
|
||||
}
|
||||
FML_CHECK(surface);
|
||||
return surface->IsValid() ? std::move(surface) : nullptr;
|
||||
;
|
||||
}
|
||||
|
||||
AndroidSurface::~AndroidSurface() = default;
|
||||
|
||||
} // namespace flutter
|
||||
@ -13,19 +13,22 @@ namespace flutter {
|
||||
|
||||
AndroidSurfaceGL::AndroidSurfaceGL(
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade)
|
||||
: native_window_(nullptr),
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
const AndroidSurface::Factory& surface_factory)
|
||||
: external_view_embedder_(
|
||||
std::make_unique<AndroidExternalViewEmbedder>(android_context,
|
||||
jni_facade,
|
||||
surface_factory)),
|
||||
android_context_(
|
||||
std::static_pointer_cast<AndroidContextGL>(android_context)),
|
||||
native_window_(nullptr),
|
||||
onscreen_surface_(nullptr),
|
||||
offscreen_surface_(nullptr) {
|
||||
android_context_ =
|
||||
std::static_pointer_cast<AndroidContextGL>(android_context);
|
||||
// Acquire the offscreen surface.
|
||||
offscreen_surface_ = android_context_->CreateOffscreenSurface();
|
||||
if (!offscreen_surface_->IsValid()) {
|
||||
offscreen_surface_ = nullptr;
|
||||
}
|
||||
external_view_embedder_ =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(jni_facade);
|
||||
}
|
||||
|
||||
AndroidSurfaceGL::~AndroidSurfaceGL() = default;
|
||||
|
||||
@ -12,9 +12,9 @@
|
||||
#include "flutter/shell/gpu/gpu_surface_gl.h"
|
||||
#include "flutter/shell/platform/android/android_context_gl.h"
|
||||
#include "flutter/shell/platform/android/android_environment_gl.h"
|
||||
#include "flutter/shell/platform/android/android_surface.h"
|
||||
#include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "flutter/shell/platform/android/surface/android_surface.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
@ -22,7 +22,8 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate,
|
||||
public AndroidSurface {
|
||||
public:
|
||||
AndroidSurfaceGL(std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade);
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
const AndroidSurface::Factory& surface_factory);
|
||||
|
||||
~AndroidSurfaceGL() override;
|
||||
|
||||
@ -63,9 +64,10 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate,
|
||||
ExternalViewEmbedder* GetExternalViewEmbedder() override;
|
||||
|
||||
private:
|
||||
const std::unique_ptr<AndroidExternalViewEmbedder> external_view_embedder_;
|
||||
const std::shared_ptr<AndroidContextGL> android_context_;
|
||||
|
||||
fml::RefPtr<AndroidNativeWindow> native_window_;
|
||||
std::unique_ptr<AndroidExternalViewEmbedder> external_view_embedder_;
|
||||
std::shared_ptr<AndroidContextGL> android_context_;
|
||||
std::unique_ptr<AndroidEGLSurface> onscreen_surface_;
|
||||
std::unique_ptr<AndroidEGLSurface> offscreen_surface_;
|
||||
|
||||
|
||||
@ -37,11 +37,15 @@ bool GetSkColorType(int32_t buffer_format,
|
||||
} // anonymous namespace
|
||||
|
||||
AndroidSurfaceSoftware::AndroidSurfaceSoftware(
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
AndroidSurface::Factory surface_factory)
|
||||
: external_view_embedder_(
|
||||
std::make_unique<AndroidExternalViewEmbedder>(android_context,
|
||||
jni_facade,
|
||||
surface_factory)) {
|
||||
GetSkColorType(WINDOW_FORMAT_RGBA_8888, &target_color_type_,
|
||||
&target_alpha_type_);
|
||||
external_view_embedder_ =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(jni_facade);
|
||||
}
|
||||
|
||||
AndroidSurfaceSoftware::~AndroidSurfaceSoftware() = default;
|
||||
|
||||
@ -9,16 +9,18 @@
|
||||
#include "flutter/fml/platform/android/jni_weak_ref.h"
|
||||
#include "flutter/fml/platform/android/scoped_java_ref.h"
|
||||
#include "flutter/shell/gpu/gpu_surface_software.h"
|
||||
#include "flutter/shell/platform/android/android_surface.h"
|
||||
#include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "flutter/shell/platform/android/surface/android_surface.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class AndroidSurfaceSoftware final : public AndroidSurface,
|
||||
public GPUSurfaceSoftwareDelegate {
|
||||
public:
|
||||
AndroidSurfaceSoftware(std::shared_ptr<PlatformViewAndroidJNI> jni_facade);
|
||||
AndroidSurfaceSoftware(std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
AndroidSurface::Factory surface_factory);
|
||||
|
||||
~AndroidSurfaceSoftware() override;
|
||||
|
||||
@ -53,11 +55,12 @@ class AndroidSurfaceSoftware final : public AndroidSurface,
|
||||
ExternalViewEmbedder* GetExternalViewEmbedder() override;
|
||||
|
||||
private:
|
||||
const std::unique_ptr<AndroidExternalViewEmbedder> external_view_embedder_;
|
||||
|
||||
sk_sp<SkSurface> sk_surface_;
|
||||
fml::RefPtr<AndroidNativeWindow> native_window_;
|
||||
SkColorType target_color_type_;
|
||||
SkAlphaType target_alpha_type_;
|
||||
std::unique_ptr<AndroidExternalViewEmbedder> external_view_embedder_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(AndroidSurfaceSoftware);
|
||||
};
|
||||
|
||||
@ -13,11 +13,14 @@
|
||||
namespace flutter {
|
||||
|
||||
AndroidSurfaceVulkan::AndroidSurfaceVulkan(
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade)
|
||||
: proc_table_(fml::MakeRefCounted<vulkan::VulkanProcTable>()) {
|
||||
external_view_embedder_ =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(jni_facade);
|
||||
}
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
AndroidSurface::Factory surface_factory)
|
||||
: external_view_embedder_(
|
||||
std::make_unique<AndroidExternalViewEmbedder>(android_context,
|
||||
jni_facade,
|
||||
surface_factory)),
|
||||
proc_table_(fml::MakeRefCounted<vulkan::VulkanProcTable>()) {}
|
||||
|
||||
AndroidSurfaceVulkan::~AndroidSurfaceVulkan() = default;
|
||||
|
||||
|
||||
@ -9,10 +9,9 @@
|
||||
#include <memory>
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h"
|
||||
#include "flutter/shell/platform/android/android_native_window.h"
|
||||
#include "flutter/shell/platform/android/android_surface.h"
|
||||
#include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "flutter/shell/platform/android/surface/android_surface.h"
|
||||
#include "flutter/vulkan/vulkan_window.h"
|
||||
|
||||
namespace flutter {
|
||||
@ -20,7 +19,9 @@ namespace flutter {
|
||||
class AndroidSurfaceVulkan : public AndroidSurface,
|
||||
public GPUSurfaceVulkanDelegate {
|
||||
public:
|
||||
AndroidSurfaceVulkan(std::shared_ptr<PlatformViewAndroidJNI> jni_facade);
|
||||
AndroidSurfaceVulkan(std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
AndroidSurface::Factory surface_factory);
|
||||
|
||||
~AndroidSurfaceVulkan() override;
|
||||
|
||||
@ -52,9 +53,10 @@ class AndroidSurfaceVulkan : public AndroidSurface,
|
||||
fml::RefPtr<vulkan::VulkanProcTable> vk() override;
|
||||
|
||||
private:
|
||||
const std::unique_ptr<AndroidExternalViewEmbedder> external_view_embedder_;
|
||||
|
||||
fml::RefPtr<vulkan::VulkanProcTable> proc_table_;
|
||||
fml::RefPtr<AndroidNativeWindow> native_window_;
|
||||
std::unique_ptr<AndroidExternalViewEmbedder> external_view_embedder_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(AndroidSurfaceVulkan);
|
||||
};
|
||||
|
||||
18
engine/src/flutter/shell/platform/android/context/BUILD.gn
Normal file
18
engine/src/flutter/shell/platform/android/context/BUILD.gn
Normal file
@ -0,0 +1,18 @@
|
||||
# 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("//flutter/common/config.gni")
|
||||
|
||||
source_set("context") {
|
||||
sources = [
|
||||
"android_context.cc",
|
||||
"android_context.h",
|
||||
]
|
||||
|
||||
public_configs = [ "//flutter:config" ]
|
||||
|
||||
deps = [
|
||||
"//flutter/fml",
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
// 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.
|
||||
|
||||
#include "flutter/shell/platform/android/context/android_context.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
AndroidContext::AndroidContext(AndroidRenderingAPI rendering_api)
|
||||
: rendering_api_(rendering_api) {}
|
||||
|
||||
AndroidContext::~AndroidContext() = default;
|
||||
|
||||
AndroidRenderingAPI AndroidContext::RenderingApi() const {
|
||||
return rendering_api_;
|
||||
}
|
||||
|
||||
bool AndroidContext::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@ -6,9 +6,6 @@
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_CONTEXT_H_
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/memory/ref_counted.h"
|
||||
#include "flutter/fml/memory/ref_ptr.h"
|
||||
#include "flutter/shell/common/platform_view.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
@ -27,11 +24,10 @@ class AndroidContext {
|
||||
|
||||
~AndroidContext();
|
||||
|
||||
static std::shared_ptr<AndroidContext> Create(
|
||||
AndroidRenderingAPI rendering_api);
|
||||
|
||||
AndroidRenderingAPI RenderingApi() const;
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
private:
|
||||
const AndroidRenderingAPI rendering_api_;
|
||||
|
||||
@ -2,18 +2,15 @@
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/config/android/config.gni")
|
||||
import("//flutter/common/config.gni")
|
||||
import("//flutter/shell/config.gni")
|
||||
import("//flutter/shell/gpu/gpu.gni")
|
||||
import("//flutter/shell/version/version.gni")
|
||||
|
||||
import("//flutter/testing/testing.gni")
|
||||
|
||||
source_set("external_view_embedder") {
|
||||
sources = [
|
||||
"external_view_embedder.cc",
|
||||
"external_view_embedder.h",
|
||||
"surface_pool.cc",
|
||||
"surface_pool.h",
|
||||
]
|
||||
|
||||
public_configs = [ "//flutter:config" ]
|
||||
@ -22,7 +19,9 @@ source_set("external_view_embedder") {
|
||||
"//flutter/common",
|
||||
"//flutter/flow",
|
||||
"//flutter/fml",
|
||||
"//flutter/shell/platform/android/context",
|
||||
"//flutter/shell/platform/android/jni",
|
||||
"//flutter/shell/platform/android/surface",
|
||||
"//third_party/skia",
|
||||
]
|
||||
}
|
||||
@ -36,11 +35,15 @@ executable("android_external_view_embedder_unittests") {
|
||||
|
||||
sources = [
|
||||
"external_view_embedder_unittests.cc",
|
||||
"surface_pool_unittests.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":external_view_embedder",
|
||||
":external_view_embedder_fixtures",
|
||||
"//flutter/shell/gpu:gpu_surface_gl",
|
||||
"//flutter/shell/platform/android/jni:jni_mock",
|
||||
"//flutter/shell/platform/android/surface:surface_mock",
|
||||
"//flutter/testing",
|
||||
"//flutter/testing:dart",
|
||||
"//flutter/testing:skia",
|
||||
|
||||
@ -9,57 +9,191 @@
|
||||
namespace flutter {
|
||||
|
||||
AndroidExternalViewEmbedder::AndroidExternalViewEmbedder(
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade)
|
||||
: ExternalViewEmbedder(), jni_facade_(jni_facade) {}
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
const AndroidSurface::Factory& surface_factory)
|
||||
: ExternalViewEmbedder(),
|
||||
android_context_(android_context),
|
||||
jni_facade_(jni_facade),
|
||||
surface_factory_(surface_factory),
|
||||
surface_pool_(std::make_unique<SurfacePool>()) {}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView(
|
||||
int view_id,
|
||||
std::unique_ptr<EmbeddedViewParams> params) {
|
||||
// TODO(egarciad): Implement hybrid composition.
|
||||
// https://github.com/flutter/flutter/issues/55270
|
||||
TRACE_EVENT0("flutter",
|
||||
"AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView");
|
||||
picture_recorders_[view_id] = std::make_unique<SkPictureRecorder>();
|
||||
picture_recorders_[view_id]->beginRecording(SkRect::Make(frame_size_));
|
||||
|
||||
auto rtree_factory = RTreeFactory();
|
||||
view_rtrees_.insert({view_id, rtree_factory.getInstance()});
|
||||
|
||||
auto picture_recorder = std::make_unique<SkPictureRecorder>();
|
||||
picture_recorder->beginRecording(SkRect::Make(frame_size_), &rtree_factory);
|
||||
|
||||
picture_recorders_.insert({view_id, std::move(picture_recorder)});
|
||||
composition_order_.push_back(view_id);
|
||||
// Update params only if they changed.
|
||||
if (view_params_.count(view_id) == 1 &&
|
||||
view_params_.at(view_id) == *params.get()) {
|
||||
return;
|
||||
}
|
||||
view_params_.insert_or_assign(view_id, EmbeddedViewParams(*params.get()));
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
SkCanvas* AndroidExternalViewEmbedder::CompositeEmbeddedView(int view_id) {
|
||||
return picture_recorders_[view_id]->getRecordingCanvas();
|
||||
if (picture_recorders_.count(view_id) == 1) {
|
||||
return picture_recorders_.at(view_id)->getRecordingCanvas();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
std::vector<SkCanvas*> AndroidExternalViewEmbedder::GetCurrentCanvases() {
|
||||
// TODO(egarciad): Implement hybrid composition.
|
||||
// https://github.com/flutter/flutter/issues/55270
|
||||
std::vector<SkCanvas*> canvases;
|
||||
for (size_t i = 0; i < composition_order_.size(); i++) {
|
||||
int64_t view_id = composition_order_[i];
|
||||
canvases.push_back(picture_recorders_[view_id]->getRecordingCanvas());
|
||||
canvases.push_back(picture_recorders_.at(view_id)->getRecordingCanvas());
|
||||
}
|
||||
return canvases;
|
||||
}
|
||||
|
||||
SkRect AndroidExternalViewEmbedder::GetViewRect(int view_id) const {
|
||||
const EmbeddedViewParams& params = view_params_.at(view_id);
|
||||
// TODO(egarciad): The rect should be computed from the mutator stack.
|
||||
// https://github.com/flutter/flutter/issues/59821
|
||||
return SkRect::MakeXYWH(params.offsetPixels.x(), //
|
||||
params.offsetPixels.y(), //
|
||||
params.sizePoints.width() * device_pixel_ratio_, //
|
||||
params.sizePoints.height() * device_pixel_ratio_ //
|
||||
);
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
bool AndroidExternalViewEmbedder::SubmitFrame(
|
||||
GrContext* context,
|
||||
std::unique_ptr<SurfaceFrame> frame) {
|
||||
// TODO(egarciad): Implement hybrid composition.
|
||||
// https://github.com/flutter/flutter/issues/55270
|
||||
TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder::SubmitFrame");
|
||||
|
||||
if (should_run_rasterizer_on_platform_thread_) {
|
||||
// Don't submit the current frame if the frame will be resubmitted.
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unordered_map<int64_t, std::list<SkRect>> overlay_layers;
|
||||
std::unordered_map<int64_t, sk_sp<SkPicture>> pictures;
|
||||
SkCanvas* background_canvas = frame->SkiaCanvas();
|
||||
|
||||
// Restore the clip context after exiting this method since it's changed
|
||||
// below.
|
||||
SkAutoCanvasRestore save(background_canvas, /*doSave=*/true);
|
||||
|
||||
for (size_t i = 0; i < composition_order_.size(); i++) {
|
||||
int64_t view_id = composition_order_[i];
|
||||
frame->SkiaCanvas()->drawPicture(
|
||||
picture_recorders_[view_id]->finishRecordingAsPicture());
|
||||
SkRect view_rect = GetViewRect(view_id);
|
||||
|
||||
// Display the platform view. If it's already displayed, then it's
|
||||
// just positioned and sized.
|
||||
jni_facade_->FlutterViewOnDisplayPlatformView(view_id, //
|
||||
view_rect.x(), //
|
||||
view_rect.y(), //
|
||||
view_rect.width(), //
|
||||
view_rect.height() //
|
||||
);
|
||||
|
||||
sk_sp<SkPicture> picture =
|
||||
picture_recorders_.at(view_id)->finishRecordingAsPicture();
|
||||
FML_CHECK(picture);
|
||||
pictures.insert({view_id, picture});
|
||||
sk_sp<RTree> rtree = view_rtrees_.at(view_id);
|
||||
// Determinate if Flutter UI intersects with any of the previous
|
||||
// platform views stacked by z position.
|
||||
//
|
||||
// This is done by querying the r-tree that holds the records for the
|
||||
// picture recorder corresponding to the flow layers added after a platform
|
||||
// view layer.
|
||||
for (ssize_t j = i; j >= 0; j--) {
|
||||
int64_t current_view_id = composition_order_[j];
|
||||
SkRect current_view_rect = GetViewRect(current_view_id);
|
||||
// Each rect corresponds to a native view that renders Flutter UI.
|
||||
std::list<SkRect> intersection_rects =
|
||||
rtree->searchNonOverlappingDrawnRects(current_view_rect);
|
||||
auto allocation_size = intersection_rects.size();
|
||||
|
||||
// Limit the number of native views, so it doesn't grow forever.
|
||||
//
|
||||
// In this case, the rects are merged into a single one that is the union
|
||||
// of all the rects.
|
||||
if (allocation_size > kMaxLayerAllocations) {
|
||||
SkRect joined_rect;
|
||||
for (const SkRect& rect : intersection_rects) {
|
||||
joined_rect.join(rect);
|
||||
}
|
||||
intersection_rects.clear();
|
||||
intersection_rects.push_back(joined_rect);
|
||||
}
|
||||
for (SkRect& intersection_rect : intersection_rects) {
|
||||
// Get the intersection rect between the current rect
|
||||
// and the platform view rect.
|
||||
// joined_rect.intersect(platform_view_rect);
|
||||
// Subpixels in the platform may not align with the canvas subpixels.
|
||||
//
|
||||
// To workaround it, round the floating point bounds and make the rect
|
||||
// slighly larger. For example, {0.3, 0.5, 3.1, 4.7} becomes {0, 0, 4,
|
||||
// 5}.
|
||||
intersection_rect.set(intersection_rect.roundOut());
|
||||
// Clip the background canvas, so it doesn't contain any of the pixels
|
||||
// drawn on the overlay layer.
|
||||
background_canvas->clipRect(intersection_rect, SkClipOp::kDifference);
|
||||
}
|
||||
overlay_layers.insert({current_view_id, intersection_rects});
|
||||
}
|
||||
background_canvas->drawPicture(pictures.at(view_id));
|
||||
}
|
||||
return frame->Submit();
|
||||
// Submit the background canvas frame before switching the GL context to
|
||||
// the surfaces above.
|
||||
frame->Submit();
|
||||
|
||||
for (int64_t view_id : composition_order_) {
|
||||
for (const SkRect& overlay_rect : overlay_layers.at(view_id)) {
|
||||
CreateSurfaceIfNeeded(context, //
|
||||
view_id, //
|
||||
pictures.at(view_id), //
|
||||
overlay_rect //
|
||||
)
|
||||
->Submit();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
std::unique_ptr<SurfaceFrame>
|
||||
AndroidExternalViewEmbedder::CreateSurfaceIfNeeded(GrContext* context,
|
||||
int64_t view_id,
|
||||
sk_sp<SkPicture> picture,
|
||||
const SkRect& rect) {
|
||||
std::shared_ptr<OverlayLayer> layer = surface_pool_->GetLayer(
|
||||
context, android_context_, jni_facade_, surface_factory_);
|
||||
|
||||
std::unique_ptr<SurfaceFrame> frame =
|
||||
layer->surface->AcquireFrame(frame_size_);
|
||||
// Display the overlay surface. If it's already displayed, then it's
|
||||
// just positioned and sized.
|
||||
jni_facade_->FlutterViewDisplayOverlaySurface(layer->id, //
|
||||
rect.x(), //
|
||||
rect.y(), //
|
||||
rect.width(), //
|
||||
rect.height() //
|
||||
);
|
||||
SkCanvas* 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);
|
||||
return frame;
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
@ -100,11 +234,18 @@ void AndroidExternalViewEmbedder::Reset() {
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void AndroidExternalViewEmbedder::BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio) {
|
||||
void AndroidExternalViewEmbedder::BeginFrame(
|
||||
SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio,
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
|
||||
Reset();
|
||||
frame_size_ = frame_size;
|
||||
device_pixel_ratio_ = device_pixel_ratio;
|
||||
// JNI method must be called on the platform thread.
|
||||
if (raster_thread_merger->IsOnPlatformThread()) {
|
||||
jni_facade_->FlutterViewBeginFrame();
|
||||
}
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
@ -119,6 +260,11 @@ void AndroidExternalViewEmbedder::EndFrame(
|
||||
raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
|
||||
should_run_rasterizer_on_platform_thread_ = false;
|
||||
}
|
||||
surface_pool_->RecycleLayers();
|
||||
// JNI method must be called on the platform thread.
|
||||
if (raster_thread_merger->IsOnPlatformThread()) {
|
||||
jni_facade_->FlutterViewEndFrame();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@ -6,16 +6,30 @@
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_EXTERNAL_VIEW_EMBEDDER_H_
|
||||
|
||||
#include "flutter/flow/embedded_views.h"
|
||||
|
||||
#include "flutter/flow/rtree.h"
|
||||
#include "flutter/shell/platform/android/context/android_context.h"
|
||||
#include "flutter/shell/platform/android/external_view_embedder/surface_pool.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "third_party/skia/include/core/SkPictureRecorder.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Allows to embed Android views into a Flutter application.
|
||||
///
|
||||
/// This class calls Java methods via |PlatformViewAndroidJNI| to manage the
|
||||
/// lifecycle of the Android view corresponding to |flutter::PlatformViewLayer|.
|
||||
///
|
||||
/// It also orchestrates overlay surfaces. These are Android views
|
||||
/// that render above (by Z order) the Android view corresponding to
|
||||
/// |flutter::PlatformViewLayer|.
|
||||
///
|
||||
class AndroidExternalViewEmbedder final : public ExternalViewEmbedder {
|
||||
public:
|
||||
AndroidExternalViewEmbedder(
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade);
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
const AndroidSurface::Factory& surface_factory);
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void PrerollCompositeEmbeddedView(
|
||||
@ -40,9 +54,11 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder {
|
||||
SkCanvas* GetRootCanvas() override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio) override;
|
||||
void BeginFrame(
|
||||
SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio,
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void CancelFrame() override;
|
||||
@ -51,9 +67,12 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder {
|
||||
void EndFrame(
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override;
|
||||
|
||||
// Gets the rect based on the device pixel ratio of a platform view displayed
|
||||
// on the screen.
|
||||
SkRect GetViewRect(int view_id) const;
|
||||
|
||||
private:
|
||||
// Allows to call methods in Java.
|
||||
const std::shared_ptr<PlatformViewAndroidJNI> jni_facade_;
|
||||
static const int kMaxLayerAllocations = 2;
|
||||
|
||||
// The number of frames the rasterizer task runner will continue
|
||||
// to run on the platform thread after no platform view is rendered.
|
||||
@ -62,13 +81,29 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder {
|
||||
// where the platform view might be momentarily off the screen.
|
||||
static const int kDefaultMergedLeaseDuration = 10;
|
||||
|
||||
// Provides metadata to the Android surfaces.
|
||||
const std::shared_ptr<AndroidContext> android_context_;
|
||||
|
||||
// Allows to call methods in Java.
|
||||
const std::shared_ptr<PlatformViewAndroidJNI> jni_facade_;
|
||||
|
||||
// Allows to create surfaces.
|
||||
const AndroidSurface::Factory surface_factory_;
|
||||
|
||||
// Holds surfaces. Allows to recycle surfaces or allocate new ones.
|
||||
const std::unique_ptr<SurfacePool> surface_pool_;
|
||||
|
||||
// Whether the rasterizer task runner should run on the platform thread.
|
||||
// When this is true, the current frame is cancelled and resubmitted.
|
||||
bool should_run_rasterizer_on_platform_thread_ = false;
|
||||
|
||||
// The size of the background canvas.
|
||||
// The size of the root canvas.
|
||||
SkISize frame_size_;
|
||||
|
||||
// The pixel ratio used to determinate the size of a platform view layer
|
||||
// relative to the device layout system.
|
||||
double device_pixel_ratio_;
|
||||
|
||||
// The order of composition. Each entry contains a unique id for the platform
|
||||
// view.
|
||||
std::vector<int64_t> composition_order_;
|
||||
@ -76,10 +111,25 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder {
|
||||
// The platform view's picture recorder keyed off the platform 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_;
|
||||
std::unordered_map<int64_t, std::unique_ptr<SkPictureRecorder>>
|
||||
picture_recorders_;
|
||||
|
||||
/// Resets the state.
|
||||
// The params for a platform view, which contains the size, position and
|
||||
// mutation stack.
|
||||
std::unordered_map<int64_t, EmbeddedViewParams> view_params_;
|
||||
|
||||
// The r-tree that captures the operations for the picture recorders.
|
||||
std::unordered_map<int64_t, sk_sp<RTree>> view_rtrees_;
|
||||
|
||||
// Resets the state.
|
||||
void Reset();
|
||||
|
||||
// Creates a Surface when needed or recycles an existing one.
|
||||
// Finally, draws the picture on the frame's canvas.
|
||||
std::unique_ptr<SurfaceFrame> CreateSurfaceIfNeeded(GrContext* context,
|
||||
int64_t view_id,
|
||||
sk_sp<SkPicture> picture,
|
||||
const SkRect& rect);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@ -2,18 +2,81 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/flow/surface.h"
|
||||
#include "flutter/fml/raster_thread_merger.h"
|
||||
#include "flutter/fml/thread.h"
|
||||
#include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h"
|
||||
#include "flutter/shell/platform/android/jni/jni_mock.h"
|
||||
#include "flutter/shell/platform/android/surface/android_surface_mock.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "third_party/skia/include/gpu/GrContext.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, GetCurrentCanvases) {
|
||||
auto embedder = new AndroidExternalViewEmbedder(nullptr);
|
||||
using ::testing::ByMove;
|
||||
using ::testing::Return;
|
||||
|
||||
embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0);
|
||||
class SurfaceMock : public Surface {
|
||||
public:
|
||||
MOCK_METHOD(bool, IsValid, (), (override));
|
||||
|
||||
MOCK_METHOD(std::unique_ptr<SurfaceFrame>,
|
||||
AcquireFrame,
|
||||
(const SkISize& size),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(SkMatrix, GetRootTransformation, (), (const, override));
|
||||
|
||||
MOCK_METHOD(GrContext*, GetContext, (), (override));
|
||||
|
||||
MOCK_METHOD(flutter::ExternalViewEmbedder*,
|
||||
GetExternalViewEmbedder,
|
||||
(),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(std::unique_ptr<GLContextResult>,
|
||||
MakeRenderContextCurrent,
|
||||
(),
|
||||
(override));
|
||||
};
|
||||
|
||||
fml::RefPtr<fml::RasterThreadMerger> GetThreadMergerFromPlatformThread() {
|
||||
auto rasterizer_thread = new fml::Thread("rasterizer");
|
||||
auto rasterizer_queue_id =
|
||||
rasterizer_thread->GetTaskRunner()->GetTaskQueueId();
|
||||
|
||||
// Assume the current thread is the platform thread.
|
||||
fml::MessageLoop::EnsureInitializedForCurrentThread();
|
||||
auto platform_queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
|
||||
|
||||
return fml::MakeRefCounted<fml::RasterThreadMerger>(platform_queue_id,
|
||||
rasterizer_queue_id);
|
||||
}
|
||||
|
||||
fml::RefPtr<fml::RasterThreadMerger> GetThreadMergerFromRasterThread() {
|
||||
auto platform_thread = new fml::Thread("rasterizer");
|
||||
auto platform_queue_id = platform_thread->GetTaskRunner()->GetTaskQueueId();
|
||||
|
||||
// Assume the current thread is the raster thread.
|
||||
fml::MessageLoop::EnsureInitializedForCurrentThread();
|
||||
auto rasterizer_queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
|
||||
|
||||
return fml::MakeRefCounted<fml::RasterThreadMerger>(platform_queue_id,
|
||||
rasterizer_queue_id);
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, GetCurrentCanvases) {
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
|
||||
auto embedder =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
|
||||
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
|
||||
embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
|
||||
raster_thread_merger);
|
||||
|
||||
embedder->PrerollCompositeEmbeddedView(
|
||||
0, std::make_unique<EmbeddedViewParams>());
|
||||
@ -26,20 +89,46 @@ TEST(AndroidExternalViewEmbedder, GetCurrentCanvases) {
|
||||
ASSERT_EQ(SkISize::Make(10, 20), canvases[1]->getBaseLayerSize());
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) {
|
||||
auto embedder = new AndroidExternalViewEmbedder(nullptr);
|
||||
TEST(AndroidExternalViewEmbedder, GetCurrentCanvases__CompositeOrder) {
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
|
||||
auto embedder =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
|
||||
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
|
||||
embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
|
||||
raster_thread_merger);
|
||||
|
||||
embedder->PrerollCompositeEmbeddedView(
|
||||
0, std::make_unique<EmbeddedViewParams>());
|
||||
ASSERT_TRUE(embedder->CompositeEmbeddedView(0) != nullptr);
|
||||
|
||||
embedder->PrerollCompositeEmbeddedView(
|
||||
1, std::make_unique<EmbeddedViewParams>());
|
||||
ASSERT_TRUE(embedder->CompositeEmbeddedView(1) != nullptr);
|
||||
|
||||
auto canvases = embedder->GetCurrentCanvases();
|
||||
ASSERT_EQ(2UL, canvases.size());
|
||||
ASSERT_EQ(embedder->CompositeEmbeddedView(0), canvases[0]);
|
||||
ASSERT_EQ(embedder->CompositeEmbeddedView(1), canvases[1]);
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) {
|
||||
auto embedder =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(nullptr, nullptr, nullptr);
|
||||
|
||||
ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(0));
|
||||
embedder->PrerollCompositeEmbeddedView(
|
||||
0, std::make_unique<EmbeddedViewParams>());
|
||||
ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(0));
|
||||
|
||||
ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(1));
|
||||
embedder->PrerollCompositeEmbeddedView(
|
||||
1, std::make_unique<EmbeddedViewParams>());
|
||||
ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(1));
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, CancelFrame) {
|
||||
auto embedder = new AndroidExternalViewEmbedder(nullptr);
|
||||
auto embedder =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(nullptr, nullptr, nullptr);
|
||||
|
||||
embedder->PrerollCompositeEmbeddedView(
|
||||
0, std::make_unique<EmbeddedViewParams>());
|
||||
@ -50,18 +139,16 @@ TEST(AndroidExternalViewEmbedder, CancelFrame) {
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) {
|
||||
auto embedder = new AndroidExternalViewEmbedder(nullptr);
|
||||
auto platform_thread = new fml::Thread("platform");
|
||||
auto rasterizer_thread = new fml::Thread("rasterizer");
|
||||
auto platform_queue_id = platform_thread->GetTaskRunner()->GetTaskQueueId();
|
||||
auto rasterizer_queue_id =
|
||||
rasterizer_thread->GetTaskRunner()->GetTaskQueueId();
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
auto embedder =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
|
||||
|
||||
auto raster_thread_merger = fml::MakeRefCounted<fml::RasterThreadMerger>(
|
||||
platform_queue_id, rasterizer_queue_id);
|
||||
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
|
||||
ASSERT_FALSE(raster_thread_merger->IsMerged());
|
||||
|
||||
embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0);
|
||||
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
|
||||
embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
|
||||
raster_thread_merger);
|
||||
// Push a platform view.
|
||||
embedder->PrerollCompositeEmbeddedView(
|
||||
0, std::make_unique<EmbeddedViewParams>());
|
||||
@ -70,7 +157,9 @@ TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) {
|
||||
ASSERT_EQ(PostPrerollResult::kResubmitFrame, postpreroll_result);
|
||||
ASSERT_TRUE(embedder->SubmitFrame(nullptr, nullptr));
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
|
||||
embedder->EndFrame(raster_thread_merger);
|
||||
|
||||
ASSERT_TRUE(raster_thread_merger->IsMerged());
|
||||
|
||||
int pending_frames = 0;
|
||||
@ -82,23 +171,221 @@ TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) {
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, RasterizerRunsOnRasterizerThread) {
|
||||
auto embedder = new AndroidExternalViewEmbedder(nullptr);
|
||||
auto platform_thread = new fml::Thread("platform");
|
||||
auto rasterizer_thread = new fml::Thread("rasterizer");
|
||||
auto platform_queue_id = platform_thread->GetTaskRunner()->GetTaskQueueId();
|
||||
auto rasterizer_queue_id =
|
||||
rasterizer_thread->GetTaskRunner()->GetTaskQueueId();
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
auto embedder =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
|
||||
|
||||
auto raster_thread_merger = fml::MakeRefCounted<fml::RasterThreadMerger>(
|
||||
platform_queue_id, rasterizer_queue_id);
|
||||
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
|
||||
ASSERT_FALSE(raster_thread_merger->IsMerged());
|
||||
|
||||
PostPrerollResult result = embedder->PostPrerollAction(raster_thread_merger);
|
||||
ASSERT_EQ(PostPrerollResult::kSuccess, result);
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
|
||||
embedder->EndFrame(raster_thread_merger);
|
||||
|
||||
ASSERT_FALSE(raster_thread_merger->IsMerged());
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, PlatformViewRect) {
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
|
||||
auto embedder =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
|
||||
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
|
||||
embedder->BeginFrame(SkISize::Make(100, 100), nullptr, 1.5,
|
||||
raster_thread_merger);
|
||||
|
||||
auto view_params = std::make_unique<EmbeddedViewParams>();
|
||||
view_params->offsetPixels = SkPoint::Make(10, 20);
|
||||
view_params->sizePoints = SkSize::Make(30, 40);
|
||||
|
||||
auto view_id = 0;
|
||||
embedder->PrerollCompositeEmbeddedView(view_id, std::move(view_params));
|
||||
ASSERT_EQ(SkRect::MakeXYWH(10, 20, 45, 60), embedder->GetViewRect(view_id));
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, PlatformViewRect__ChangedParams) {
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
|
||||
auto embedder =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
|
||||
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
|
||||
embedder->BeginFrame(SkISize::Make(100, 100), nullptr, 1.5,
|
||||
raster_thread_merger);
|
||||
|
||||
auto view_id = 0;
|
||||
auto view_params_1 = std::make_unique<EmbeddedViewParams>();
|
||||
view_params_1->offsetPixels = SkPoint::Make(10, 20);
|
||||
view_params_1->sizePoints = SkSize::Make(30, 40);
|
||||
embedder->PrerollCompositeEmbeddedView(view_id, std::move(view_params_1));
|
||||
|
||||
auto view_params_2 = std::make_unique<EmbeddedViewParams>();
|
||||
view_params_2->offsetPixels = SkPoint::Make(50, 60);
|
||||
view_params_2->sizePoints = SkSize::Make(70, 80);
|
||||
embedder->PrerollCompositeEmbeddedView(view_id, std::move(view_params_2));
|
||||
|
||||
ASSERT_EQ(SkRect::MakeXYWH(50, 60, 105, 120), embedder->GetViewRect(view_id));
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, SubmitFrame__RecycleSurfaces) {
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
auto android_context =
|
||||
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
|
||||
|
||||
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
|
||||
auto gr_context = GrContext::MakeMock(nullptr);
|
||||
auto frame_size = SkISize::Make(1000, 1000);
|
||||
auto surface_factory =
|
||||
[gr_context, window, frame_size](
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
|
||||
auto surface_frame_1 = std::make_unique<SurfaceFrame>(
|
||||
SkSurface::MakeNull(1000, 1000), false,
|
||||
[](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
|
||||
return true;
|
||||
});
|
||||
auto surface_frame_2 = std::make_unique<SurfaceFrame>(
|
||||
SkSurface::MakeNull(1000, 1000), false,
|
||||
[](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
|
||||
return true;
|
||||
});
|
||||
|
||||
auto surface_mock = std::make_unique<SurfaceMock>();
|
||||
EXPECT_CALL(*surface_mock, AcquireFrame(frame_size))
|
||||
.Times(2 /* frames */)
|
||||
.WillOnce(Return(ByMove(std::move(surface_frame_1))))
|
||||
.WillOnce(Return(ByMove(std::move(surface_frame_2))));
|
||||
|
||||
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
|
||||
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()))
|
||||
.WillOnce(Return(ByMove(std::move(surface_mock))));
|
||||
|
||||
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
|
||||
|
||||
return android_surface_mock;
|
||||
};
|
||||
auto embedder = std::make_unique<AndroidExternalViewEmbedder>(
|
||||
android_context, jni_mock, surface_factory);
|
||||
auto raster_thread_merger = GetThreadMergerFromPlatformThread();
|
||||
|
||||
// ------------------ First frame ------------------ //
|
||||
{
|
||||
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
|
||||
embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
|
||||
|
||||
// Add an Android view.
|
||||
auto view_params_1 = std::make_unique<EmbeddedViewParams>();
|
||||
view_params_1->offsetPixels = SkPoint::Make(100, 100);
|
||||
// TODO(egarciad): Investigate why Flow applies the device pixel ratio to
|
||||
// the offsetPixels, but not the sizePoints.
|
||||
view_params_1->sizePoints = SkSize::Make(200, 200);
|
||||
embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
|
||||
// This is the recording canvas flow writes to.
|
||||
auto canvas_1 = embedder->CompositeEmbeddedView(0);
|
||||
|
||||
auto rect_paint = SkPaint();
|
||||
rect_paint.setColor(SkColors::kCyan);
|
||||
rect_paint.setStyle(SkPaint::Style::kFill_Style);
|
||||
|
||||
// This simulates Flutter UI that doesn't intersect with the Android view.
|
||||
canvas_1->drawRect(SkRect::MakeXYWH(0, 0, 50, 50), rect_paint);
|
||||
// This simulates Flutter UI that intersects with the Android view.
|
||||
canvas_1->drawRect(SkRect::MakeXYWH(50, 50, 200, 200), rect_paint);
|
||||
canvas_1->drawRect(SkRect::MakeXYWH(150, 150, 100, 100), rect_paint);
|
||||
|
||||
// Create a new overlay surface.
|
||||
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
|
||||
.WillOnce(Return(
|
||||
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
|
||||
0, window))));
|
||||
// The JNI call to display the Android view.
|
||||
EXPECT_CALL(*jni_mock,
|
||||
FlutterViewOnDisplayPlatformView(0, 100, 100, 300, 300));
|
||||
// The JNI call to display the overlay surface.
|
||||
EXPECT_CALL(*jni_mock,
|
||||
FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
|
||||
|
||||
auto surface_frame =
|
||||
std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
|
||||
[](const SurfaceFrame& surface_frame,
|
||||
SkCanvas* canvas) { return true; });
|
||||
|
||||
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
|
||||
embedder->EndFrame(raster_thread_merger);
|
||||
}
|
||||
|
||||
// ------------------ Second frame ------------------ //
|
||||
{
|
||||
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame());
|
||||
embedder->BeginFrame(frame_size, nullptr, 1.5, raster_thread_merger);
|
||||
|
||||
// Add an Android view.
|
||||
auto view_params_1 = std::make_unique<EmbeddedViewParams>();
|
||||
view_params_1->offsetPixels = SkPoint::Make(100, 100);
|
||||
// TODO(egarciad): Investigate why Flow applies the device pixel ratio to
|
||||
// the offsetPixels, but not the sizePoints.
|
||||
view_params_1->sizePoints = SkSize::Make(200, 200);
|
||||
embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1));
|
||||
// This is the recording canvas flow writes to.
|
||||
auto canvas_1 = embedder->CompositeEmbeddedView(0);
|
||||
|
||||
auto rect_paint = SkPaint();
|
||||
rect_paint.setColor(SkColors::kCyan);
|
||||
rect_paint.setStyle(SkPaint::Style::kFill_Style);
|
||||
|
||||
// This simulates Flutter UI that doesn't intersect with the Android view.
|
||||
canvas_1->drawRect(SkRect::MakeXYWH(0, 0, 50, 50), rect_paint);
|
||||
// This simulates Flutter UI that intersects with the Android view.
|
||||
canvas_1->drawRect(SkRect::MakeXYWH(50, 50, 200, 200), rect_paint);
|
||||
canvas_1->drawRect(SkRect::MakeXYWH(150, 150, 100, 100), rect_paint);
|
||||
|
||||
// Don't create a new overlay surface since it's recycled from the first
|
||||
// frame.
|
||||
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface()).Times(0);
|
||||
// The JNI call to display the Android view.
|
||||
EXPECT_CALL(*jni_mock,
|
||||
FlutterViewOnDisplayPlatformView(0, 100, 100, 300, 300));
|
||||
// The JNI call to display the overlay surface.
|
||||
EXPECT_CALL(*jni_mock,
|
||||
FlutterViewDisplayOverlaySurface(0, 50, 50, 200, 200));
|
||||
|
||||
auto surface_frame =
|
||||
std::make_unique<SurfaceFrame>(SkSurface::MakeNull(1000, 1000), false,
|
||||
[](const SurfaceFrame& surface_frame,
|
||||
SkCanvas* canvas) { return true; });
|
||||
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
|
||||
embedder->EndFrame(raster_thread_merger);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AndroidExternalViewEmbedder, DoesNotCallJNIPlatformThreadOnlyMethods) {
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
|
||||
auto embedder =
|
||||
std::make_unique<AndroidExternalViewEmbedder>(nullptr, jni_mock, nullptr);
|
||||
|
||||
// While on the raster thread, don't make JNI calls as these methods can only
|
||||
// run on the platform thread.
|
||||
auto raster_thread_merger = GetThreadMergerFromRasterThread();
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewBeginFrame()).Times(0);
|
||||
embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0,
|
||||
raster_thread_merger);
|
||||
|
||||
EXPECT_CALL(*jni_mock, FlutterViewEndFrame()).Times(0);
|
||||
embedder->EndFrame(raster_thread_merger);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
// 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.
|
||||
|
||||
#include "flutter/shell/platform/android/external_view_embedder/surface_pool.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
OverlayLayer::OverlayLayer(int id,
|
||||
std::unique_ptr<AndroidSurface> android_surface,
|
||||
std::unique_ptr<Surface> surface)
|
||||
: id(id),
|
||||
android_surface(std::move(android_surface)),
|
||||
surface(std::move(surface)){};
|
||||
|
||||
OverlayLayer::~OverlayLayer() = default;
|
||||
|
||||
SurfacePool::SurfacePool() = default;
|
||||
|
||||
SurfacePool::~SurfacePool() = default;
|
||||
|
||||
std::shared_ptr<OverlayLayer> SurfacePool::GetLayer(
|
||||
GrContext* gr_context,
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
const AndroidSurface::Factory& surface_factory) {
|
||||
intptr_t gr_context_key = reinterpret_cast<intptr_t>(gr_context);
|
||||
// Allocate a new surface if there isn't one available.
|
||||
if (available_layer_index_ >= layers_.size()) {
|
||||
std::unique_ptr<AndroidSurface> android_surface =
|
||||
surface_factory(android_context, jni_facade);
|
||||
|
||||
FML_CHECK(android_surface && android_surface->IsValid())
|
||||
<< "Could not create an OpenGL, Vulkan or Software surface to setup "
|
||||
"rendering.";
|
||||
|
||||
std::unique_ptr<PlatformViewAndroidJNI::OverlayMetadata> java_metadata =
|
||||
jni_facade->FlutterViewCreateOverlaySurface();
|
||||
|
||||
FML_CHECK(java_metadata->window);
|
||||
android_surface->SetNativeWindow(java_metadata->window);
|
||||
|
||||
std::unique_ptr<Surface> surface =
|
||||
android_surface->CreateGPUSurface(gr_context);
|
||||
|
||||
std::shared_ptr<OverlayLayer> layer =
|
||||
std::make_shared<OverlayLayer>(java_metadata->id, //
|
||||
std::move(android_surface), //
|
||||
std::move(surface) //
|
||||
);
|
||||
layer->gr_context_key = gr_context_key;
|
||||
layers_.push_back(layer);
|
||||
}
|
||||
std::shared_ptr<OverlayLayer> layer = layers_[available_layer_index_];
|
||||
// Since the surfaces are recycled, it's possible that the GrContext is
|
||||
// different.
|
||||
if (gr_context_key != layer->gr_context_key) {
|
||||
layer->gr_context_key = gr_context_key;
|
||||
// The overlay already exists, but the GrContext was changed so we need to
|
||||
// recreate the rendering surface with the new GrContext.
|
||||
std::unique_ptr<Surface> surface =
|
||||
layer->android_surface->CreateGPUSurface(gr_context);
|
||||
layer->surface = std::move(surface);
|
||||
}
|
||||
available_layer_index_++;
|
||||
return layer;
|
||||
}
|
||||
|
||||
void SurfacePool::RecycleLayers() {
|
||||
available_layer_index_ = 0;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<OverlayLayer>> SurfacePool::GetUnusedLayers() {
|
||||
std::vector<std::shared_ptr<OverlayLayer>> results;
|
||||
for (size_t i = available_layer_index_; i < layers_.size(); i++) {
|
||||
results.push_back(layers_[i]);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@ -0,0 +1,86 @@
|
||||
// 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.
|
||||
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_EXTERNAL_VIEW_EMBEDDER_SURFACE_POOL_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_EXTERNAL_VIEW_EMBEDDER_SURFACE_POOL_H_
|
||||
|
||||
#include "flutter/flow/surface.h"
|
||||
#include "flutter/shell/platform/android/context/android_context.h"
|
||||
#include "flutter/shell/platform/android/surface/android_surface.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// An Overlay layer represents an `android.view.View` in the C side.
|
||||
///
|
||||
/// The `id` is used to uniquely identify the layer and recycle it between
|
||||
/// frames.
|
||||
///
|
||||
struct OverlayLayer {
|
||||
OverlayLayer(int id,
|
||||
std::unique_ptr<AndroidSurface> android_surface,
|
||||
std::unique_ptr<Surface> surface);
|
||||
|
||||
~OverlayLayer();
|
||||
|
||||
// A unique id to identify the overlay when it gets recycled.
|
||||
const int id;
|
||||
|
||||
// A GPU surface.
|
||||
const std::unique_ptr<AndroidSurface> android_surface;
|
||||
|
||||
// A GPU surface. This may change when the overlay is recycled.
|
||||
std::unique_ptr<Surface> surface;
|
||||
|
||||
// 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.
|
||||
//
|
||||
// This may change when the overlay is recycled.
|
||||
intptr_t gr_context_key;
|
||||
};
|
||||
|
||||
// This class isn't thread safe.
|
||||
class SurfacePool {
|
||||
public:
|
||||
SurfacePool();
|
||||
|
||||
~SurfacePool();
|
||||
|
||||
// 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<OverlayLayer> GetLayer(
|
||||
GrContext* gr_context,
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
|
||||
const AndroidSurface::Factory& surface_factory);
|
||||
|
||||
// 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<OverlayLayer>> 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<OverlayLayer>> layers_;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_ANDROID_EXTERNAL_VIEW_EMBEDDER_SURFACE_POOL_H_
|
||||
@ -0,0 +1,168 @@
|
||||
// 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.
|
||||
|
||||
#include "flutter/fml/make_copyable.h"
|
||||
#include "flutter/shell/platform/android/external_view_embedder/surface_pool.h"
|
||||
#include "flutter/shell/platform/android/jni/jni_mock.h"
|
||||
#include "flutter/shell/platform/android/surface/android_surface_mock.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "third_party/skia/include/gpu/GrContext.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
using ::testing::ByMove;
|
||||
using ::testing::Return;
|
||||
|
||||
TEST(SurfacePool, GetLayer__AllocateOneLayer) {
|
||||
auto pool = std::make_unique<SurfacePool>();
|
||||
|
||||
auto gr_context = GrContext::MakeMock(nullptr);
|
||||
auto android_context =
|
||||
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
|
||||
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
|
||||
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
|
||||
.WillOnce(Return(
|
||||
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
|
||||
0, window))));
|
||||
|
||||
auto surface_factory =
|
||||
[gr_context, window](std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
|
||||
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
|
||||
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()));
|
||||
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
|
||||
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
|
||||
return android_surface_mock;
|
||||
};
|
||||
auto layer = pool->GetLayer(gr_context.get(), android_context, jni_mock,
|
||||
surface_factory);
|
||||
|
||||
ASSERT_NE(nullptr, layer);
|
||||
ASSERT_EQ(reinterpret_cast<intptr_t>(gr_context.get()),
|
||||
layer->gr_context_key);
|
||||
}
|
||||
|
||||
TEST(SurfacePool, GetUnusedLayers) {
|
||||
auto pool = std::make_unique<SurfacePool>();
|
||||
|
||||
auto gr_context = GrContext::MakeMock(nullptr);
|
||||
auto android_context =
|
||||
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
|
||||
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
|
||||
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
|
||||
.WillOnce(Return(
|
||||
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
|
||||
0, window))));
|
||||
|
||||
auto surface_factory =
|
||||
[gr_context, window](std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
|
||||
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
|
||||
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()));
|
||||
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
|
||||
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
|
||||
return android_surface_mock;
|
||||
};
|
||||
auto layer = pool->GetLayer(gr_context.get(), android_context, jni_mock,
|
||||
surface_factory);
|
||||
ASSERT_EQ(0UL, pool->GetUnusedLayers().size());
|
||||
|
||||
pool->RecycleLayers();
|
||||
|
||||
ASSERT_EQ(1UL, pool->GetUnusedLayers().size());
|
||||
ASSERT_EQ(layer, pool->GetUnusedLayers()[0]);
|
||||
}
|
||||
|
||||
TEST(SurfacePool, GetLayer__Recycle) {
|
||||
auto pool = std::make_unique<SurfacePool>();
|
||||
|
||||
auto gr_context_1 = GrContext::MakeMock(nullptr);
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
|
||||
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
|
||||
.WillOnce(Return(
|
||||
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
|
||||
0, window))));
|
||||
|
||||
auto android_context =
|
||||
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
|
||||
|
||||
auto gr_context_2 = GrContext::MakeMock(nullptr);
|
||||
auto surface_factory =
|
||||
[gr_context_1, gr_context_2, window](
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
|
||||
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
|
||||
// Allocate two GPU surfaces for each gr context.
|
||||
EXPECT_CALL(*android_surface_mock,
|
||||
CreateGPUSurface(gr_context_1.get()));
|
||||
EXPECT_CALL(*android_surface_mock,
|
||||
CreateGPUSurface(gr_context_2.get()));
|
||||
// Set the native window once.
|
||||
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
|
||||
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
|
||||
return android_surface_mock;
|
||||
};
|
||||
auto layer_1 = pool->GetLayer(gr_context_1.get(), android_context, jni_mock,
|
||||
surface_factory);
|
||||
|
||||
pool->RecycleLayers();
|
||||
|
||||
auto layer_2 = pool->GetLayer(gr_context_2.get(), android_context, jni_mock,
|
||||
surface_factory);
|
||||
|
||||
ASSERT_NE(nullptr, layer_1);
|
||||
ASSERT_EQ(layer_1, layer_2);
|
||||
ASSERT_EQ(reinterpret_cast<intptr_t>(gr_context_2.get()),
|
||||
layer_1->gr_context_key);
|
||||
ASSERT_EQ(reinterpret_cast<intptr_t>(gr_context_2.get()),
|
||||
layer_2->gr_context_key);
|
||||
}
|
||||
|
||||
TEST(SurfacePool, GetLayer__AllocateTwoLayers) {
|
||||
auto pool = std::make_unique<SurfacePool>();
|
||||
|
||||
auto gr_context = GrContext::MakeMock(nullptr);
|
||||
auto android_context =
|
||||
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
|
||||
|
||||
auto jni_mock = std::make_shared<JNIMock>();
|
||||
auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
|
||||
EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface())
|
||||
.Times(2)
|
||||
.WillOnce(Return(
|
||||
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
|
||||
0, window))))
|
||||
.WillOnce(Return(
|
||||
ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
|
||||
1, window))));
|
||||
|
||||
auto surface_factory =
|
||||
[gr_context, window](std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
|
||||
auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
|
||||
EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get()));
|
||||
EXPECT_CALL(*android_surface_mock, SetNativeWindow(window));
|
||||
EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true));
|
||||
return android_surface_mock;
|
||||
};
|
||||
auto layer_1 = pool->GetLayer(gr_context.get(), android_context, jni_mock,
|
||||
surface_factory);
|
||||
auto layer_2 = pool->GetLayer(gr_context.get(), android_context, jni_mock,
|
||||
surface_factory);
|
||||
ASSERT_NE(nullptr, layer_1);
|
||||
ASSERT_NE(nullptr, layer_2);
|
||||
ASSERT_NE(layer_1, layer_2);
|
||||
ASSERT_EQ(0, layer_1->id);
|
||||
ASSERT_EQ(1, layer_2->id);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
@ -3,6 +3,7 @@
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//flutter/common/config.gni")
|
||||
import("//flutter/testing/testing.gni")
|
||||
|
||||
source_set("jni") {
|
||||
sources = [
|
||||
@ -15,6 +16,41 @@ source_set("jni") {
|
||||
deps = [
|
||||
"//flutter/fml",
|
||||
"//flutter/lib/ui",
|
||||
"//flutter/shell/platform/android/surface:native_window",
|
||||
"//third_party/skia",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("jni_mock") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"jni_mock.h",
|
||||
]
|
||||
|
||||
public_configs = [ "//flutter:config" ]
|
||||
|
||||
deps = [
|
||||
":jni",
|
||||
]
|
||||
}
|
||||
|
||||
test_fixtures("jni_fixtures") {
|
||||
fixtures = []
|
||||
}
|
||||
|
||||
executable("jni_unittests") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"jni_mock_unittest.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":jni_fixtures",
|
||||
":jni_mock",
|
||||
"//flutter/testing",
|
||||
"//flutter/testing:dart",
|
||||
"//flutter/testing:skia",
|
||||
]
|
||||
}
|
||||
|
||||
91
engine/src/flutter/shell/platform/android/jni/jni_mock.h
Normal file
91
engine/src/flutter/shell/platform/android/jni/jni_mock.h
Normal file
@ -0,0 +1,91 @@
|
||||
// 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.
|
||||
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_JNI_MOCK_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_JNI_MOCK_H_
|
||||
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Mock for |PlatformViewAndroidJNI|. This implementation can be used in unit
|
||||
/// tests without requiring the Android toolchain.
|
||||
///
|
||||
class JNIMock final : public PlatformViewAndroidJNI {
|
||||
public:
|
||||
MOCK_METHOD(void,
|
||||
FlutterViewHandlePlatformMessage,
|
||||
(fml::RefPtr<flutter::PlatformMessage> message, int responseId),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
FlutterViewHandlePlatformMessageResponse,
|
||||
(int responseId, std::unique_ptr<fml::Mapping> data),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
FlutterViewUpdateSemantics,
|
||||
(std::vector<uint8_t> buffer, std::vector<std::string> strings),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
FlutterViewUpdateCustomAccessibilityActions,
|
||||
(std::vector<uint8_t> actions_buffer,
|
||||
std::vector<std::string> strings),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void, FlutterViewOnFirstFrame, (), (override));
|
||||
|
||||
MOCK_METHOD(void, FlutterViewOnPreEngineRestart, (), (override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
SurfaceTextureAttachToGLContext,
|
||||
(JavaWeakGlobalRef surface_texture, int textureId),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
SurfaceTextureUpdateTexImage,
|
||||
(JavaWeakGlobalRef surface_texture),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
SurfaceTextureGetTransformMatrix,
|
||||
(JavaWeakGlobalRef surface_texture, SkMatrix& transform),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
SurfaceTextureDetachFromGLContext,
|
||||
(JavaWeakGlobalRef surface_texture),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
FlutterViewOnDisplayPlatformView,
|
||||
(int view_id, int x, int y, int width, int height),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void,
|
||||
FlutterViewDisplayOverlaySurface,
|
||||
(int surface_id, int x, int y, int width, int height),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(void, FlutterViewBeginFrame, (), (override));
|
||||
|
||||
MOCK_METHOD(void, FlutterViewEndFrame, (), (override));
|
||||
|
||||
MOCK_METHOD(std::unique_ptr<PlatformViewAndroidJNI::OverlayMetadata>,
|
||||
FlutterViewCreateOverlaySurface,
|
||||
(),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(std::unique_ptr<std::vector<std::string>>,
|
||||
FlutterViewComputePlatformResolvedLocale,
|
||||
(std::vector<std::string> supported_locales_data),
|
||||
(override));
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_ANDROID_JNI_MOCK_H_
|
||||
@ -0,0 +1,25 @@
|
||||
// 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.
|
||||
|
||||
#include "flutter/shell/platform/android/jni/jni_mock.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
TEST(JNIMock, FlutterViewHandlePlatformMessage) {
|
||||
JNIMock mock;
|
||||
|
||||
auto message =
|
||||
fml::MakeRefCounted<PlatformMessage>("<channel-name>", nullptr);
|
||||
auto response_id = 1;
|
||||
|
||||
EXPECT_CALL(mock, FlutterViewHandlePlatformMessage(message, response_id));
|
||||
|
||||
mock.FlutterViewHandlePlatformMessage(message, response_id);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_H_
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_JNI_PLATFORM_VIEW_ANDROID_JNI_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_JNI_PLATFORM_VIEW_ANDROID_JNI_H_
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/mapping.h"
|
||||
@ -13,6 +13,7 @@
|
||||
#endif
|
||||
|
||||
#include "flutter/lib/ui/window/platform_message.h"
|
||||
#include "flutter/shell/platform/android/surface/android_native_window.h"
|
||||
#include "third_party/skia/include/core/SkMatrix.h"
|
||||
|
||||
namespace flutter {
|
||||
@ -147,12 +148,32 @@ class PlatformViewAndroidJNI {
|
||||
///
|
||||
virtual void FlutterViewEndFrame() = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// The metadata returned from Java which is converted into an |OverlayLayer|
|
||||
/// by |SurfacePool|.
|
||||
///
|
||||
struct OverlayMetadata {
|
||||
OverlayMetadata(int id, fml::RefPtr<AndroidNativeWindow> window)
|
||||
: id(id), window(window){};
|
||||
|
||||
~OverlayMetadata() = default;
|
||||
|
||||
// A unique id to identify the overlay when it gets recycled.
|
||||
const int id;
|
||||
|
||||
// Holds a reference to the native window. That is, an `ANativeWindow`,
|
||||
// which is the C counterpart of the `android.view.Surface` object in Java.
|
||||
const fml::RefPtr<AndroidNativeWindow> window;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Instantiates an overlay surface in hybrid composition.
|
||||
/// @brief Instantiates an overlay surface in hybrid composition and
|
||||
/// provides the necessary metadata to operate the surface in C.
|
||||
///
|
||||
/// @note Must be called from the platform thread.
|
||||
///
|
||||
virtual void FlutterViewCreateOverlaySurface() = 0;
|
||||
virtual std::unique_ptr<PlatformViewAndroidJNI::OverlayMetadata>
|
||||
FlutterViewCreateOverlaySurface() = 0;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Computes the locale Android would select.
|
||||
@ -164,4 +185,4 @@ class PlatformViewAndroidJNI {
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_H_
|
||||
#endif // FLUTTER_SHELL_PLATFORM_ANDROID_JNI_PLATFORM_VIEW_ANDROID_JNI_H_
|
||||
|
||||
@ -10,15 +10,43 @@
|
||||
#include "flutter/fml/synchronization/waitable_event.h"
|
||||
#include "flutter/shell/common/shell_io_manager.h"
|
||||
#include "flutter/shell/gpu/gpu_surface_gl_delegate.h"
|
||||
#include "flutter/shell/platform/android/android_context.h"
|
||||
#include "flutter/shell/platform/android/android_context_gl.h"
|
||||
#include "flutter/shell/platform/android/android_external_texture_gl.h"
|
||||
#include "flutter/shell/platform/android/android_surface_gl.h"
|
||||
#include "flutter/shell/platform/android/android_surface_software.h"
|
||||
|
||||
#if SHELL_ENABLE_VULKAN
|
||||
#include "flutter/shell/platform/android/android_surface_vulkan.h"
|
||||
#endif // SHELL_ENABLE_VULKAN
|
||||
|
||||
#include "flutter/shell/platform/android/context/android_context.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "flutter/shell/platform/android/platform_message_response_android.h"
|
||||
#include "flutter/shell/platform/android/vsync_waiter_android.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
std::unique_ptr<AndroidSurface> SurfaceFactory(
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade) {
|
||||
FML_CHECK(SurfaceFactory);
|
||||
switch (android_context->RenderingApi()) {
|
||||
case AndroidRenderingAPI::kSoftware:
|
||||
return std::make_unique<AndroidSurfaceSoftware>(
|
||||
android_context, jni_facade, SurfaceFactory);
|
||||
case AndroidRenderingAPI::kOpenGLES:
|
||||
return std::make_unique<AndroidSurfaceGL>(android_context, jni_facade,
|
||||
SurfaceFactory);
|
||||
case AndroidRenderingAPI::kVulkan:
|
||||
#if SHELL_ENABLE_VULKAN
|
||||
return std::make_unique<AndroidSurfaceVulkan>(android_context, jni_facade,
|
||||
SurfaceFactory);
|
||||
#endif // SHELL_ENABLE_VULKAN
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PlatformViewAndroid::PlatformViewAndroid(
|
||||
PlatformView::Delegate& delegate,
|
||||
flutter::TaskRunners task_runners,
|
||||
@ -27,16 +55,23 @@ PlatformViewAndroid::PlatformViewAndroid(
|
||||
: PlatformView(delegate, std::move(task_runners)), jni_facade_(jni_facade) {
|
||||
std::shared_ptr<AndroidContext> android_context;
|
||||
if (use_software_rendering) {
|
||||
android_context = AndroidContext::Create(AndroidRenderingAPI::kSoftware);
|
||||
android_context =
|
||||
std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
|
||||
} else {
|
||||
#if SHELL_ENABLE_VULKAN
|
||||
android_context = AndroidContext::Create(AndroidRenderingAPI::kVulkan);
|
||||
android_context =
|
||||
std::make_shared<AndroidContext>(AndroidRenderingAPI::kVulkan);
|
||||
#else // SHELL_ENABLE_VULKAN
|
||||
android_context = AndroidContext::Create(AndroidRenderingAPI::kOpenGLES);
|
||||
android_context = std::make_shared<AndroidContextGL>(
|
||||
AndroidRenderingAPI::kOpenGLES,
|
||||
fml::MakeRefCounted<AndroidEnvironmentGL>());
|
||||
#endif // SHELL_ENABLE_VULKAN
|
||||
}
|
||||
android_surface_ = AndroidSurface::Create(android_context, jni_facade);
|
||||
FML_CHECK(android_surface_)
|
||||
FML_CHECK(android_context && android_context->IsValid())
|
||||
<< "Could not create an Android context.";
|
||||
|
||||
android_surface_ = SurfaceFactory(std::move(android_context), jni_facade);
|
||||
FML_CHECK(android_surface_ && android_surface_->IsValid())
|
||||
<< "Could not create an OpenGL, Vulkan or Software surface to setup "
|
||||
"rendering.";
|
||||
}
|
||||
|
||||
@ -15,9 +15,9 @@
|
||||
#include "flutter/fml/platform/android/scoped_java_ref.h"
|
||||
#include "flutter/lib/ui/window/platform_message.h"
|
||||
#include "flutter/shell/common/platform_view.h"
|
||||
#include "flutter/shell/platform/android/android_native_window.h"
|
||||
#include "flutter/shell/platform/android/android_surface.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "flutter/shell/platform/android/surface/android_native_window.h"
|
||||
#include "flutter/shell/platform/android/surface/android_surface.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
|
||||
@ -1104,17 +1104,21 @@ void PlatformViewAndroidJNIImpl::FlutterViewEndFrame() {
|
||||
FML_CHECK(CheckException(env));
|
||||
}
|
||||
|
||||
void PlatformViewAndroidJNIImpl::FlutterViewCreateOverlaySurface() {
|
||||
std::unique_ptr<PlatformViewAndroidJNI::OverlayMetadata>
|
||||
PlatformViewAndroidJNIImpl::FlutterViewCreateOverlaySurface() {
|
||||
JNIEnv* env = fml::jni::AttachCurrentThread();
|
||||
|
||||
auto java_object = java_object_.get(env);
|
||||
if (java_object.is_null()) {
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
env->CallVoidMethod(java_object.obj(), g_create_overlay_surface_method);
|
||||
|
||||
FML_CHECK(CheckException(env));
|
||||
// TODO(egarciad): Wire this up.
|
||||
// https://github.com/flutter/flutter/issues/55270
|
||||
return std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(0, nullptr);
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<std::string>>
|
||||
|
||||
@ -66,7 +66,8 @@ class PlatformViewAndroidJNIImpl final : public PlatformViewAndroidJNI {
|
||||
|
||||
void FlutterViewEndFrame() override;
|
||||
|
||||
void FlutterViewCreateOverlaySurface() override;
|
||||
std::unique_ptr<PlatformViewAndroidJNI::OverlayMetadata>
|
||||
FlutterViewCreateOverlaySurface() override;
|
||||
|
||||
std::unique_ptr<std::vector<std::string>>
|
||||
FlutterViewComputePlatformResolvedLocale(
|
||||
|
||||
54
engine/src/flutter/shell/platform/android/surface/BUILD.gn
Normal file
54
engine/src/flutter/shell/platform/android/surface/BUILD.gn
Normal file
@ -0,0 +1,54 @@
|
||||
# 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.
|
||||
|
||||
source_set("surface") {
|
||||
sources = [
|
||||
"android_surface.cc",
|
||||
"android_surface.h",
|
||||
]
|
||||
|
||||
public_configs = [ "//flutter:config" ]
|
||||
|
||||
deps = [
|
||||
":native_window",
|
||||
"//flutter/flow",
|
||||
"//flutter/fml",
|
||||
"//flutter/shell/platform/android/context",
|
||||
"//flutter/shell/platform/android/jni",
|
||||
"//third_party/skia",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("native_window") {
|
||||
sources = [
|
||||
"android_native_window.cc",
|
||||
"android_native_window.h",
|
||||
]
|
||||
|
||||
public_configs = [ "//flutter:config" ]
|
||||
|
||||
deps = [
|
||||
"//flutter/fml",
|
||||
"//third_party/skia",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("surface_mock") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"android_surface_mock.cc",
|
||||
"android_surface_mock.h",
|
||||
]
|
||||
|
||||
public_configs = [ "//flutter:config" ]
|
||||
|
||||
deps = [
|
||||
":surface",
|
||||
"//flutter/shell/gpu:gpu_surface_gl",
|
||||
"//third_party/googletest:gmock",
|
||||
"//third_party/googletest:gtest",
|
||||
"//third_party/skia",
|
||||
]
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/shell/platform/android/android_native_window.h"
|
||||
#include "flutter/shell/platform/android/surface/android_native_window.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
@ -10,7 +10,9 @@ AndroidNativeWindow::AndroidNativeWindow(Handle window) : window_(window) {}
|
||||
|
||||
AndroidNativeWindow::~AndroidNativeWindow() {
|
||||
if (window_ != nullptr) {
|
||||
#if OS_ANDROID
|
||||
ANativeWindow_release(window_);
|
||||
#endif // OS_ANDROID
|
||||
window_ = nullptr;
|
||||
}
|
||||
}
|
||||
@ -24,9 +26,13 @@ AndroidNativeWindow::Handle AndroidNativeWindow::handle() const {
|
||||
}
|
||||
|
||||
SkISize AndroidNativeWindow::GetSize() const {
|
||||
#if OS_ANDROID
|
||||
return window_ == nullptr ? SkISize::Make(0, 0)
|
||||
: SkISize::Make(ANativeWindow_getWidth(window_),
|
||||
ANativeWindow_getHeight(window_));
|
||||
#else // OS_ANDROID
|
||||
return SkISize::Make(0, 0);
|
||||
#endif // OS_ANDROID
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@ -5,10 +5,14 @@
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_NATIVE_WINDOW_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_NATIVE_WINDOW_H_
|
||||
|
||||
#include "flutter/fml/build_config.h"
|
||||
|
||||
#if OS_ANDROID
|
||||
#include <android/native_window.h>
|
||||
#endif // OS_ANDROID
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/memory/ref_counted.h"
|
||||
#include "flutter/fml/memory/ref_ptr.h"
|
||||
#include "third_party/skia/include/core/SkSize.h"
|
||||
|
||||
namespace flutter {
|
||||
@ -16,7 +20,11 @@ namespace flutter {
|
||||
class AndroidNativeWindow
|
||||
: public fml::RefCountedThreadSafe<AndroidNativeWindow> {
|
||||
public:
|
||||
#if OS_ANDROID
|
||||
using Handle = ANativeWindow*;
|
||||
#else // OS_ANDROID
|
||||
using Handle = std::nullptr_t;
|
||||
#endif // OS_ANDROID
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
// 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.
|
||||
|
||||
#include "flutter/shell/platform/android/surface/android_surface.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
AndroidSurface::~AndroidSurface() = default;
|
||||
|
||||
} // namespace flutter
|
||||
@ -5,25 +5,20 @@
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/flow/surface.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/platform/android/jni_util.h"
|
||||
#include "flutter/fml/platform/android/jni_weak_ref.h"
|
||||
#include "flutter/shell/common/platform_view.h"
|
||||
#include "flutter/shell/platform/android/android_context.h"
|
||||
#include "flutter/shell/platform/android/android_native_window.h"
|
||||
#include "flutter/shell/platform/android/context/android_context.h"
|
||||
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
|
||||
#include "flutter/shell/platform/android/surface/android_native_window.h"
|
||||
#include "third_party/skia/include/core/SkSize.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class AndroidSurface {
|
||||
public:
|
||||
static std::unique_ptr<AndroidSurface> Create(
|
||||
using Factory = std::function<std::unique_ptr<AndroidSurface>(
|
||||
std::shared_ptr<AndroidContext> android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade);
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade)>;
|
||||
|
||||
virtual ~AndroidSurface();
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
#include "flutter/shell/platform/android/surface/android_surface_mock.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
std::unique_ptr<GLContextResult> AndroidSurfaceMock::GLContextMakeCurrent() {
|
||||
return std::make_unique<GLContextDefaultResult>(/*static_result=*/true);
|
||||
}
|
||||
|
||||
bool AndroidSurfaceMock::GLContextClearCurrent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AndroidSurfaceMock::GLContextPresent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
intptr_t AndroidSurfaceMock::GLContextFBO() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExternalViewEmbedder* AndroidSurfaceMock::GetExternalViewEmbedder() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@ -0,0 +1,59 @@
|
||||
// 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.
|
||||
|
||||
#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_MOCK_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_MOCK_H_
|
||||
|
||||
#include "flutter/shell/gpu/gpu_surface_gl.h"
|
||||
#include "flutter/shell/platform/android/surface/android_surface.h"
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Mock for |AndroidSurface|. This implementation can be used in unit
|
||||
/// tests without requiring the Android toolchain.
|
||||
///
|
||||
class AndroidSurfaceMock final : public GPUSurfaceGLDelegate,
|
||||
public AndroidSurface {
|
||||
public:
|
||||
MOCK_METHOD(bool, IsValid, (), (const, override));
|
||||
|
||||
MOCK_METHOD(void, TeardownOnScreenContext, (), (override));
|
||||
|
||||
MOCK_METHOD(std::unique_ptr<Surface>,
|
||||
CreateGPUSurface,
|
||||
(GrContext * gr_context),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(bool, OnScreenSurfaceResize, (const SkISize& size), (override));
|
||||
|
||||
MOCK_METHOD(bool, ResourceContextMakeCurrent, (), (override));
|
||||
|
||||
MOCK_METHOD(bool, ResourceContextClearCurrent, (), (override));
|
||||
|
||||
MOCK_METHOD(bool,
|
||||
SetNativeWindow,
|
||||
(fml::RefPtr<AndroidNativeWindow> window),
|
||||
(override));
|
||||
|
||||
// |GPUSurfaceGLDelegate|
|
||||
std::unique_ptr<GLContextResult> GLContextMakeCurrent() override;
|
||||
|
||||
// |GPUSurfaceGLDelegate|
|
||||
bool GLContextClearCurrent() override;
|
||||
|
||||
// |GPUSurfaceGLDelegate|
|
||||
bool GLContextPresent() override;
|
||||
|
||||
// |GPUSurfaceGLDelegate|
|
||||
intptr_t GLContextFBO() const override;
|
||||
|
||||
// |GPUSurfaceGLDelegate|
|
||||
ExternalViewEmbedder* GetExternalViewEmbedder() override;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_MOCK_H_
|
||||
@ -62,7 +62,11 @@ class IOSSurface : public ExternalViewEmbedder {
|
||||
void CancelFrame() override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void BeginFrame(SkISize frame_size, GrContext* context, double device_pixel_ratio) override;
|
||||
void BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio,
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void PrerollCompositeEmbeddedView(int view_id,
|
||||
std::unique_ptr<flutter::EmbeddedViewParams> params) override;
|
||||
|
||||
@ -94,7 +94,10 @@ void IOSSurface::CancelFrame() {
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void IOSSurface::BeginFrame(SkISize frame_size, GrContext* context, double device_pixel_ratio) {
|
||||
void IOSSurface::BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio,
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
|
||||
TRACE_EVENT0("flutter", "IOSSurface::BeginFrame");
|
||||
FML_CHECK(platform_views_controller_ != nullptr);
|
||||
platform_views_controller_->SetFrameSize(frame_size);
|
||||
|
||||
@ -47,9 +47,11 @@ void EmbedderExternalViewEmbedder::CancelFrame() {
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void EmbedderExternalViewEmbedder::BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio) {
|
||||
void EmbedderExternalViewEmbedder::BeginFrame(
|
||||
SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio,
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
|
||||
Reset();
|
||||
|
||||
pending_frame_size_ = frame_size;
|
||||
|
||||
@ -73,9 +73,11 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder {
|
||||
void CancelFrame() override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio) override;
|
||||
void BeginFrame(
|
||||
SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio,
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void PrerollCompositeEmbeddedView(
|
||||
|
||||
@ -18,6 +18,7 @@ source_set("testing_lib") {
|
||||
|
||||
public_deps = [
|
||||
"//flutter/fml",
|
||||
"//third_party/googletest:gmock",
|
||||
"//third_party/googletest:gtest",
|
||||
]
|
||||
public_configs = [ "//flutter:config" ]
|
||||
|
||||
@ -131,16 +131,17 @@ def RunCCTests(build_dir, filter):
|
||||
|
||||
RunEngineExecutable(build_dir, 'runtime_unittests', filter, shuffle_flags)
|
||||
|
||||
# https://github.com/flutter/flutter/issues/36295
|
||||
if not IsWindows():
|
||||
# https://github.com/flutter/flutter/issues/36295
|
||||
RunEngineExecutable(build_dir, 'shell_unittests', filter, shuffle_flags)
|
||||
# https://github.com/google/googletest/issues/2490
|
||||
RunEngineExecutable(build_dir, 'android_external_view_embedder_unittests', filter, shuffle_flags)
|
||||
RunEngineExecutable(build_dir, 'jni_unittests', filter, shuffle_flags)
|
||||
|
||||
RunEngineExecutable(build_dir, 'ui_unittests', filter, shuffle_flags)
|
||||
|
||||
RunEngineExecutable(build_dir, 'testing_unittests', filter, shuffle_flags)
|
||||
|
||||
RunEngineExecutable(build_dir, 'android_external_view_embedder_unittests', filter, shuffle_flags)
|
||||
|
||||
# These unit-tests are Objective-C and can only run on Darwin.
|
||||
if IsMac():
|
||||
RunEngineExecutable(build_dir, 'flutter_channels_unittests', filter, shuffle_flags)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user