From 6ac2e23ea084954aaab9bad109159085bf8c55de Mon Sep 17 00:00:00 2001 From: Boram Bae Date: Tue, 3 May 2022 18:57:22 +0900 Subject: [PATCH] Refactor embedder and introduce FlutterTizenView (#278) * Introduce FlutterTizenView. It is a delegate for the flutter rendering host. and it provides interfaces. * Introduce TizenView. it abstracts the platform window and it provides interfaces. Responsibilities of TizenRenderer is reduced, and those responsibilities are transferred to TizenWindow and FlutterTizenView. * Rename the Flutter-tizen C-APIs. this change requires an update of flutter-tizen and plugin too. * The engine runs as headless mode by default now. Signed-off-by: Boram Bae --- shell/platform/tizen/BUILD.gn | 13 +- .../tizen/channels/platform_channel.cc | 16 +- .../tizen/channels/platform_channel.h | 8 +- .../platform/tizen/channels/window_channel.cc | 37 +- .../platform/tizen/channels/window_channel.h | 13 +- .../platform/tizen/flutter_project_bundle.cc | 4 + shell/platform/tizen/flutter_project_bundle.h | 8 + shell/platform/tizen/flutter_tizen.cc | 45 +- shell/platform/tizen/flutter_tizen_ecore.cc | 52 ++ .../tizen/flutter_tizen_elementary.cc | 52 ++ shell/platform/tizen/flutter_tizen_engine.cc | 204 ++---- shell/platform/tizen/flutter_tizen_engine.h | 61 +- .../tizen/flutter_tizen_engine_unittest.cc | 2 +- shell/platform/tizen/flutter_tizen_view.cc | 303 +++++++++ shell/platform/tizen/flutter_tizen_view.h | 144 ++++ shell/platform/tizen/key_event_handler.cc | 101 --- shell/platform/tizen/key_event_handler.h | 30 - shell/platform/tizen/public/flutter_tizen.h | 63 +- shell/platform/tizen/tizen_event_loop.cc | 28 +- shell/platform/tizen/tizen_event_loop.h | 4 +- .../tizen/tizen_input_method_context.cc | 11 +- .../tizen/tizen_input_method_context.h | 8 +- shell/platform/tizen/tizen_renderer.cc | 11 +- shell/platform/tizen/tizen_renderer.h | 63 +- .../platform/tizen/tizen_renderer_ecore_wl2.h | 93 --- ...rer_ecore_wl2.cc => tizen_renderer_egl.cc} | 625 ++++++------------ shell/platform/tizen/tizen_renderer_egl.h | 61 ++ .../platform/tizen/tizen_renderer_evas_gl.cc | 352 +++------- shell/platform/tizen/tizen_renderer_evas_gl.h | 65 +- shell/platform/tizen/tizen_window.h | 88 +++ .../platform/tizen/tizen_window_ecore_wl2.cc | 396 +++++++++++ shell/platform/tizen/tizen_window_ecore_wl2.h | 80 +++ .../platform/tizen/tizen_window_elementary.cc | 348 ++++++++++ .../platform/tizen/tizen_window_elementary.h | 79 +++ shell/platform/tizen/touch_event_handler.cc | 129 ---- shell/platform/tizen/touch_event_handler.h | 43 -- 36 files changed, 2158 insertions(+), 1482 deletions(-) create mode 100644 shell/platform/tizen/flutter_tizen_ecore.cc create mode 100644 shell/platform/tizen/flutter_tizen_elementary.cc create mode 100644 shell/platform/tizen/flutter_tizen_view.cc create mode 100644 shell/platform/tizen/flutter_tizen_view.h delete mode 100644 shell/platform/tizen/key_event_handler.cc delete mode 100644 shell/platform/tizen/key_event_handler.h delete mode 100644 shell/platform/tizen/tizen_renderer_ecore_wl2.h rename shell/platform/tizen/{tizen_renderer_ecore_wl2.cc => tizen_renderer_egl.cc} (52%) create mode 100644 shell/platform/tizen/tizen_renderer_egl.h create mode 100644 shell/platform/tizen/tizen_window.h create mode 100644 shell/platform/tizen/tizen_window_ecore_wl2.cc create mode 100644 shell/platform/tizen/tizen_window_ecore_wl2.h create mode 100644 shell/platform/tizen/tizen_window_elementary.cc create mode 100644 shell/platform/tizen/tizen_window_elementary.h delete mode 100644 shell/platform/tizen/touch_event_handler.cc delete mode 100644 shell/platform/tizen/touch_event_handler.h diff --git a/shell/platform/tizen/BUILD.gn b/shell/platform/tizen/BUILD.gn index a235bfeabaa9c..44574e346ac56 100644 --- a/shell/platform/tizen/BUILD.gn +++ b/shell/platform/tizen/BUILD.gn @@ -123,13 +123,12 @@ template("embedder") { "flutter_tizen.cc", "flutter_tizen_engine.cc", "flutter_tizen_texture_registrar.cc", - "key_event_handler.cc", + "flutter_tizen_view.cc", "logger.cc", "system_utils.cc", "tizen_event_loop.cc", "tizen_input_method_context.cc", "tizen_renderer.cc", - "touch_event_handler.cc", ] if (target_name != "flutter_tizen_wearable") { @@ -185,7 +184,11 @@ template("embedder") { ] if (use_evas_gl_renderer) { - sources += [ "tizen_renderer_evas_gl.cc" ] + sources += [ + "flutter_tizen_elementary.cc", + "tizen_renderer_evas_gl.cc", + "tizen_window_elementary.cc", + ] libs += [ "ecore_evas", @@ -196,8 +199,10 @@ template("embedder") { public_configs += [ ":evas_gl_renderer" ] } else { sources += [ - "tizen_renderer_ecore_wl2.cc", + "flutter_tizen_ecore.cc", + "tizen_renderer_egl.cc", "tizen_vsync_waiter.cc", + "tizen_window_ecore_wl2.cc", ] libs += [ diff --git a/shell/platform/tizen/channels/platform_channel.cc b/shell/platform/tizen/channels/platform_channel.cc index 95f89ccf1eb8c..5672bd73ef908 100644 --- a/shell/platform/tizen/channels/platform_channel.cc +++ b/shell/platform/tizen/channels/platform_channel.cc @@ -58,12 +58,12 @@ std::string text_clipboard = ""; } // namespace PlatformChannel::PlatformChannel(BinaryMessenger* messenger, - TizenRenderer* renderer) + TizenWindow* window) : channel_(std::make_unique>( messenger, kChannelName, &JsonMethodCodec::GetInstance())), - renderer_(renderer) { + window_(window) { channel_->SetMethodCallHandler( [this](const MethodCall& call, std::unique_ptr> result) { @@ -164,13 +164,13 @@ void PlatformChannel::HapticFeedbackVibrate(const std::string& feedback_type) { } void PlatformChannel::RestoreSystemUiOverlays() { - if (!renderer_) { + if (!window_) { return; } #ifdef COMMON_PROFILE auto& shell = TizenShell::GetInstance(); - shell.InitializeSoftkey(renderer_->GetWindowId()); + shell.InitializeSoftkey(window_->GetWindowId()); if (shell.IsSoftkeyShown()) { shell.ShowSoftkey(); @@ -182,13 +182,13 @@ void PlatformChannel::RestoreSystemUiOverlays() { void PlatformChannel::SetEnabledSystemUiOverlays( const std::vector& overlays) { - if (!renderer_) { + if (!window_) { return; } #ifdef COMMON_PROFILE auto& shell = TizenShell::GetInstance(); - shell.InitializeSoftkey(renderer_->GetWindowId()); + shell.InitializeSoftkey(window_->GetWindowId()); if (std::find(overlays.begin(), overlays.end(), kSystemUiOverlayBottom) != overlays.end()) { @@ -201,7 +201,7 @@ void PlatformChannel::SetEnabledSystemUiOverlays( void PlatformChannel::SetPreferredOrientations( const std::vector& orientations) { - if (!renderer_) { + if (!window_) { return; } @@ -220,7 +220,7 @@ void PlatformChannel::SetPreferredOrientations( // default. rotations = {0, 90, 180, 270}; } - renderer_->SetPreferredOrientations(rotations); + window_->SetPreferredOrientations(rotations); } } // namespace flutter diff --git a/shell/platform/tizen/channels/platform_channel.h b/shell/platform/tizen/channels/platform_channel.h index 49fcb031258d5..4e11fdd5ca7af 100644 --- a/shell/platform/tizen/channels/platform_channel.h +++ b/shell/platform/tizen/channels/platform_channel.h @@ -11,14 +11,14 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/method_channel.h" -#include "flutter/shell/platform/tizen/tizen_renderer.h" +#include "flutter/shell/platform/tizen/tizen_window.h" #include "rapidjson/document.h" namespace flutter { class PlatformChannel { public: - explicit PlatformChannel(BinaryMessenger* messenger, TizenRenderer* renderer); + explicit PlatformChannel(BinaryMessenger* messenger, TizenWindow* window); virtual ~PlatformChannel(); private: @@ -35,9 +35,9 @@ class PlatformChannel { std::unique_ptr> channel_; - // A reference to the renderer object managed by FlutterTizenEngine. + // A reference to the window object managed by FlutterTizenView. // This can be nullptr if the engine is running in headless mode. - TizenRenderer* renderer_; + TizenWindow* window_; }; } // namespace flutter diff --git a/shell/platform/tizen/channels/window_channel.cc b/shell/platform/tizen/channels/window_channel.cc index 53a221d6cad72..b7e246cb06946 100644 --- a/shell/platform/tizen/channels/window_channel.cc +++ b/shell/platform/tizen/channels/window_channel.cc @@ -16,10 +16,8 @@ constexpr char kChannelName[] = "tizen/internal/window"; } // namespace -WindowChannel::WindowChannel(BinaryMessenger* messenger, - TizenRenderer* renderer, - TizenRenderer::Delegate* delegate) - : renderer_(renderer), delegate_(delegate) { +WindowChannel::WindowChannel(BinaryMessenger* messenger, TizenWindow* window) + : window_(window) { channel_ = std::make_unique>( messenger, kChannelName, &StandardMethodCodec::GetInstance()); channel_->SetMethodCallHandler( @@ -37,12 +35,12 @@ void WindowChannel::HandleMethodCall( const std::string& method_name = method_call.method_name(); if (method_name == "getWindowGeometry") { - TizenRenderer::Geometry geometry = renderer_->GetWindowGeometry(); + TizenWindow::Geometry geometry = window_->GetWindowGeometry(); EncodableMap map; - map[EncodableValue("x")] = EncodableValue(geometry.x); - map[EncodableValue("y")] = EncodableValue(geometry.y); - map[EncodableValue("width")] = EncodableValue(geometry.w); - map[EncodableValue("height")] = EncodableValue(geometry.h); + map[EncodableValue("x")] = EncodableValue(geometry.left); + map[EncodableValue("y")] = EncodableValue(geometry.top); + map[EncodableValue("width")] = EncodableValue(geometry.width); + map[EncodableValue("height")] = EncodableValue(geometry.height); result->Success(EncodableValue(map)); } else if (method_name == "setWindowGeometry") { #ifdef TIZEN_RENDERER_EVAS_GL @@ -59,18 +57,23 @@ void WindowChannel::HandleMethodCall( EncodableValueHolder width(arguments, "width"); EncodableValueHolder height(arguments, "height"); - TizenRenderer::Geometry geometry = renderer_->GetWindowGeometry(); - - delegate_->OnGeometryChange(x ? *x : geometry.x, y ? *y : geometry.y, - width ? *width : geometry.w, - height ? *height : geometry.h); + TizenWindow::Geometry geometry = window_->GetWindowGeometry(); + // FIXME: Use SetWindowGeometry() instead of OnGeometryChanged() + // After the SetWindowGeometry was successfully executed, I expected a + // handler of ECORE_WL2_EVENT_WINDOW_CONFIGURE to be called, but it didn't. + window_->OnGeometryChanged({ + x ? *x : geometry.left, + y ? *y : geometry.top, + width ? *width : geometry.width, + height ? *height : geometry.height, + }); result->Success(); #endif } else if (method_name == "getScreenGeometry") { - TizenRenderer::Geometry geometry = renderer_->GetScreenGeometry(); + TizenWindow::Geometry geometry = window_->GetScreenGeometry(); EncodableMap map; - map[EncodableValue("width")] = EncodableValue(geometry.w); - map[EncodableValue("height")] = EncodableValue(geometry.h); + map[EncodableValue("width")] = EncodableValue(geometry.width); + map[EncodableValue("height")] = EncodableValue(geometry.height); result->Success(EncodableValue(map)); } else { result->NotImplemented(); diff --git a/shell/platform/tizen/channels/window_channel.h b/shell/platform/tizen/channels/window_channel.h index 19a9a442fe36a..78c01ee2b94a1 100644 --- a/shell/platform/tizen/channels/window_channel.h +++ b/shell/platform/tizen/channels/window_channel.h @@ -10,16 +10,14 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/method_channel.h" -#include "flutter/shell/platform/tizen/tizen_renderer.h" +#include "flutter/shell/platform/tizen/tizen_window.h" namespace flutter { // Channel to get/set application's window size and device's screen size. class WindowChannel { public: - explicit WindowChannel(BinaryMessenger* messenger, - TizenRenderer* renderer, - TizenRenderer::Delegate* delegate); + explicit WindowChannel(BinaryMessenger* messenger, TizenWindow* window); virtual ~WindowChannel(); private: @@ -28,11 +26,8 @@ class WindowChannel { std::unique_ptr> channel_; - // A reference to the renderer object managed by FlutterTizenEngine. - // This can be nullptr if the engine is running in headless mode. - TizenRenderer* renderer_; - - [[maybe_unused]] TizenRenderer::Delegate* delegate_; + // A reference to the renderer object managed by FlutterTizenView. + TizenWindow* window_; }; } // namespace flutter diff --git a/shell/platform/tizen/flutter_project_bundle.cc b/shell/platform/tizen/flutter_project_bundle.cc index b81f5e21a6cfb..23ef6d2153b93 100644 --- a/shell/platform/tizen/flutter_project_bundle.cc +++ b/shell/platform/tizen/flutter_project_bundle.cc @@ -40,6 +40,10 @@ FlutterProjectBundle::FlutterProjectBundle( aot_library_path_ = std::filesystem::path(properties.aot_library_path); } + if (properties.entrypoint != nullptr) { + custom_dart_entrypoint_ = std::string(properties.entrypoint); + } + for (int i = 0; i < properties.dart_entrypoint_argc; i++) { dart_entrypoint_arguments_.push_back( std::string(properties.dart_entrypoint_argv[i])); diff --git a/shell/platform/tizen/flutter_project_bundle.h b/shell/platform/tizen/flutter_project_bundle.h index 399b2aa14d171..c167357af5768 100644 --- a/shell/platform/tizen/flutter_project_bundle.h +++ b/shell/platform/tizen/flutter_project_bundle.h @@ -56,6 +56,11 @@ class FlutterProjectBundle { // Logs and returns nullptr on failure. UniqueAotDataPtr LoadAotData(const FlutterEngineProcTable& engine_procs); + // Returns custom entrypoint in the Dart project. + const std::string& custom_dart_entrypoint() { + return custom_dart_entrypoint_; + } + // Returns the command line arguments to be passed through to the Dart // entrypoint. const std::vector& dart_entrypoint_arguments() const { @@ -70,6 +75,9 @@ class FlutterProjectBundle { // Path to the AOT library file, if any. std::filesystem::path aot_library_path_; + // Custom entrypoint in the Dart project + std::string custom_dart_entrypoint_; + // Dart entrypoint arguments. std::vector dart_entrypoint_arguments_; }; diff --git a/shell/platform/tizen/flutter_tizen.cc b/shell/platform/tizen/flutter_tizen.cc index b97f78f6c1d82..2f58bc48074a1 100644 --- a/shell/platform/tizen/flutter_tizen.cc +++ b/shell/platform/tizen/flutter_tizen.cc @@ -10,8 +10,10 @@ #include "flutter/shell/platform/common/incoming_message_dispatcher.h" #include "flutter/shell/platform/tizen/flutter_project_bundle.h" #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" +#include "flutter/shell/platform/tizen/flutter_tizen_view.h" #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/public/flutter_platform_view.h" +#include "flutter/shell/platform/tizen/tizen_window.h" namespace { @@ -39,8 +41,7 @@ FlutterDesktopTextureRegistrarRef HandleForTextureRegistrar( } // namespace -FlutterDesktopEngineRef FlutterDesktopRunEngine( - const FlutterDesktopWindowProperties& window_properties, +FlutterDesktopEngineRef FlutterDesktopEngineCreate( const FlutterDesktopEngineProperties& engine_properties) { flutter::FlutterProjectBundle project(engine_properties); if (project.HasArgument("--verbose-logging")) { @@ -53,20 +54,14 @@ FlutterDesktopEngineRef FlutterDesktopRunEngine( flutter::Logger::Start(); auto engine = std::make_unique(project); - if (window_properties.headed) { - engine->InitializeRenderer( - window_properties.x, window_properties.y, window_properties.width, - window_properties.height, window_properties.transparent, - window_properties.focusable, window_properties.top_level); - } - if (!engine->RunEngine(engine_properties.entrypoint)) { - FT_LOG(Error) << "Failed to start the Flutter engine."; - return nullptr; - } return HandleForEngine(engine.release()); } -void FlutterDesktopShutdownEngine(FlutterDesktopEngineRef engine_ref) { +bool FlutterDesktopEngineRun(const FlutterDesktopEngineRef engine) { + return EngineFromHandle(engine)->RunEngine(); +} + +void FlutterDesktopEngineShutdown(FlutterDesktopEngineRef engine_ref) { flutter::Logger::Stop(); flutter::FlutterTizenEngine* engine = EngineFromHandle(engine_ref); @@ -74,8 +69,9 @@ void FlutterDesktopShutdownEngine(FlutterDesktopEngineRef engine_ref) { delete engine; } -void* FlutterDesktopGetWindow(FlutterDesktopPluginRegistrarRef registrar) { - return registrar->engine->renderer()->GetWindowHandle(); +void* FlutterDesktopPluginRegistrarGetNativeWindow( + FlutterDesktopPluginRegistrarRef registrar) { + return registrar->engine->view()->window()->GetWindowHandle(); } void FlutterDesktopPluginRegistrarEnableInputBlocking( @@ -85,7 +81,7 @@ void FlutterDesktopPluginRegistrarEnableInputBlocking( channel); } -FlutterDesktopPluginRegistrarRef FlutterDesktopGetPluginRegistrar( +FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar( FlutterDesktopEngineRef engine, const char* plugin_name) { // Currently, one registrar acts as the registrar for all plugins, so the @@ -144,33 +140,34 @@ void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger, user_data); } -void FlutterDesktopNotifyAppControl(FlutterDesktopEngineRef engine, - void* app_control) { +void FlutterDesktopEngineNotifyAppControl(FlutterDesktopEngineRef engine, + void* app_control) { EngineFromHandle(engine)->app_control_channel()->NotifyAppControl( app_control); } -void FlutterDesktopNotifyLocaleChange(FlutterDesktopEngineRef engine) { +void FlutterDesktopEngineNotifyLocaleChange(FlutterDesktopEngineRef engine) { EngineFromHandle(engine)->SetupLocales(); } -void FlutterDesktopNotifyLowMemoryWarning(FlutterDesktopEngineRef engine) { +void FlutterDesktopEngineNotifyLowMemoryWarning( + FlutterDesktopEngineRef engine) { EngineFromHandle(engine)->NotifyLowMemoryWarning(); } -void FlutterDesktopNotifyAppIsInactive(FlutterDesktopEngineRef engine) { +void FlutterDesktopEngineNotifyAppIsInactive(FlutterDesktopEngineRef engine) { EngineFromHandle(engine)->lifecycle_channel()->AppIsInactive(); } -void FlutterDesktopNotifyAppIsResumed(FlutterDesktopEngineRef engine) { +void FlutterDesktopEngineNotifyAppIsResumed(FlutterDesktopEngineRef engine) { EngineFromHandle(engine)->lifecycle_channel()->AppIsResumed(); } -void FlutterDesktopNotifyAppIsPaused(FlutterDesktopEngineRef engine) { +void FlutterDesktopEngineNotifyAppIsPaused(FlutterDesktopEngineRef engine) { EngineFromHandle(engine)->lifecycle_channel()->AppIsPaused(); } -void FlutterDesktopNotifyAppIsDetached(FlutterDesktopEngineRef engine) { +void FlutterDesktopEngineNotifyAppIsDetached(FlutterDesktopEngineRef engine) { EngineFromHandle(engine)->lifecycle_channel()->AppIsDetached(); } diff --git a/shell/platform/tizen/flutter_tizen_ecore.cc b/shell/platform/tizen/flutter_tizen_ecore.cc new file mode 100644 index 0000000000000..a8ba934721c2c --- /dev/null +++ b/shell/platform/tizen/flutter_tizen_ecore.cc @@ -0,0 +1,52 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "public/flutter_tizen.h" + +#include "flutter/shell/platform/tizen/flutter_tizen_engine.h" +#include "flutter/shell/platform/tizen/flutter_tizen_view.h" +#include "flutter/shell/platform/tizen/tizen_window_ecore_wl2.h" + +namespace { + +// Returns the engine corresponding to the given opaque API handle. +flutter::FlutterTizenEngine* EngineFromHandle(FlutterDesktopEngineRef ref) { + return reinterpret_cast(ref); +} + +FlutterDesktopViewRef HandleForView(flutter::FlutterTizenView* view) { + return reinterpret_cast(view); +} + +} // namespace + +FlutterDesktopViewRef FlutterDesktopViewCreateFromNewWindow( + const FlutterDesktopWindowProperties& window_properties, + FlutterDesktopEngineRef engine) { + flutter::TizenWindow::Geometry window_geometry = { + window_properties.x, + window_properties.y, + window_properties.width, + window_properties.height, + }; + + std::unique_ptr window = + std::make_unique( + window_geometry, window_properties.transparent, + window_properties.focusable, window_properties.top_level); + + auto view = std::make_unique(std::move(window)); + + // Take ownership of the engine, starting it if necessary. + view->SetEngine( + std::unique_ptr(EngineFromHandle(engine))); + view->CreateRenderSurface(); + if (!view->engine()->IsRunning()) { + view->engine()->RunEngine(); + } + + view->SendInitialGeometry(); + + return HandleForView(view.release()); +} diff --git a/shell/platform/tizen/flutter_tizen_elementary.cc b/shell/platform/tizen/flutter_tizen_elementary.cc new file mode 100644 index 0000000000000..aade8e8f0a888 --- /dev/null +++ b/shell/platform/tizen/flutter_tizen_elementary.cc @@ -0,0 +1,52 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "public/flutter_tizen.h" + +#include "flutter/shell/platform/tizen/flutter_tizen_engine.h" +#include "flutter/shell/platform/tizen/flutter_tizen_view.h" +#include "flutter/shell/platform/tizen/tizen_window_elementary.h" + +namespace { + +// Returns the engine corresponding to the given opaque API handle. +flutter::FlutterTizenEngine* EngineFromHandle(FlutterDesktopEngineRef ref) { + return reinterpret_cast(ref); +} + +FlutterDesktopViewRef HandleForView(flutter::FlutterTizenView* view) { + return reinterpret_cast(view); +} + +} // namespace + +FlutterDesktopViewRef FlutterDesktopViewCreateFromNewWindow( + const FlutterDesktopWindowProperties& window_properties, + FlutterDesktopEngineRef engine) { + flutter::TizenWindow::Geometry window_geometry = { + window_properties.x, + window_properties.y, + window_properties.width, + window_properties.height, + }; + + std::unique_ptr window = + std::make_unique( + window_geometry, window_properties.transparent, + window_properties.focusable, window_properties.top_level); + + auto view = std::make_unique(std::move(window)); + + // Take ownership of the engine, starting it if necessary. + view->SetEngine( + std::unique_ptr(EngineFromHandle(engine))); + view->CreateRenderSurface(); + if (!view->engine()->IsRunning()) { + view->engine()->RunEngine(); + } + + view->SendInitialGeometry(); + + return HandleForView(view.release()); +} diff --git a/shell/platform/tizen/flutter_tizen_engine.cc b/shell/platform/tizen/flutter_tizen_engine.cc index 2d6c0a0d5e21e..d28a5b5549a96 100644 --- a/shell/platform/tizen/flutter_tizen_engine.cc +++ b/shell/platform/tizen/flutter_tizen_engine.cc @@ -13,6 +13,7 @@ #include "flutter/shell/platform/tizen/accessibility_bridge_delegate_tizen.h" #include "flutter/shell/platform/tizen/flutter_platform_node_delegate_tizen.h" #endif +#include "flutter/shell/platform/tizen/flutter_tizen_view.h" #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/system_utils.h" #include "flutter/shell/platform/tizen/tizen_input_method_context.h" @@ -27,16 +28,6 @@ constexpr size_t kPlatformTaskRunnerIdentifier = 1; constexpr size_t kRenderTaskRunnerIdentifier = 2; #endif -#if defined(MOBILE_PROFILE) -constexpr double kProfileFactor = 0.7; -#elif defined(WEARABLE_PROFILE) -constexpr double kProfileFactor = 0.4; -#elif defined(TV_PROFILE) -constexpr double kProfileFactor = 2.0; -#else -constexpr double kProfileFactor = 1.0; -#endif - // Converts a LanguageInfo struct to a FlutterLocale struct. |info| must outlive // the returned value, since the returned FlutterLocale has pointers into it. FlutterLocale CovertToFlutterLocale(const LanguageInfo& info) { @@ -74,33 +65,8 @@ FlutterTizenEngine::FlutterTizenEngine(const FlutterProjectBundle& project) } }); - messenger_ = std::make_unique(); - messenger_->engine = this; - message_dispatcher_ = - std::make_unique(messenger_.get()); - - plugin_registrar_ = std::make_unique(); - plugin_registrar_->engine = this; - - transformation_ = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; -} - -FlutterTizenEngine::~FlutterTizenEngine() { - renderer_ = nullptr; -} - -void FlutterTizenEngine::InitializeRenderer(int32_t x, - int32_t y, - int32_t width, - int32_t height, - bool transparent, - bool focusable, - bool top_level) { - TizenRenderer::Geometry geometry = {x, y, width, height}; - #ifdef TIZEN_RENDERER_EVAS_GL - renderer_ = std::make_unique( - geometry, transparent, focusable, top_level, *this); + renderer_ = std::make_unique(); render_loop_ = std::make_unique( std::this_thread::get_id(), // main thread @@ -112,14 +78,23 @@ void FlutterTizenEngine::InitializeRenderer(int32_t x, }, renderer_.get()); #else - renderer_ = std::make_unique( - geometry, transparent, focusable, top_level, *this); - - tizen_vsync_waiter_ = std::make_unique(this); + renderer_ = std::make_unique(); #endif + + messenger_ = std::make_unique(); + messenger_->engine = this; + message_dispatcher_ = + std::make_unique(messenger_.get()); + + plugin_registrar_ = std::make_unique(); + plugin_registrar_->engine = this; } -bool FlutterTizenEngine::RunEngine(const char* entrypoint) { +FlutterTizenEngine::~FlutterTizenEngine() { + renderer_ = nullptr; +} + +bool FlutterTizenEngine::RunEngine() { if (engine_ != nullptr) { FT_LOG(Error) << "The engine has already started."; return false; @@ -225,6 +200,7 @@ bool FlutterTizenEngine::RunEngine(const char* entrypoint) { #endif #ifndef TIZEN_RENDERER_EVAS_GL if (IsHeaded()) { + tizen_vsync_waiter_ = std::make_unique(this); args.vsync_callback = [](void* user_data, intptr_t baton) -> void { reinterpret_cast(user_data) ->tizen_vsync_waiter_->AsyncWaitForVsync(baton); @@ -234,8 +210,8 @@ bool FlutterTizenEngine::RunEngine(const char* entrypoint) { if (aot_data_) { args.aot_data = aot_data_.get(); } - if (entrypoint) { - args.custom_dart_entrypoint = entrypoint; + if (!project_->custom_dart_entrypoint().empty()) { + args.custom_dart_entrypoint = project_->custom_dart_entrypoint().c_str(); } FlutterRendererConfig renderer_config = GetRendererConfig(); @@ -256,8 +232,6 @@ bool FlutterTizenEngine::RunEngine(const char* entrypoint) { internal_plugin_registrar_->messenger()); lifecycle_channel_ = std::make_unique( internal_plugin_registrar_->messenger()); - platform_channel_ = std::make_unique( - internal_plugin_registrar_->messenger(), renderer_.get()); settings_channel_ = std::make_unique( internal_plugin_registrar_->messenger()); @@ -269,16 +243,6 @@ bool FlutterTizenEngine::RunEngine(const char* entrypoint) { internal_plugin_registrar_->messenger()); platform_view_channel_ = std::make_unique( internal_plugin_registrar_->messenger()); - text_input_channel_ = std::make_unique( - internal_plugin_registrar_->messenger(), - std::make_unique(this)); - window_channel_ = std::make_unique( - internal_plugin_registrar_->messenger(), renderer_.get(), this); - - key_event_handler_ = std::make_unique(this); - touch_event_handler_ = std::make_unique(this); - - SetWindowOrientation(0); } accessibility_settings_ = std::make_unique(this); @@ -306,6 +270,10 @@ bool FlutterTizenEngine::StopEngine() { return false; } +void FlutterTizenEngine::SetView(FlutterTizenView* view) { + view_ = view; +} + void FlutterTizenEngine::SetPluginRegistrarDestructionCallback( FlutterDesktopOnPluginRegistrarDestroyed callback) { plugin_registrar_destruction_callback_ = callback; @@ -367,80 +335,10 @@ void FlutterTizenEngine::SendWindowMetrics(int32_t x, event.top = static_cast(y); event.width = static_cast(width); event.height = static_cast(height); - if (pixel_ratio == 0.0) { - // The scale factor is computed based on the display DPI and the current - // profile. A fixed DPI value (72) is used on TVs. See: - // https://docs.tizen.org/application/native/guides/ui/efl/multiple-screens -#ifdef TV_PROFILE - double dpi = 72.0; -#else - double dpi = static_cast(renderer_->GetDpi()); -#endif - double scale_factor = dpi / 90.0 * kProfileFactor; - event.pixel_ratio = std::max(scale_factor, 1.0); - } else { - event.pixel_ratio = pixel_ratio; - } + event.pixel_ratio = pixel_ratio; embedder_api_.SendWindowMetricsEvent(engine_, &event); } -// This must be called at least once in order to initialize the value of -// transformation_. -void FlutterTizenEngine::SetWindowOrientation(int32_t degree) { - if (!renderer_->IsValid()) { - return; - } - - renderer_->SetRotate(degree); - // Compute renderer transformation based on the angle of rotation. - double rad = (360 - degree) * M_PI / 180; - TizenRenderer::Geometry geometry = renderer_->GetWindowGeometry(); - double width = geometry.w; - double height = geometry.h; - - double trans_x = 0.0, trans_y = 0.0; - if (degree == 90) { - trans_y = height; - } else if (degree == 180) { - trans_x = width; - trans_y = height; - } else if (degree == 270) { - trans_x = width; - } - transformation_ = { - cos(rad), -sin(rad), trans_x, // x - sin(rad), cos(rad), trans_y, // y - 0.0, 0.0, 1.0 // perspective - }; - touch_event_handler_->rotation = degree; - if (degree == 90 || degree == 270) { - std::swap(width, height); - } - renderer_->ResizeWithRotation(geometry.x, geometry.y, width, height, degree); - // Window position does not change on rotation regardless of its orientation. - SendWindowMetrics(geometry.x, geometry.y, width, height, 0.0); -} - -void FlutterTizenEngine::OnOrientationChange(int32_t degree) { - SetWindowOrientation(degree); -} - -void FlutterTizenEngine::OnGeometryChange(int32_t x, - int32_t y, - int32_t width, - int32_t height) { -#ifdef TIZEN_RENDERER_EVAS_GL - FT_UNIMPLEMENTED(); -#else - if (!renderer_->IsValid()) { - return; - } - renderer_->SetGeometry(x, y, width, height); - renderer_->ResizeWithRotation(x, y, width, height, 0); - SendWindowMetrics(x, y, width, height, 0.0); -#endif -} - void FlutterTizenEngine::OnVsync(intptr_t baton, uint64_t frame_start_time_nanos, uint64_t frame_target_time_nanos) { @@ -512,33 +410,55 @@ FlutterRendererConfig FlutterTizenEngine::GetRendererConfig() { config.type = kOpenGL; config.open_gl.struct_size = sizeof(config.open_gl); config.open_gl.make_current = [](void* user_data) -> bool { - return reinterpret_cast(user_data) - ->renderer_->OnMakeCurrent(); + auto* engine = reinterpret_cast(user_data); + if (!engine->view()) { + return false; + } + return engine->view()->OnMakeCurrent(); }; config.open_gl.make_resource_current = [](void* user_data) -> bool { - return reinterpret_cast(user_data) - ->renderer_->OnMakeResourceCurrent(); + auto* engine = reinterpret_cast(user_data); + if (!engine->view()) { + return false; + } + return engine->view()->OnMakeResourceCurrent(); }; config.open_gl.clear_current = [](void* user_data) -> bool { - return reinterpret_cast(user_data) - ->renderer_->OnClearCurrent(); + auto* engine = reinterpret_cast(user_data); + if (!engine->view()) { + return false; + } + return engine->view()->OnClearCurrent(); }; config.open_gl.present = [](void* user_data) -> bool { - return reinterpret_cast(user_data) - ->renderer_->OnPresent(); + auto* engine = reinterpret_cast(user_data); + if (!engine->view()) { + return false; + } + return engine->view()->OnPresent(); }; config.open_gl.fbo_callback = [](void* user_data) -> uint32_t { - return reinterpret_cast(user_data) - ->renderer_->OnGetFBO(); + auto* engine = reinterpret_cast(user_data); + if (!engine->view()) { + return false; + } + return engine->view()->OnGetFBO(); }; config.open_gl.surface_transformation = [](void* user_data) -> FlutterTransformation { - return reinterpret_cast(user_data)->transformation_; + auto* engine = reinterpret_cast(user_data); + if (!engine->view()) { + return FlutterTransformation(); + } + return engine->view()->GetFlutterTransformation(); }; config.open_gl.gl_proc_resolver = [](void* user_data, const char* name) -> void* { - return reinterpret_cast(user_data) - ->renderer_->OnProcResolver(name); + auto* engine = reinterpret_cast(user_data); + if (!engine->view()) { + return nullptr; + } + return engine->view()->OnProcResolver(name); }; config.open_gl.gl_external_texture_frame_callback = [](void* user_data, int64_t texture_id, size_t width, size_t height, @@ -616,8 +536,10 @@ void FlutterTizenEngine::OnUpdateSemanticsCustomActions( bridge->GetFlutterPlatformNodeDelegateFromID(0); std::shared_ptr window = FlutterPlatformAppDelegateTizen::GetInstance().GetWindow().lock(); - TizenRenderer::Geometry geometry = engine->renderer_->GetWindowGeometry(); - window->SetGeometry(geometry.x, geometry.y, geometry.w, geometry.h); + TizenWindow::Geometry geometry = + engine->view_->window()->GetWindowGeometry(); + window->SetGeometry(geometry.left, geometry.top, geometry.width, + geometry.height); window->SetRootNode(root); return; } diff --git a/shell/platform/tizen/flutter_tizen_engine.h b/shell/platform/tizen/flutter_tizen_engine.h index 78c464d890787..a63fee393c759 100644 --- a/shell/platform/tizen/flutter_tizen_engine.h +++ b/shell/platform/tizen/flutter_tizen_engine.h @@ -20,24 +20,19 @@ #include "flutter/shell/platform/tizen/channels/key_event_channel.h" #include "flutter/shell/platform/tizen/channels/lifecycle_channel.h" #include "flutter/shell/platform/tizen/channels/navigation_channel.h" -#include "flutter/shell/platform/tizen/channels/platform_channel.h" #include "flutter/shell/platform/tizen/channels/platform_view_channel.h" #include "flutter/shell/platform/tizen/channels/settings_channel.h" -#include "flutter/shell/platform/tizen/channels/text_input_channel.h" -#include "flutter/shell/platform/tizen/channels/window_channel.h" #include "flutter/shell/platform/tizen/flutter_project_bundle.h" #include "flutter/shell/platform/tizen/flutter_tizen_texture_registrar.h" -#include "flutter/shell/platform/tizen/key_event_handler.h" #include "flutter/shell/platform/tizen/public/flutter_tizen.h" #include "flutter/shell/platform/tizen/tizen_event_loop.h" #include "flutter/shell/platform/tizen/tizen_renderer.h" #ifdef TIZEN_RENDERER_EVAS_GL #include "flutter/shell/platform/tizen/tizen_renderer_evas_gl.h" #else -#include "flutter/shell/platform/tizen/tizen_renderer_ecore_wl2.h" +#include "flutter/shell/platform/tizen/tizen_renderer_egl.h" #include "flutter/shell/platform/tizen/tizen_vsync_waiter.h" #endif -#include "flutter/shell/platform/tizen/touch_event_handler.h" // State associated with the plugin registrar. struct FlutterDesktopPluginRegistrar { @@ -53,8 +48,10 @@ struct FlutterDesktopMessenger { namespace flutter { +class FlutterTizenView; + // Manages state associated with the underlying FlutterEngine. -class FlutterTizenEngine : public TizenRenderer::Delegate { +class FlutterTizenEngine { public: // Creates a new Flutter engine object configured to run |project|. explicit FlutterTizenEngine(const FlutterProjectBundle& project); @@ -65,24 +62,25 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { FlutterTizenEngine(FlutterTizenEngine const&) = delete; FlutterTizenEngine& operator=(FlutterTizenEngine const&) = delete; - // Sets up an instance of TizenRenderer. - void InitializeRenderer(int32_t x, - int32_t y, - int32_t width, - int32_t height, - bool transparent, - bool focusable, - bool top_level); - // Starts running the engine with the given entrypoint. If null, defaults to // main(). // // Returns false if the engine couldn't be started. - bool RunEngine(const char* entrypoint); + bool RunEngine(); + + // Returns true if the engine is currently running. + bool IsRunning() { return engine_ != nullptr; } // Stops the engine. bool StopEngine(); + // Sets the view that is displaying this engine's content. + void SetView(FlutterTizenView* view); + + // The view displaying this engine's content, if any. This will be null for + // headless engines. + FlutterTizenView* view() { return view_; } + FlutterDesktopMessengerRef messenger() { return messenger_.get(); } IncomingMessageDispatcher* message_dispatcher() { @@ -113,8 +111,6 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { return platform_view_channel_.get(); } - TextInputChannel* text_input_channel() { return text_input_channel_.get(); } - #ifndef WEARABLE_PROFILE std::weak_ptr accessibility_bridge() { return accessibility_bridge_; @@ -150,12 +146,6 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { int32_t height, double pixel_ratio); - void SetWindowOrientation(int32_t degree); - void OnOrientationChange(int32_t degree) override; - void OnGeometryChange(int32_t x, - int32_t y, - int32_t width, - int32_t height) override; void OnVsync(intptr_t baton, uint64_t frame_start_time_nanos, uint64_t frame_target_time_nanos); @@ -193,7 +183,7 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { friend class EngineModifier; // Whether the engine is running in headed or headless mode. - bool IsHeaded() { return renderer_ != nullptr; } + bool IsHeaded() { return view_ != nullptr; } // Converts a FlutterPlatformMessage to an equivalent FlutterDesktopMessage. FlutterDesktopMessage ConvertToDesktopMessage( @@ -228,11 +218,8 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { // AOT data for this engine instance, if applicable. UniqueAotDataPtr aot_data_; - // An event dispatcher for Ecore key events. - std::unique_ptr key_event_handler_; - - // An event dispatcher for Ecore mouse events. - std::unique_ptr touch_event_handler_; + // The view displaying the content running in this engine, if any. + FlutterTizenView* view_ = nullptr; // The plugin messenger handle given to API clients. std::unique_ptr messenger_; @@ -276,21 +263,12 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { // A plugin that implements the Flutter navigation channel. std::unique_ptr navigation_channel_; - // A plugin that implements the Flutter platform channel. - std::unique_ptr platform_channel_; - // A plugin that implements the Flutter platform_views channel. std::unique_ptr platform_view_channel_; // A plugin that implements the Flutter settings channel. std::unique_ptr settings_channel_; - // A plugin that implements the Flutter textinput channel. - std::unique_ptr text_input_channel_; - - // A plugin that implements the Tizen window channel. - std::unique_ptr window_channel_; - // The event loop for the main thread that allows for delayed task execution. std::unique_ptr event_loop_; @@ -305,9 +283,6 @@ class FlutterTizenEngine : public TizenRenderer::Delegate { // The vsync waiter for the embedder. std::unique_ptr tizen_vsync_waiter_; #endif - - // The current renderer transformation. - FlutterTransformation transformation_; }; } // namespace flutter diff --git a/shell/platform/tizen/flutter_tizen_engine_unittest.cc b/shell/platform/tizen/flutter_tizen_engine_unittest.cc index d129bdc837e36..bdaa2cfa56053 100644 --- a/shell/platform/tizen/flutter_tizen_engine_unittest.cc +++ b/shell/platform/tizen/flutter_tizen_engine_unittest.cc @@ -94,7 +94,7 @@ TEST_F(FlutterTizenEngineTest, RunDoesExpectedInitialization) { return kSuccess; })); - engine_->RunEngine(nullptr); + engine_->RunEngine(); EXPECT_TRUE(run_called); EXPECT_TRUE(update_locales_called); diff --git a/shell/platform/tizen/flutter_tizen_view.cc b/shell/platform/tizen/flutter_tizen_view.cc new file mode 100644 index 0000000000000..d6db6bf5851d8 --- /dev/null +++ b/shell/platform/tizen/flutter_tizen_view.cc @@ -0,0 +1,303 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// 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_tizen_view.h" + +#include "flutter/shell/platform/tizen/logger.h" + +namespace { + +#if defined(MOBILE_PROFILE) +constexpr double kProfileFactor = 0.7; +#elif defined(WEARABLE_PROFILE) +constexpr double kProfileFactor = 0.4; +#elif defined(TV_PROFILE) +constexpr double kProfileFactor = 2.0; +#else +constexpr double kProfileFactor = 1.0; +#endif + +constexpr char kBackKey[] = "XF86Back"; +constexpr char kExitKey[] = "XF86Exit"; + +// Keys that should always be handled by the app first but not by the system. +const std::vector kBindableSystemKeys = { + "XF86Menu", "XF86Back", "XF86AudioPlay", + "XF86AudioPause", "XF86AudioStop", "XF86AudioNext", + "XF86AudioPrev", "XF86AudioRewind", "XF86AudioForward", + "XF86AudioPlayPause", "XF86AudioRecord", "XF86LowerChannel", + "XF86RaiseChannel", "XF86ChannelList", "XF86PreviousChannel", + "XF86SysMenu", "XF86SimpleMenu", "XF86History", + "XF86Favorites", "XF86Info", "XF86Red", + "XF86Green", "XF86Yellow", "XF86Blue", + "XF86Subtitle", "XF86PlayBack", "XF86ChannelGuide", + "XF86Caption", "XF86Exit", +}; + +} // namespace + +namespace flutter { + +FlutterTizenView::FlutterTizenView(std::unique_ptr window) + : window_(std::move(window)) { + window_->SetView(this); + window_->BindKeys(kBindableSystemKeys); +} + +FlutterTizenView::~FlutterTizenView() {} + +void FlutterTizenView::SetEngine(std::unique_ptr engine) { + engine_ = std::move(engine); + engine_->SetView(this); + + internal_plugin_registrar_ = + std::make_unique(engine_->plugin_registrar()); + + // Set up window dependent channels. + BinaryMessenger* messenger = internal_plugin_registrar_->messenger(); + platform_channel_ = + std::make_unique(messenger, window_.get()); + window_channel_ = std::make_unique(messenger, window_.get()); + text_input_channel_ = std::make_unique( + internal_plugin_registrar_->messenger(), + std::make_unique(window_.get())); + + OnRotate(window_->GetRotation()); +} + +void FlutterTizenView::CreateRenderSurface() { + if (engine_ && engine_->renderer()) { + TizenWindow::Geometry geometry = window_->GetWindowGeometry(); + engine_->renderer()->CreateSurface(window_->GetRenderTarget(), + window_->GetRenderTargetDisplay(), + geometry.width, geometry.height); + } +} + +void FlutterTizenView::DestroyRenderSurface() { + if (engine_ && engine_->renderer()) { + engine_->renderer()->DestroySurface(); + } +} + +bool FlutterTizenView::OnMakeCurrent() { + return engine_->renderer()->OnMakeCurrent(); +} + +bool FlutterTizenView::OnClearCurrent() { + return engine_->renderer()->OnClearCurrent(); +} + +bool FlutterTizenView::OnMakeResourceCurrent() { + return engine_->renderer()->OnMakeResourceCurrent(); +} + +bool FlutterTizenView::OnPresent() { + return engine_->renderer()->OnPresent(); +} + +uint32_t FlutterTizenView::OnGetFBO() { + return engine_->renderer()->OnGetFBO(); +} + +void* FlutterTizenView::OnProcResolver(const char* name) { + return engine_->renderer()->OnProcResolver(name); +} + +void FlutterTizenView::OnResize(int32_t left, + int32_t top, + int32_t width, + int32_t height) { + if (rotation_degree_ == 90 || rotation_degree_ == 270) { + std::swap(width, height); + } + + window_->ResizeRenderTargetWithRotation({left, top, width, height}, + rotation_degree_); + SendWindowMetrics(left, top, width, height, 0.0); +} + +void FlutterTizenView::OnRotate(int32_t degree) { + rotation_degree_ = degree; + // Compute renderer transformation based on the angle of rotation. + double rad = (360 - rotation_degree_) * M_PI / 180; + TizenWindow::Geometry geometry = window_->GetWindowGeometry(); + int32_t width = geometry.width; + int32_t height = geometry.height; + + double trans_x = 0.0, trans_y = 0.0; + if (rotation_degree_ == 90) { + trans_y = height; + } else if (rotation_degree_ == 180) { + trans_x = width; + trans_y = height; + } else if (rotation_degree_ == 270) { + trans_x = width; + } + + flutter_transformation_ = { + cos(rad), -sin(rad), trans_x, // x + sin(rad), cos(rad), trans_y, // y + 0.0, 0.0, 1.0 // perspective + }; + + if (rotation_degree_ == 90 || rotation_degree_ == 270) { + std::swap(width, height); + } + + window_->ResizeRenderTargetWithRotation( + {geometry.left, geometry.top, width, height}, rotation_degree_); + + // Window position does not change on rotation regardless of its orientation. + SendWindowMetrics(geometry.left, geometry.top, width, height, 0.0); +} + +void FlutterTizenView::OnPointerMove(double x, + double y, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int32_t device_id) { + if (pointer_state_) { + SendFlutterPointerEvent(kMove, x, y, 0, 0, timestamp, device_kind, + device_id); + } +} + +void FlutterTizenView::OnPointerDown(double x, + double y, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int32_t device_id) { + pointer_state_ = true; + SendFlutterPointerEvent(kDown, x, y, 0, 0, timestamp, device_kind, device_id); +} + +void FlutterTizenView::OnPointerUp(double x, + double y, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int32_t device_id) { + pointer_state_ = false; + SendFlutterPointerEvent(kUp, x, y, 0, 0, timestamp, device_kind, device_id); +} + +void FlutterTizenView::OnScroll(double x, + double y, + double delta_x, + double delta_y, + int scroll_offset_multiplier, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int32_t device_id) { + SendFlutterPointerEvent( + pointer_state_ ? kMove : kHover, x, y, delta_x * scroll_offset_multiplier, + delta_y * scroll_offset_multiplier, timestamp, device_kind, device_id); +} + +void FlutterTizenView::OnKey(Ecore_Event_Key* event, bool is_down) { + if (is_down) { + FT_LOG(Info) << "Key symbol: " << event->key << ", code: 0x" << std::setw(8) + << std::setfill('0') << std::right << std::hex + << event->keycode; + } + + if (text_input_channel_) { + if (text_input_channel_->SendKeyEvent(event, is_down)) { + return; + } + } + + if (engine_->platform_view_channel()) { + engine_->platform_view_channel()->SendKeyEvent(event, is_down); + } + + if (engine_->key_event_channel()) { + engine_->key_event_channel()->SendKeyEvent( + event, is_down, + [engine = engine_.get(), symbol = std::string(event->key), + is_down](bool handled) { + if (handled) { + return; + } + if (symbol == kBackKey && !is_down) { + if (engine->navigation_channel()) { + engine->navigation_channel()->PopRoute(); + } + } else if (symbol == kExitKey && !is_down) { + ui_app_exit(); + } + }); + } +} + +void FlutterTizenView::SendInitialGeometry() { + OnRotate(window_->GetRotation()); +} + +void FlutterTizenView::SendWindowMetrics(int32_t left, + int32_t top, + int32_t width, + int32_t height, + double pixel_ratio) { + double computed_pixel_ratio = pixel_ratio; + if (pixel_ratio == 0.0) { + // The scale factor is computed based on the display DPI and the current + // profile. A fixed DPI value (72) is used on TVs. See: + // https://docs.tizen.org/application/native/guides/ui/efl/multiple-screens +#ifdef TV_PROFILE + double dpi = 72.0; +#else + double dpi = static_cast(window_->GetDpi()); +#endif + double scale_factor = dpi / 90.0 * kProfileFactor; + computed_pixel_ratio = std::max(scale_factor, 1.0); + } else { + computed_pixel_ratio = pixel_ratio; + } + + engine_->SendWindowMetrics(left, top, width, height, computed_pixel_ratio); +} + +void FlutterTizenView::SendFlutterPointerEvent( + FlutterPointerPhase phase, + double x, + double y, + double delta_x, + double delta_y, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int device_id) { + TizenWindow::Geometry geometry = window_->GetWindowGeometry(); + double new_x = x, new_y = y; + + if (rotation_degree_ == 90) { + new_x = geometry.height - y; + new_y = x; + } else if (rotation_degree_ == 180) { + new_x = geometry.width - x; + new_y = geometry.height - y; + } else if (rotation_degree_ == 270) { + new_x = y; + new_y = geometry.width - x; + } + + FlutterPointerEvent event = {}; + event.struct_size = sizeof(event); + event.phase = phase; + event.x = new_x; + event.y = new_y; + if (delta_x != 0 || delta_y != 0) { + event.signal_kind = kFlutterPointerSignalKindScroll; + } + event.scroll_delta_x = delta_x; + event.scroll_delta_y = delta_y; + event.timestamp = timestamp * 1000; + event.device = device_id; + event.device_kind = kFlutterPointerDeviceKindTouch; + + engine_->SendPointerEvent(event); +} + +} // namespace flutter diff --git a/shell/platform/tizen/flutter_tizen_view.h b/shell/platform/tizen/flutter_tizen_view.h new file mode 100644 index 0000000000000..b59fa6d7d0606 --- /dev/null +++ b/shell/platform/tizen/flutter_tizen_view.h @@ -0,0 +1,144 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// 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 EMBEDDER_FLUTTER_TIZEN_VIEW_H_ +#define EMBEDDER_FLUTTER_TIZEN_VIEW_H_ + +#include + +#include + +#include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/tizen/channels/platform_channel.h" +#include "flutter/shell/platform/tizen/channels/text_input_channel.h" +#include "flutter/shell/platform/tizen/channels/window_channel.h" +#include "flutter/shell/platform/tizen/flutter_tizen_engine.h" +#include "flutter/shell/platform/tizen/tizen_window.h" + +namespace flutter { + +class FlutterTizenView { + public: + FlutterTizenView(std::unique_ptr window); + + ~FlutterTizenView(); + + // Configures the window instance with an instance of a running Flutter + // engine. + void SetEngine(std::unique_ptr engine); + + FlutterTizenEngine* engine() { return engine_.get(); } + + TizenWindow* window() { return window_.get(); } + + // Creates rendering surface for Flutter engine to draw into. + // Should be called before calling FlutterEngineRun using this view. + void CreateRenderSurface(); + + // Destroys current rendering surface if one has been allocated. + void DestroyRenderSurface(); + + // Callbacks for clearing context, settings context and swapping buffers, + // these are typically called on an engine-controlled (non-platform) thread. + bool OnMakeCurrent(); + bool OnClearCurrent(); + bool OnMakeResourceCurrent(); + bool OnPresent(); + + uint32_t OnGetFBO(); + + void* OnProcResolver(const char* name); + + void OnResize(int32_t left, int32_t top, int32_t width, int32_t height); + + void OnRotate(int32_t degree); + + void OnPointerMove(double x, + double y, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int32_t device_id); + + void OnPointerDown(double x, + double y, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int32_t device_id); + + void OnPointerUp(double x, + double y, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int32_t device_id); + + void OnScroll(double x, + double y, + double delta_x, + double delta_y, + int scroll_offset_multiplier, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int32_t device_id); + + void OnKey(Ecore_Event_Key* event, bool is_down); + + FlutterTransformation GetFlutterTransformation() { + return flutter_transformation_; + } + + void SendInitialGeometry(); + + private: + // Sends a window metrics update to the Flutter engine using current window + // dimensions in physical. + void SendWindowMetrics(int32_t left, + int32_t top, + int32_t width, + int32_t height, + double pixel_ratio); + + // Reports pointer event to Flutter engine. + void SendFlutterPointerEvent(FlutterPointerPhase phase, + double x, + double y, + double delta_x, + double delta_y, + size_t timestamp, + FlutterPointerDeviceKind device_kind, + int device_id); + + // The engine associated with this view. + std::unique_ptr engine_; + + // The window associated with this view. + std::unique_ptr window_; + + // The plugin registrar managing internal plugins. + std::unique_ptr internal_plugin_registrar_; + + // A plugin that implements the Tizen window channel. + std::unique_ptr window_channel_; + + // A plugin that implements the Flutter platform channel. + std::unique_ptr platform_channel_; + + // A plugin that implements the Flutter textinput channel. + std::unique_ptr text_input_channel_; + + // The current view rotation degree. + int32_t rotation_degree_ = 0; + + // The current pointer state to distinguish move or hover event. + bool pointer_state_ = false; + + // The current view transformation. + FlutterTransformation flutter_transformation_ = {1.0, 0.0, 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, 1.0}; +}; + +} // namespace flutter + +#endif // EMBEDDER_FLUTTER_TIZEN_VIEW_H_ diff --git a/shell/platform/tizen/key_event_handler.cc b/shell/platform/tizen/key_event_handler.cc deleted file mode 100644 index 86de311969341..0000000000000 --- a/shell/platform/tizen/key_event_handler.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "key_event_handler.h" - -#include - -#include - -#include "flutter/shell/platform/tizen/flutter_tizen_engine.h" -#include "flutter/shell/platform/tizen/logger.h" - -namespace flutter { - -namespace { - -constexpr char kBackKey[] = "XF86Back"; -constexpr char kExitKey[] = "XF86Exit"; - -// Keys that should always be handled by the app first but not by the system. -const std::vector kBindableSystemKeys = { - "XF86Menu", "XF86Back", "XF86AudioPlay", - "XF86AudioPause", "XF86AudioStop", "XF86AudioNext", - "XF86AudioPrev", "XF86AudioRewind", "XF86AudioForward", - "XF86AudioPlayPause", "XF86AudioRecord", "XF86LowerChannel", - "XF86RaiseChannel", "XF86ChannelList", "XF86PreviousChannel", - "XF86SysMenu", "XF86SimpleMenu", "XF86History", - "XF86Favorites", "XF86Info", "XF86Red", - "XF86Green", "XF86Yellow", "XF86Blue", - "XF86Subtitle", "XF86PlayBack", "XF86ChannelGuide", - "XF86Caption", "XF86Exit", -}; - -} // namespace - -KeyEventHandler::KeyEventHandler(FlutterTizenEngine* engine) : engine_(engine) { - if (!engine->renderer() || !engine->renderer()->IsValid()) { - return; - } - engine->renderer()->BindKeys(kBindableSystemKeys); - - key_event_handlers_.push_back( - ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, OnKey, this)); - key_event_handlers_.push_back( - ecore_event_handler_add(ECORE_EVENT_KEY_UP, OnKey, this)); -} - -KeyEventHandler::~KeyEventHandler() { - for (Ecore_Event_Handler* handler : key_event_handlers_) { - ecore_event_handler_del(handler); - } - key_event_handlers_.clear(); -} - -Eina_Bool KeyEventHandler::OnKey(void* data, int type, void* raw_event) { - auto* self = reinterpret_cast(data); - auto* event = reinterpret_cast(raw_event); - FlutterTizenEngine* engine = self->engine_; - bool is_down = type == ECORE_EVENT_KEY_DOWN; - - if (engine->renderer()->GetWindowId() != event->window) { - return ECORE_CALLBACK_PASS_ON; - } - - if (is_down) { - FT_LOG(Info) << "Key symbol: " << event->key << ", code: 0x" << std::setw(8) - << std::setfill('0') << std::right << std::hex - << event->keycode; - } - - if (engine->text_input_channel()) { - if (engine->text_input_channel()->SendKeyEvent(event, is_down)) { - return ECORE_CALLBACK_DONE; - } - } - - if (engine->platform_view_channel()) { - engine->platform_view_channel()->SendKeyEvent(event, is_down); - } - - if (engine->key_event_channel()) { - engine->key_event_channel()->SendKeyEvent( - event, is_down, - [engine, symbol = std::string(event->key), is_down](bool handled) { - if (handled) { - return; - } - if (symbol == kBackKey && !is_down) { - if (engine->navigation_channel()) { - engine->navigation_channel()->PopRoute(); - } - } else if (symbol == kExitKey && !is_down) { - ui_app_exit(); - } - }); - } - return ECORE_CALLBACK_DONE; -} - -} // namespace flutter diff --git a/shell/platform/tizen/key_event_handler.h b/shell/platform/tizen/key_event_handler.h deleted file mode 100644 index 07ce8b8615770..0000000000000 --- a/shell/platform/tizen/key_event_handler.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef EMBEDDER_KEY_EVENT_HANDLER_H_ -#define EMBEDDER_KEY_EVENT_HANDLER_H_ - -#include - -#include - -namespace flutter { - -class FlutterTizenEngine; - -class KeyEventHandler { - public: - explicit KeyEventHandler(FlutterTizenEngine* engine); - virtual ~KeyEventHandler(); - - private: - FlutterTizenEngine* engine_; - std::vector key_event_handlers_; - - static Eina_Bool OnKey(void* data, int type, void* event); -}; - -} // namespace flutter - -#endif // EMBEDDER_KEY_EVENT_HANDLER_H_ diff --git a/shell/platform/tizen/public/flutter_tizen.h b/shell/platform/tizen/public/flutter_tizen.h index f311611a9ad3e..aeba4ec9e42b9 100644 --- a/shell/platform/tizen/public/flutter_tizen.h +++ b/shell/platform/tizen/public/flutter_tizen.h @@ -21,11 +21,12 @@ extern "C" { struct FlutterDesktopEngine; typedef struct FlutterDesktopEngine* FlutterDesktopEngineRef; +// Opaque reference to a Flutter view instance. +struct FlutterDesktopView; +typedef struct FlutterDesktopView* FlutterDesktopViewRef; + // Properties for configuring the initial settings of a Flutter window. typedef struct { - // Whether the app is headed or headless. Other properties are ignored if - // this value is set to false. - bool headed; // The x-coordinate of the top left corner of the window. int32_t x; // The y-coordinate of the top left corner of the window. @@ -67,68 +68,82 @@ typedef struct { const char** dart_entrypoint_argv; } FlutterDesktopEngineProperties; +// ========== Engine ========== + +// Creates a Flutter engine with the given properties. +FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopEngineCreate( + const FlutterDesktopEngineProperties& engine_properties); + // Runs an instance of a Flutter engine with the given properties. // -// If |headed| is false, the engine is run in headless mode. -FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopRunEngine( - const FlutterDesktopWindowProperties& window_properties, - const FlutterDesktopEngineProperties& engine_properties); +// If view is not specified, the engine is run in headless mode. +FLUTTER_EXPORT bool FlutterDesktopEngineRun( + const FlutterDesktopEngineRef engine); // Shuts down the given engine instance. // // |engine| is no longer valid after this call. -FLUTTER_EXPORT void FlutterDesktopShutdownEngine( +FLUTTER_EXPORT void FlutterDesktopEngineShutdown( FlutterDesktopEngineRef engine); // Returns the plugin registrar handle for the plugin with the given name. // // The name must be unique across the application. FLUTTER_EXPORT FlutterDesktopPluginRegistrarRef -FlutterDesktopGetPluginRegistrar(FlutterDesktopEngineRef engine, - const char* plugin_name); +FlutterDesktopEngineGetPluginRegistrar(FlutterDesktopEngineRef engine, + const char* plugin_name); // Returns the messenger associated with the engine. FLUTTER_EXPORT FlutterDesktopMessengerRef FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine); -// Returns the window associated with this registrar's engine instance. -// -// If the app runs on a wearable device, cast void* to Evas_Object*, -// otherwise cast it to Ecore_Wl2_Window*. -FLUTTER_EXPORT void* FlutterDesktopGetWindow( - FlutterDesktopPluginRegistrarRef registrar); - // Posts an app control to the engine instance. -FLUTTER_EXPORT void FlutterDesktopNotifyAppControl( +FLUTTER_EXPORT void FlutterDesktopEngineNotifyAppControl( FlutterDesktopEngineRef engine, void* app_control); // Posts a locale change notification to the engine instance. -FLUTTER_EXPORT void FlutterDesktopNotifyLocaleChange( +FLUTTER_EXPORT void FlutterDesktopEngineNotifyLocaleChange( FlutterDesktopEngineRef engine); // Posts a low memory notification to the engine instance. -FLUTTER_EXPORT void FlutterDesktopNotifyLowMemoryWarning( +FLUTTER_EXPORT void FlutterDesktopEngineNotifyLowMemoryWarning( FlutterDesktopEngineRef engine); // Notifies the engine that the app is in an inactive state and not receiving // user input. -FLUTTER_EXPORT void FlutterDesktopNotifyAppIsInactive( +FLUTTER_EXPORT void FlutterDesktopEngineNotifyAppIsInactive( FlutterDesktopEngineRef engine); // Notifies the engine that the app is visible and responding to user input. -FLUTTER_EXPORT void FlutterDesktopNotifyAppIsResumed( +FLUTTER_EXPORT void FlutterDesktopEngineNotifyAppIsResumed( FlutterDesktopEngineRef engine); // Notifies the engine that the app is not currently visible to the user, not // responding to user input, and running in the background. -FLUTTER_EXPORT void FlutterDesktopNotifyAppIsPaused( +FLUTTER_EXPORT void FlutterDesktopEngineNotifyAppIsPaused( FlutterDesktopEngineRef engine); // Notifies the engine that the engine is detached from any host views. -FLUTTER_EXPORT void FlutterDesktopNotifyAppIsDetached( +FLUTTER_EXPORT void FlutterDesktopEngineNotifyAppIsDetached( FlutterDesktopEngineRef engine); +// ========== View ========== + +// Creates a view that hosts and displays the given engine instance. +FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopViewCreateFromNewWindow( + const FlutterDesktopWindowProperties& window_properties, + FlutterDesktopEngineRef engine); + +// ========== Plugin Registrar (extensions) ========== + +// Returns the window associated with this registrar's engine instance. +// +// If the app runs on a wearable device, cast void* to Evas_Object*, +// otherwise cast it to Ecore_Wl2_Window*. +FLUTTER_EXPORT void* FlutterDesktopPluginRegistrarGetNativeWindow( + FlutterDesktopPluginRegistrarRef registrar); + #if defined(__cplusplus) } // extern "C" #endif diff --git a/shell/platform/tizen/tizen_event_loop.cc b/shell/platform/tizen/tizen_event_loop.cc index 6502ecd9bff3d..8faba58b34ee3 100644 --- a/shell/platform/tizen/tizen_event_loop.cc +++ b/shell/platform/tizen/tizen_event_loop.cc @@ -117,20 +117,16 @@ TizenRenderEventLoop::TizenRenderEventLoop(std::thread::id main_thread_id, TizenRenderer* renderer) : TizenEventLoop(main_thread_id, get_current_time, on_task_expired), renderer_(renderer) { - evas_object_image_pixels_get_callback_set( - static_cast(renderer_)->GetImageHandle(), - [](void* data, Evas_Object* o) { // Render callback - auto* self = static_cast(data); - { - std::lock_guard lock(self->expired_tasks_mutex_); - for (const Task& task : self->expired_tasks_) { - self->on_task_expired_(&task.task); - } - self->expired_tasks_.clear(); - } - self->has_pending_renderer_callback_ = false; - }, - this); + static_cast(renderer_)->SetOnPixelsDirty([this]() { + { + std::lock_guard lock(expired_tasks_mutex_); + for (const Task& task : expired_tasks_) { + on_task_expired_(&task.task); + } + expired_tasks_.clear(); + } + has_pending_renderer_callback_ = false; + }); } TizenRenderEventLoop::~TizenRenderEventLoop() {} @@ -138,9 +134,7 @@ TizenRenderEventLoop::~TizenRenderEventLoop() {} void TizenRenderEventLoop::OnTaskExpired() { std::lock_guard lock(expired_tasks_mutex_); if (!has_pending_renderer_callback_ && !expired_tasks_.empty()) { - evas_object_image_pixels_dirty_set( - static_cast(renderer_)->GetImageHandle(), - EINA_TRUE); + static_cast(renderer_)->MarkPixelsDirty(); has_pending_renderer_callback_ = true; } } diff --git a/shell/platform/tizen/tizen_event_loop.h b/shell/platform/tizen/tizen_event_loop.h index 32aa1cd1668b8..dae7c3e2e3b53 100644 --- a/shell/platform/tizen/tizen_event_loop.h +++ b/shell/platform/tizen/tizen_event_loop.h @@ -22,8 +22,6 @@ namespace flutter { typedef uint64_t (*CurrentTimeProc)(); -class TizenRenderer; - class TizenEventLoop { public: using TaskExpiredCallback = std::function; @@ -91,6 +89,8 @@ class TizenPlatformEventLoop : public TizenEventLoop { }; #ifdef TIZEN_RENDERER_EVAS_GL +class TizenRenderer; + class TizenRenderEventLoop : public TizenEventLoop { public: TizenRenderEventLoop(std::thread::id main_thread_id, diff --git a/shell/platform/tizen/tizen_input_method_context.cc b/shell/platform/tizen/tizen_input_method_context.cc index 98c8a9be45826..4b83d1b53dbf6 100644 --- a/shell/platform/tizen/tizen_input_method_context.cc +++ b/shell/platform/tizen/tizen_input_method_context.cc @@ -4,8 +4,8 @@ #include "tizen_input_method_context.h" -#include "flutter/shell/platform/tizen/flutter_tizen_engine.h" #include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_window.h" namespace { @@ -103,9 +103,9 @@ T EcoreEventKeyToEcoreImfEvent(Ecore_Event_Key* event, const char* dev_name) { namespace flutter { -TizenInputMethodContext::TizenInputMethodContext(FlutterTizenEngine* engine) - : engine_(engine) { - FT_ASSERT(engine_); +TizenInputMethodContext::TizenInputMethodContext(TizenWindow* window) + : window_(window) { + FT_ASSERT(window_); ecore_imf_init(); const char* imf_id = ecore_imf_context_default_id_get(); @@ -125,8 +125,7 @@ TizenInputMethodContext::TizenInputMethodContext(FlutterTizenEngine* engine) } ecore_imf_context_client_window_set( - imf_context_, - reinterpret_cast(engine_->renderer()->GetWindowId())); + imf_context_, reinterpret_cast(window_->GetWindowId())); SetContextOptions(); SetInputPanelOptions(); RegisterEventCallbacks(); diff --git a/shell/platform/tizen/tizen_input_method_context.h b/shell/platform/tizen/tizen_input_method_context.h index 18febbeac1754..dcc069c36791e 100644 --- a/shell/platform/tizen/tizen_input_method_context.h +++ b/shell/platform/tizen/tizen_input_method_context.h @@ -21,7 +21,7 @@ using OnPreeditStart = std::function; using OnPreeditEnd = std::function; using OnInputPanelStateChanged = std::function; -class FlutterTizenEngine; +class TizenWindow; struct InputPanelGeometry { int32_t x = 0, y = 0, w = 0, h = 0; @@ -29,7 +29,7 @@ struct InputPanelGeometry { class TizenInputMethodContext { public: - TizenInputMethodContext(FlutterTizenEngine* engine); + TizenInputMethodContext(TizenWindow* window); ~TizenInputMethodContext(); bool FilterEvent(Ecore_Event_Key* event, const char* dev_name, bool is_down); @@ -69,8 +69,8 @@ class TizenInputMethodContext { void SetContextOptions(); void SetInputPanelOptions(); - FlutterTizenEngine* engine_{nullptr}; - Ecore_IMF_Context* imf_context_{nullptr}; + TizenWindow* window_ = nullptr; + Ecore_IMF_Context* imf_context_ = nullptr; OnCommit on_commit_; OnPreeditChanged on_preedit_changed_; OnPreeditStart on_preedit_start_; diff --git a/shell/platform/tizen/tizen_renderer.cc b/shell/platform/tizen/tizen_renderer.cc index 314f75f05adac..f37732b22d22f 100644 --- a/shell/platform/tizen/tizen_renderer.cc +++ b/shell/platform/tizen/tizen_renderer.cc @@ -6,16 +6,7 @@ namespace flutter { -TizenRenderer::TizenRenderer(Geometry geometry, - bool transparent, - bool focusable, - bool top_level, - Delegate& delegate) - : initial_geometry_(geometry), - transparent_(transparent), - focusable_(focusable), - top_level_(top_level), - delegate_(delegate) {} +TizenRenderer::TizenRenderer() {} TizenRenderer::~TizenRenderer() = default; diff --git a/shell/platform/tizen/tizen_renderer.h b/shell/platform/tizen/tizen_renderer.h index 8dc9abbc205f1..c5f600a251641 100644 --- a/shell/platform/tizen/tizen_renderer.h +++ b/shell/platform/tizen/tizen_renderer.h @@ -6,77 +6,40 @@ #define EMBEDDER_TIZEN_RENDERER_H_ #include -#include namespace flutter { class TizenRenderer { public: - struct Geometry { - int32_t x{0}, y{0}, w{0}, h{0}; - }; - - class Delegate { - public: - virtual void OnOrientationChange(int32_t degree) = 0; - virtual void OnGeometryChange(int32_t x, - int32_t y, - int32_t width, - int32_t height) = 0; - }; + TizenRenderer(); virtual ~TizenRenderer(); + virtual bool CreateSurface(void* render_target, + void* render_target_display, + int32_t width, + int32_t height) = 0; + + virtual void DestroySurface() = 0; + bool IsValid() { return is_valid_; } virtual bool OnMakeCurrent() = 0; + virtual bool OnClearCurrent() = 0; - virtual bool OnMakeResourceCurrent() = 0; - virtual bool OnPresent() = 0; - virtual uint32_t OnGetFBO() = 0; - virtual void* OnProcResolver(const char* name) = 0; - // Returns the geometry of the current window. - virtual Geometry GetWindowGeometry() = 0; + virtual bool OnMakeResourceCurrent() = 0; - // Returns the geometry of the display screen. - virtual Geometry GetScreenGeometry() = 0; + virtual bool OnPresent() = 0; - virtual int32_t GetDpi() = 0; - virtual uintptr_t GetWindowId() = 0; - virtual void* GetWindowHandle() = 0; + virtual uint32_t OnGetFBO() = 0; - virtual void SetRotate(int angle) = 0; - virtual void SetGeometry(int32_t x, - int32_t y, - int32_t width, - int32_t height) = 0; - virtual void ResizeWithRotation(int32_t x, - int32_t y, - int32_t width, - int32_t height, - int32_t degree) = 0; - virtual void SetPreferredOrientations(const std::vector& rotations) = 0; + virtual void* OnProcResolver(const char* name) = 0; virtual bool IsSupportedExtension(const char* name) = 0; - virtual void BindKeys(const std::vector& keys) = 0; - protected: - explicit TizenRenderer(Geometry geometry, - bool transparent, - bool focusable, - bool top_level, - Delegate& delegate); - - Geometry initial_geometry_; - bool transparent_; - bool focusable_; - bool top_level_; - Delegate& delegate_; - bool is_valid_ = false; - bool received_rotation_ = false; }; } // namespace flutter diff --git a/shell/platform/tizen/tizen_renderer_ecore_wl2.h b/shell/platform/tizen/tizen_renderer_ecore_wl2.h deleted file mode 100644 index 468249802e57d..0000000000000 --- a/shell/platform/tizen/tizen_renderer_ecore_wl2.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef EMBEDDER_TIZEN_RENDERER_ECORE_WL2_H_ -#define EMBEDDER_TIZEN_RENDERER_ECORE_WL2_H_ - -#define EFL_BETA_API_SUPPORT -#include -#include -#include - -#include - -#include "flutter/shell/platform/tizen/tizen_renderer.h" - -namespace flutter { - -class TizenRendererEcoreWl2 : public TizenRenderer { - public: - explicit TizenRendererEcoreWl2(Geometry geometry, - bool transparent, - bool focusable, - bool top_level, - Delegate& delegate); - virtual ~TizenRendererEcoreWl2(); - - bool OnMakeCurrent() override; - bool OnClearCurrent() override; - bool OnMakeResourceCurrent() override; - bool OnPresent() override; - uint32_t OnGetFBO() override; - void* OnProcResolver(const char* name) override; - - Geometry GetWindowGeometry() override; - Geometry GetScreenGeometry() override; - int32_t GetDpi() override; - uintptr_t GetWindowId() override; - - void* GetWindowHandle() override { return ecore_wl2_window_; } - - void SetRotate(int angle) override; - void SetGeometry(int32_t x, - int32_t y, - int32_t width, - int32_t height) override; - void ResizeWithRotation(int32_t x, - int32_t y, - int32_t width, - int32_t height, - int32_t angle) override; - void SetPreferredOrientations(const std::vector& rotations) override; - - bool IsSupportedExtension(const char* name) override; - - void BindKeys(const std::vector& keys) override; - - private: - void Show(); - - bool SetupEcoreWl2(); - bool SetupEGL(); - - bool ChooseEGLConfiguration(); - void PrintEGLError(); - - void DestroyEcoreWl2(); - void DestroyEGL(); - - static Eina_Bool RotationEventCb(void* data, int type, void* event); - void SendRotationChangeDone(); - - void SetTizenPolicyNotificationLevel(int level); - - Ecore_Wl2_Display* ecore_wl2_display_ = nullptr; - Ecore_Wl2_Window* ecore_wl2_window_ = nullptr; - Ecore_Wl2_Egl_Window* ecore_wl2_egl_window_ = nullptr; - - EGLConfig egl_config_ = nullptr; - EGLDisplay egl_display_ = EGL_NO_DISPLAY; - EGLContext egl_context_ = EGL_NO_CONTEXT; - EGLSurface egl_surface_ = EGL_NO_SURFACE; - EGLContext egl_resource_context_ = EGL_NO_CONTEXT; - EGLSurface egl_resource_surface_ = EGL_NO_SURFACE; - - std::string egl_extension_str_; - - tizen_policy* tizen_policy_ = nullptr; -}; - -} // namespace flutter - -#endif // EMBEDDER_TIZEN_RENDERER_ECORE_WL2_H_ diff --git a/shell/platform/tizen/tizen_renderer_ecore_wl2.cc b/shell/platform/tizen/tizen_renderer_egl.cc similarity index 52% rename from shell/platform/tizen/tizen_renderer_ecore_wl2.cc rename to shell/platform/tizen/tizen_renderer_egl.cc index f20334052c76d..0b88fc2212235 100644 --- a/shell/platform/tizen/tizen_renderer_ecore_wl2.cc +++ b/shell/platform/tizen/tizen_renderer_egl.cc @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "tizen_renderer_ecore_wl2.h" +#include "tizen_renderer_egl.h" +#include #include #include @@ -11,31 +12,173 @@ namespace flutter { -TizenRendererEcoreWl2::TizenRendererEcoreWl2(Geometry geometry, - bool transparent, - bool focusable, - bool top_level, - Delegate& delegate) - : TizenRenderer(geometry, transparent, focusable, top_level, delegate) { - if (!SetupEcoreWl2()) { - FT_LOG(Error) << "Could not set up Ecore Wl2."; - return; +TizenRendererEgl::TizenRendererEgl() {} + +TizenRendererEgl::~TizenRendererEgl() { + DestroySurface(); +} + +bool TizenRendererEgl::CreateSurface(void* render_target, + void* render_target_display, + int32_t width, + int32_t height) { + egl_display_ = eglGetDisplay(static_cast(render_target_display)); + + if (EGL_NO_DISPLAY == egl_display_) { + PrintEGLError(); + FT_LOG(Error) << "Could not get EGL display."; + return false; + } + + if (!ChooseEGLConfiguration()) { + FT_LOG(Error) << "Could not choose an EGL configuration."; + return false; + } + + egl_extension_str_ = eglQueryString(egl_display_, EGL_EXTENSIONS); + + { + const EGLint attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + + egl_context_ = + eglCreateContext(egl_display_, egl_config_, EGL_NO_CONTEXT, attribs); + if (egl_context_ == EGL_NO_CONTEXT) { + PrintEGLError(); + FT_LOG(Error) << "Could not create an onscreen context."; + return false; + } + + egl_resource_context_ = + eglCreateContext(egl_display_, egl_config_, egl_context_, attribs); + if (egl_resource_context_ == EGL_NO_CONTEXT) { + PrintEGLError(); + FT_LOG(Error) << "Could not create an offscreen context."; + return false; + } } - if (!SetupEGL()) { - FT_LOG(Error) << "Could not set up EGL."; - return; + + { + const EGLint attribs[] = {EGL_NONE}; + + auto* egl_window = + static_cast(ecore_wl2_egl_window_native_get( + static_cast(render_target))); + egl_surface_ = + eglCreateWindowSurface(egl_display_, egl_config_, egl_window, attribs); + if (egl_surface_ == EGL_NO_SURFACE) { + FT_LOG(Error) << "Could not create an onscreen window surface."; + return false; + } + } + + { + const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + + egl_resource_surface_ = + eglCreatePbufferSurface(egl_display_, egl_config_, attribs); + if (egl_resource_surface_ == EGL_NO_SURFACE) { + FT_LOG(Error) << "Could not create an offscreen window surface."; + return false; + } } - Show(); is_valid_ = true; + return true; } -TizenRendererEcoreWl2::~TizenRendererEcoreWl2() { - DestroyEGL(); - DestroyEcoreWl2(); +void TizenRendererEgl::DestroySurface() { + if (egl_display_) { + eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + + if (EGL_NO_SURFACE != egl_surface_) { + eglDestroySurface(egl_display_, egl_surface_); + egl_surface_ = EGL_NO_SURFACE; + } + + if (EGL_NO_CONTEXT != egl_context_) { + eglDestroyContext(egl_display_, egl_context_); + egl_context_ = EGL_NO_CONTEXT; + } + + if (EGL_NO_SURFACE != egl_resource_surface_) { + eglDestroySurface(egl_display_, egl_resource_surface_); + egl_resource_surface_ = EGL_NO_SURFACE; + } + + if (EGL_NO_CONTEXT != egl_resource_context_) { + eglDestroyContext(egl_display_, egl_resource_context_); + egl_resource_context_ = EGL_NO_CONTEXT; + } + + eglTerminate(egl_display_); + egl_display_ = EGL_NO_DISPLAY; + } } -bool TizenRendererEcoreWl2::OnMakeCurrent() { +bool TizenRendererEgl::ChooseEGLConfiguration() { + EGLint config_attribs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, EGL_DONT_CARE, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_SAMPLE_BUFFERS, EGL_DONT_CARE, + EGL_SAMPLES, EGL_DONT_CARE, + EGL_NONE + // clang-format on + }; + + if (!eglInitialize(egl_display_, nullptr, nullptr)) { + PrintEGLError(); + FT_LOG(Error) << "Could not initialize the EGL display."; + return false; + } + + if (!eglBindAPI(EGL_OPENGL_ES_API)) { + PrintEGLError(); + FT_LOG(Error) << "Could not bind the ES API."; + return false; + } + + EGLint config_size = 0; + if (!eglGetConfigs(egl_display_, nullptr, 0, &config_size)) { + PrintEGLError(); + FT_LOG(Error) << "Could not query framebuffer configurations."; + return false; + } + + EGLConfig* configs = (EGLConfig*)calloc(config_size, sizeof(EGLConfig)); + EGLint num_config; + if (!eglChooseConfig(egl_display_, config_attribs, configs, config_size, + &num_config)) { + free(configs); + PrintEGLError(); + FT_LOG(Error) << "No matching configurations found."; + return false; + } + + int buffer_size = 32; + EGLint size; + for (int i = 0; i < num_config; i++) { + eglGetConfigAttrib(egl_display_, configs[i], EGL_BUFFER_SIZE, &size); + if (buffer_size == size) { + egl_config_ = configs[i]; + break; + } + } + free(configs); + if (!egl_config_) { + FT_LOG(Error) << "No matching configuration found."; + return false; + } + + return true; +} + +bool TizenRendererEgl::OnMakeCurrent() { if (!IsValid()) { return false; } @@ -48,7 +191,7 @@ bool TizenRendererEcoreWl2::OnMakeCurrent() { return true; } -bool TizenRendererEcoreWl2::OnClearCurrent() { +bool TizenRendererEgl::OnClearCurrent() { if (!IsValid()) { return false; } @@ -61,7 +204,7 @@ bool TizenRendererEcoreWl2::OnClearCurrent() { return true; } -bool TizenRendererEcoreWl2::OnMakeResourceCurrent() { +bool TizenRendererEgl::OnMakeResourceCurrent() { if (!IsValid()) { return false; } @@ -74,16 +217,11 @@ bool TizenRendererEcoreWl2::OnMakeResourceCurrent() { return true; } -bool TizenRendererEcoreWl2::OnPresent() { +bool TizenRendererEgl::OnPresent() { if (!IsValid()) { return false; } - if (received_rotation_) { - SendRotationChangeDone(); - received_rotation_ = false; - } - if (eglSwapBuffers(egl_display_, egl_surface_) != EGL_TRUE) { PrintEGLError(); FT_LOG(Error) << "Could not swap EGL buffers."; @@ -92,14 +230,47 @@ bool TizenRendererEcoreWl2::OnPresent() { return true; } -uint32_t TizenRendererEcoreWl2::OnGetFBO() { +uint32_t TizenRendererEgl::OnGetFBO() { if (!IsValid()) { return 999; } return 0; } -void* TizenRendererEcoreWl2::OnProcResolver(const char* name) { +void TizenRendererEgl::PrintEGLError() { + EGLint error = eglGetError(); + switch (error) { +#define CASE_PRINT(value) \ + case value: { \ + FT_LOG(Error) << "EGL error: " << #value; \ + break; \ + } + CASE_PRINT(EGL_NOT_INITIALIZED) + CASE_PRINT(EGL_BAD_ACCESS) + CASE_PRINT(EGL_BAD_ALLOC) + CASE_PRINT(EGL_BAD_ATTRIBUTE) + CASE_PRINT(EGL_BAD_CONTEXT) + CASE_PRINT(EGL_BAD_CONFIG) + CASE_PRINT(EGL_BAD_CURRENT_SURFACE) + CASE_PRINT(EGL_BAD_DISPLAY) + CASE_PRINT(EGL_BAD_SURFACE) + CASE_PRINT(EGL_BAD_MATCH) + CASE_PRINT(EGL_BAD_PARAMETER) + CASE_PRINT(EGL_BAD_NATIVE_PIXMAP) + CASE_PRINT(EGL_BAD_NATIVE_WINDOW) + CASE_PRINT(EGL_CONTEXT_LOST) +#undef CASE_PRINT + default: { + FT_LOG(Error) << "Unknown EGL error: " << error; + } + } +} + +bool TizenRendererEgl::IsSupportedExtension(const char* name) { + return strstr(egl_extension_str_.c_str(), name); +} + +void* TizenRendererEgl::OnProcResolver(const char* name) { auto address = eglGetProcAddress(name); if (address != nullptr) { return reinterpret_cast(address); @@ -220,402 +391,4 @@ void* TizenRendererEcoreWl2::OnProcResolver(const char* name) { FT_LOG(Warn) << "Could not resolve: " << name; return nullptr; } - -TizenRenderer::Geometry TizenRendererEcoreWl2::GetWindowGeometry() { - Geometry result; - ecore_wl2_window_geometry_get(ecore_wl2_window_, &result.x, &result.y, - &result.w, &result.h); - return result; -} - -TizenRenderer::Geometry TizenRendererEcoreWl2::GetScreenGeometry() { - Geometry result = {}; - ecore_wl2_display_screen_size_get(ecore_wl2_display_, &result.w, &result.h); - return result; -} - -int32_t TizenRendererEcoreWl2::GetDpi() { - Ecore_Wl2_Output* output = ecore_wl2_window_output_find(ecore_wl2_window_); - if (!output) { - FT_LOG(Error) << "Could not find an output associated with the window."; - return 0; - } - return ecore_wl2_output_dpi_get(output); -} - -uintptr_t TizenRendererEcoreWl2::GetWindowId() { - return ecore_wl2_window_id_get(ecore_wl2_window_); -} - -void TizenRendererEcoreWl2::Show() { - ecore_wl2_window_show(ecore_wl2_window_); -} - -bool TizenRendererEcoreWl2::SetupEcoreWl2() { - if (!ecore_wl2_init()) { - FT_LOG(Error) << "Could not initialize Ecore Wl2."; - return false; - } - - ecore_wl2_display_ = ecore_wl2_display_connect(nullptr); - if (!ecore_wl2_display_) { - FT_LOG(Error) << "Ecore Wl2 display not found."; - return false; - } - ecore_wl2_sync(); - - int32_t width, height; - ecore_wl2_display_screen_size_get(ecore_wl2_display_, &width, &height); - if (width == 0 || height == 0) { - FT_LOG(Error) << "Invalid screen size: " << width << " x " << height; - return false; - } - - if (initial_geometry_.w == 0) { - initial_geometry_.w = width; - } - if (initial_geometry_.h == 0) { - initial_geometry_.h = height; - } - - ecore_wl2_window_ = ecore_wl2_window_new( - ecore_wl2_display_, nullptr, initial_geometry_.x, initial_geometry_.y, - initial_geometry_.w, initial_geometry_.h); - - // Change the window type to use the tizen policy for notification window - // according to top_level_. - // Note: ECORE_WL2_WINDOW_TYPE_TOPLEVEL is similar to "ELM_WIN_BASIC" and it - // does not mean that the window always will be overlaid on other apps :( - ecore_wl2_window_type_set(ecore_wl2_window_, - top_level_ ? ECORE_WL2_WINDOW_TYPE_NOTIFICATION - : ECORE_WL2_WINDOW_TYPE_TOPLEVEL); - if (top_level_) { - SetTizenPolicyNotificationLevel(TIZEN_POLICY_LEVEL_TOP); - } - - ecore_wl2_window_position_set(ecore_wl2_window_, initial_geometry_.x, - initial_geometry_.y); - ecore_wl2_window_aux_hint_add(ecore_wl2_window_, 0, - "wm.policy.win.user.geometry", "1"); - - if (transparent_) { - ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_TRUE); - } else { - ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_FALSE); - } - - if (!focusable_) { - ecore_wl2_window_focus_skip_set(ecore_wl2_window_, EINA_TRUE); - } - - ecore_wl2_window_indicator_state_set(ecore_wl2_window_, - ECORE_WL2_INDICATOR_STATE_ON); - ecore_wl2_window_indicator_opacity_set(ecore_wl2_window_, - ECORE_WL2_INDICATOR_OPAQUE); - ecore_wl2_indicator_visible_type_set(ecore_wl2_window_, - ECORE_WL2_INDICATOR_VISIBLE_TYPE_SHOWN); - - int rotations[4] = {0, 90, 180, 270}; - ecore_wl2_window_available_rotations_set(ecore_wl2_window_, rotations, - sizeof(rotations) / sizeof(int)); - ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_ROTATE, RotationEventCb, this); - - return true; -} - -bool TizenRendererEcoreWl2::SetupEGL() { - ecore_wl2_egl_window_ = ecore_wl2_egl_window_create( - ecore_wl2_window_, initial_geometry_.w, initial_geometry_.h); - if (!ecore_wl2_egl_window_) { - FT_LOG(Error) << "Could not create an EGL window."; - return false; - } - - if (!ChooseEGLConfiguration()) { - FT_LOG(Error) << "Could not choose an EGL configuration."; - return false; - } - - egl_extension_str_ = eglQueryString(egl_display_, EGL_EXTENSIONS); - - { - const EGLint attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - - egl_context_ = - eglCreateContext(egl_display_, egl_config_, EGL_NO_CONTEXT, attribs); - if (egl_context_ == EGL_NO_CONTEXT) { - PrintEGLError(); - FT_LOG(Error) << "Could not create an onscreen context."; - return false; - } - - egl_resource_context_ = - eglCreateContext(egl_display_, egl_config_, egl_context_, attribs); - if (egl_resource_context_ == EGL_NO_CONTEXT) { - PrintEGLError(); - FT_LOG(Error) << "Could not create an offscreen context."; - return false; - } - } - - { - const EGLint attribs[] = {EGL_NONE}; - - auto* egl_window = static_cast( - ecore_wl2_egl_window_native_get(ecore_wl2_egl_window_)); - egl_surface_ = - eglCreateWindowSurface(egl_display_, egl_config_, egl_window, attribs); - if (egl_surface_ == EGL_NO_SURFACE) { - FT_LOG(Error) << "Could not create an onscreen window surface."; - return false; - } - } - - { - const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; - - egl_resource_surface_ = - eglCreatePbufferSurface(egl_display_, egl_config_, attribs); - if (egl_resource_surface_ == EGL_NO_SURFACE) { - FT_LOG(Error) << "Could not create an offscreen window surface."; - return false; - } - } - - return true; -} - -bool TizenRendererEcoreWl2::ChooseEGLConfiguration() { - EGLint config_attribs[] = { - // clang-format off - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, EGL_DONT_CARE, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_SAMPLE_BUFFERS, EGL_DONT_CARE, - EGL_SAMPLES, EGL_DONT_CARE, - EGL_NONE - // clang-format on - }; - - egl_display_ = eglGetDisplay(ecore_wl2_display_get(ecore_wl2_display_)); - if (EGL_NO_DISPLAY == egl_display_) { - PrintEGLError(); - FT_LOG(Error) << "Could not get EGL display."; - return false; - } - - if (!eglInitialize(egl_display_, nullptr, nullptr)) { - PrintEGLError(); - FT_LOG(Error) << "Could not initialize the EGL display."; - return false; - } - - if (!eglBindAPI(EGL_OPENGL_ES_API)) { - PrintEGLError(); - FT_LOG(Error) << "Could not bind the ES API."; - return false; - } - - EGLint config_size = 0; - if (!eglGetConfigs(egl_display_, nullptr, 0, &config_size)) { - PrintEGLError(); - FT_LOG(Error) << "Could not query framebuffer configurations."; - return false; - } - - EGLConfig* configs = (EGLConfig*)calloc(config_size, sizeof(EGLConfig)); - EGLint num_config; - if (!eglChooseConfig(egl_display_, config_attribs, configs, config_size, - &num_config)) { - free(configs); - PrintEGLError(); - FT_LOG(Error) << "No matching configurations found."; - return false; - } - - int buffer_size = 32; - EGLint size; - for (int i = 0; i < num_config; i++) { - eglGetConfigAttrib(egl_display_, configs[i], EGL_BUFFER_SIZE, &size); - if (buffer_size == size) { - egl_config_ = configs[i]; - break; - } - } - free(configs); - if (!egl_config_) { - FT_LOG(Error) << "No matching configuration found."; - return false; - } - - return true; -} - -void TizenRendererEcoreWl2::PrintEGLError() { - EGLint error = eglGetError(); - switch (error) { -#define CASE_PRINT(value) \ - case value: { \ - FT_LOG(Error) << "EGL error: " << #value; \ - break; \ - } - CASE_PRINT(EGL_NOT_INITIALIZED) - CASE_PRINT(EGL_BAD_ACCESS) - CASE_PRINT(EGL_BAD_ALLOC) - CASE_PRINT(EGL_BAD_ATTRIBUTE) - CASE_PRINT(EGL_BAD_CONTEXT) - CASE_PRINT(EGL_BAD_CONFIG) - CASE_PRINT(EGL_BAD_CURRENT_SURFACE) - CASE_PRINT(EGL_BAD_DISPLAY) - CASE_PRINT(EGL_BAD_SURFACE) - CASE_PRINT(EGL_BAD_MATCH) - CASE_PRINT(EGL_BAD_PARAMETER) - CASE_PRINT(EGL_BAD_NATIVE_PIXMAP) - CASE_PRINT(EGL_BAD_NATIVE_WINDOW) - CASE_PRINT(EGL_CONTEXT_LOST) -#undef CASE_PRINT - default: { - FT_LOG(Error) << "Unknown EGL error: " << error; - } - } -} - -void TizenRendererEcoreWl2::DestroyEcoreWl2() { - if (ecore_wl2_window_) { - ecore_wl2_window_free(ecore_wl2_window_); - ecore_wl2_window_ = nullptr; - } - - if (ecore_wl2_display_) { - ecore_wl2_display_disconnect(ecore_wl2_display_); - ecore_wl2_display_ = nullptr; - } - ecore_wl2_shutdown(); -} - -void TizenRendererEcoreWl2::DestroyEGL() { - if (egl_display_) { - eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - - if (EGL_NO_SURFACE != egl_surface_) { - eglDestroySurface(egl_display_, egl_surface_); - egl_surface_ = EGL_NO_SURFACE; - } - - if (EGL_NO_CONTEXT != egl_context_) { - eglDestroyContext(egl_display_, egl_context_); - egl_context_ = EGL_NO_CONTEXT; - } - - if (EGL_NO_SURFACE != egl_resource_surface_) { - eglDestroySurface(egl_display_, egl_resource_surface_); - egl_resource_surface_ = EGL_NO_SURFACE; - } - - if (EGL_NO_CONTEXT != egl_resource_context_) { - eglDestroyContext(egl_display_, egl_resource_context_); - egl_resource_context_ = EGL_NO_CONTEXT; - } - - eglTerminate(egl_display_); - egl_display_ = EGL_NO_DISPLAY; - } - - if (ecore_wl2_egl_window_) { - ecore_wl2_egl_window_destroy(ecore_wl2_egl_window_); - ecore_wl2_egl_window_ = nullptr; - } -} - -Eina_Bool TizenRendererEcoreWl2::RotationEventCb(void* data, - int type, - void* event) { - auto* self = reinterpret_cast(data); - auto* rotation_event = - reinterpret_cast(event); - self->delegate_.OnOrientationChange(rotation_event->angle); - return ECORE_CALLBACK_PASS_ON; -} - -void TizenRendererEcoreWl2::SetRotate(int angle) { - ecore_wl2_window_rotation_set(ecore_wl2_window_, angle); - received_rotation_ = true; -} - -void TizenRendererEcoreWl2::SetGeometry(int32_t x, - int32_t y, - int32_t width, - int32_t height) { - ecore_wl2_window_geometry_set(ecore_wl2_window_, x, y, width, height); - ecore_wl2_window_position_set(ecore_wl2_window_, x, y); -} - -void TizenRendererEcoreWl2::ResizeWithRotation(int32_t x, - int32_t y, - int32_t width, - int32_t height, - int32_t angle) { - ecore_wl2_egl_window_resize_with_rotation(ecore_wl2_egl_window_, x, y, width, - height, angle); -} - -void TizenRendererEcoreWl2::SendRotationChangeDone() { - int x, y, w, h; - ecore_wl2_window_geometry_get(ecore_wl2_window_, &x, &y, &w, &h); - ecore_wl2_window_rotation_change_done_send( - ecore_wl2_window_, ecore_wl2_window_rotation_get(ecore_wl2_window_), w, - h); -} - -void TizenRendererEcoreWl2::SetPreferredOrientations( - const std::vector& rotations) { - ecore_wl2_window_available_rotations_set(ecore_wl2_window_, rotations.data(), - rotations.size()); -} - -bool TizenRendererEcoreWl2::IsSupportedExtension(const char* name) { - return strstr(egl_extension_str_.c_str(), name); -} - -void TizenRendererEcoreWl2::SetTizenPolicyNotificationLevel(int level) { - Eina_Iterator* iter = ecore_wl2_display_globals_get(ecore_wl2_display_); - struct wl_registry* registry = - ecore_wl2_display_registry_get(ecore_wl2_display_); - - if (iter && registry) { - Ecore_Wl2_Global* global = nullptr; - - // Retrieve global objects to bind tizen policy - EINA_ITERATOR_FOREACH(iter, global) { - if (strcmp(global->interface, tizen_policy_interface.name) == 0) { - tizen_policy_ = static_cast( - wl_registry_bind(registry, global->id, &tizen_policy_interface, 1)); - break; - } - } - } - eina_iterator_free(iter); - - if (tizen_policy_ == nullptr) { - FT_LOG(Error) - << "Failed to initialize the tizen policy handle, the top_level " - "attribute is ignored."; - return; - } - - tizen_policy_set_notification_level( - tizen_policy_, ecore_wl2_window_surface_get(ecore_wl2_window_), level); -} - -void TizenRendererEcoreWl2::BindKeys(const std::vector& keys) { - for (const std::string& key : keys) { - ecore_wl2_window_keygrab_set(ecore_wl2_window_, key.c_str(), 0, 0, 0, - ECORE_WL2_WINDOW_KEYGRAB_TOPMOST); - } -} - } // namespace flutter diff --git a/shell/platform/tizen/tizen_renderer_egl.h b/shell/platform/tizen/tizen_renderer_egl.h new file mode 100644 index 0000000000000..74708e3b65fc6 --- /dev/null +++ b/shell/platform/tizen/tizen_renderer_egl.h @@ -0,0 +1,61 @@ +// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EMBEDDER_TIZEN_RENDERER_EGL_H_ +#define EMBEDDER_TIZEN_RENDERER_EGL_H_ + +#define EFL_BETA_API_SUPPORT +#include + +#include + +#include "flutter/shell/platform/tizen/tizen_renderer.h" + +namespace flutter { + +class TizenRendererEgl : public TizenRenderer { + public: + explicit TizenRendererEgl(); + + virtual ~TizenRendererEgl(); + + bool CreateSurface(void* render_target, + void* render_target_display, + int32_t width, + int32_t height) override; + + void DestroySurface() override; + + bool OnMakeCurrent() override; + + bool OnClearCurrent() override; + + bool OnMakeResourceCurrent() override; + + bool OnPresent() override; + + uint32_t OnGetFBO() override; + + void* OnProcResolver(const char* name) override; + + bool IsSupportedExtension(const char* name) override; + + private: + bool ChooseEGLConfiguration(); + + void PrintEGLError(); + + EGLConfig egl_config_ = nullptr; + EGLDisplay egl_display_ = EGL_NO_DISPLAY; + EGLContext egl_context_ = EGL_NO_CONTEXT; + EGLSurface egl_surface_ = EGL_NO_SURFACE; + EGLContext egl_resource_context_ = EGL_NO_CONTEXT; + EGLSurface egl_resource_surface_ = EGL_NO_SURFACE; + + std::string egl_extension_str_; +}; + +} // namespace flutter + +#endif // EMBEDDER_TIZEN_RENDERER_EGL_H_ diff --git a/shell/platform/tizen/tizen_renderer_evas_gl.cc b/shell/platform/tizen/tizen_renderer_evas_gl.cc index a4b218ee93575..5994cd0b4d54c 100644 --- a/shell/platform/tizen/tizen_renderer_evas_gl.cc +++ b/shell/platform/tizen/tizen_renderer_evas_gl.cc @@ -4,32 +4,79 @@ #include "tizen_renderer_evas_gl.h" -#include -#include - #include "tizen_evas_gl_helper.h" + +// g_evas_gl is shared with ExternalTexturePixelGL and ExternalTextureSurfaceGL. Evas_GL* g_evas_gl = nullptr; + EVAS_GL_GLOBAL_GLES3_DEFINE(); #include "flutter/shell/platform/tizen/logger.h" namespace flutter { -TizenRendererEvasGL::TizenRendererEvasGL(Geometry geometry, - bool transparent, - bool focusable, - bool top_level, - Delegate& delegate) - : TizenRenderer(geometry, transparent, focusable, top_level, delegate) { - if (!SetupEvasWindow()) { - FT_LOG(Error) << "Could not set up Evas window."; - return; +TizenRendererEvasGL::TizenRendererEvasGL() {} + +TizenRendererEvasGL::~TizenRendererEvasGL() { + DestroySurface(); +} + +bool TizenRendererEvasGL::CreateSurface(void* render_target, + void* render_target_display, + int32_t width, + int32_t height) { + evas_gl_ = evas_gl_new( + evas_object_evas_get(static_cast(render_target))); + if (!evas_gl_) { + FT_LOG(Error) << "Could not create an Evas GL object."; + return false; + } + + g_evas_gl = evas_gl_; + + gl_config_ = evas_gl_config_new(); + gl_config_->color_format = EVAS_GL_RGBA_8888; + gl_config_->depth_bits = EVAS_GL_DEPTH_NONE; + gl_config_->stencil_bits = EVAS_GL_STENCIL_NONE; + + gl_context_ = + evas_gl_context_version_create(evas_gl_, nullptr, EVAS_GL_GLES_3_X); + gl_resource_context_ = + evas_gl_context_version_create(evas_gl_, gl_context_, EVAS_GL_GLES_3_X); + if (!gl_context_) { + FT_LOG(Error) << "Failed to create an Evas GL context with " + "EVAS_GL_GLES_3_X; trying with EVAS_GL_GLES_2_X."; + gl_context_ = + evas_gl_context_version_create(evas_gl_, nullptr, EVAS_GL_GLES_2_X); + gl_resource_context_ = + evas_gl_context_version_create(evas_gl_, gl_context_, EVAS_GL_GLES_2_X); } - if (!SetupEvasGL()) { - FT_LOG(Error) << "Could not set up Evas GL."; - return; + if (!gl_context_) { + FT_LOG(Fatal) << "Failed to create an Evas GL context."; + return false; } - Show(); + + EVAS_GL_GLOBAL_GLES3_USE(evas_gl_, gl_context_); + + gl_surface_ = evas_gl_surface_create(evas_gl_, gl_config_, width, height); + gl_resource_surface_ = evas_gl_pbuffer_surface_create(evas_gl_, gl_config_, + width, height, nullptr); + + Evas_Native_Surface native_surface; + evas_gl_native_surface_get(evas_gl_, gl_surface_, &native_surface); + + image_ = static_cast(render_target_display); + evas_object_image_native_surface_set(image_, &native_surface); + + evas_object_image_pixels_get_callback_set( + image_, + [](void* data, Evas_Object* o) { + TizenRendererEvasGL* self = static_cast(data); + if (self->on_pixels_dirty_) { + self->on_pixels_dirty_(); + } + }, + this); is_valid_ = true; @@ -38,11 +85,18 @@ TizenRendererEvasGL::TizenRendererEvasGL(Geometry geometry, glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); OnPresent(); + return true; } -TizenRendererEvasGL::~TizenRendererEvasGL() { - DestroyEvasGL(); - DestroyEvasWindow(); +void TizenRendererEvasGL::DestroySurface() { + evas_gl_surface_destroy(evas_gl_, gl_surface_); + evas_gl_surface_destroy(evas_gl_, gl_resource_surface_); + + evas_gl_context_destroy(evas_gl_, gl_context_); + evas_gl_context_destroy(evas_gl_, gl_resource_context_); + + evas_gl_config_free(gl_config_); + evas_gl_free(evas_gl_); } bool TizenRendererEvasGL::OnMakeCurrent() { @@ -84,11 +138,6 @@ bool TizenRendererEvasGL::OnPresent() { return false; } - if (received_rotation_) { - SendRotationChangeDone(); - received_rotation_ = false; - } - return true; } @@ -99,6 +148,29 @@ uint32_t TizenRendererEvasGL::OnGetFBO() { return 0; } +bool TizenRendererEvasGL::IsSupportedExtension(const char* name) { + return strcmp(name, "EGL_TIZEN_image_native_surface") == 0; +} + +void TizenRendererEvasGL::MarkPixelsDirty() { + evas_object_image_pixels_dirty_set(image_, EINA_TRUE); +} + +void TizenRendererEvasGL::ResizeSurface(int32_t width, int32_t height) { + evas_gl_surface_destroy(evas_gl_, gl_surface_); + evas_gl_surface_destroy(evas_gl_, gl_resource_surface_); + + evas_object_image_native_surface_set(image_, nullptr); + evas_object_image_size_set(image_, width, height); + gl_surface_ = evas_gl_surface_create(evas_gl_, gl_config_, width, height); + gl_resource_surface_ = evas_gl_pbuffer_surface_create(evas_gl_, gl_config_, + width, height, nullptr); + + Evas_Native_Surface native_surface; + evas_gl_native_surface_get(evas_gl_, gl_surface_, &native_surface); + evas_object_image_native_surface_set(image_, &native_surface); +} + void* TizenRendererEvasGL::OnProcResolver(const char* name) { auto address = evas_gl_proc_address_get(evas_gl_, name); if (address != nullptr) { @@ -554,236 +626,4 @@ void* TizenRendererEvasGL::OnProcResolver(const char* name) { return nullptr; } -TizenRenderer::Geometry TizenRendererEvasGL::GetWindowGeometry() { - Geometry result; - evas_object_geometry_get(evas_window_, &result.x, &result.y, &result.w, - &result.h); - return result; -} - -TizenRenderer::Geometry TizenRendererEvasGL::GetScreenGeometry() { - Geometry result = {}; - Ecore_Evas* ecore_evas = - ecore_evas_ecore_evas_get(evas_object_evas_get(evas_window_)); - ecore_evas_screen_geometry_get(ecore_evas, nullptr, nullptr, &result.w, - &result.h); - return result; -} - -int32_t TizenRendererEvasGL::GetDpi() { - Ecore_Evas* ecore_evas = - ecore_evas_ecore_evas_get(evas_object_evas_get(evas_window_)); - int32_t xdpi, ydpi; - ecore_evas_screen_dpi_get(ecore_evas, &xdpi, &ydpi); - return xdpi; -} - -uintptr_t TizenRendererEvasGL::GetWindowId() { - return ecore_evas_window_get( - ecore_evas_ecore_evas_get(evas_object_evas_get(evas_window_))); -} - -void TizenRendererEvasGL::Show() { - evas_object_show(graphics_adapter_); - evas_object_show(evas_window_); -} - -bool TizenRendererEvasGL::SetupEvasGL() { - evas_gl_ = evas_gl_new(evas_object_evas_get(evas_window_)); - if (!evas_gl_) { - FT_LOG(Error) << "Could not create an Evas GL object."; - return false; - } - g_evas_gl = evas_gl_; - - gl_config_ = evas_gl_config_new(); - gl_config_->color_format = EVAS_GL_RGBA_8888; - gl_config_->depth_bits = EVAS_GL_DEPTH_NONE; - gl_config_->stencil_bits = EVAS_GL_STENCIL_NONE; - - gl_context_ = - evas_gl_context_version_create(evas_gl_, nullptr, EVAS_GL_GLES_3_X); - gl_resource_context_ = - evas_gl_context_version_create(evas_gl_, gl_context_, EVAS_GL_GLES_3_X); - if (!gl_context_) { - FT_LOG(Error) << "Failed to create an Evas GL context with " - "EVAS_GL_GLES_3_X; trying with EVAS_GL_GLES_2_X."; - gl_context_ = - evas_gl_context_version_create(evas_gl_, nullptr, EVAS_GL_GLES_2_X); - gl_resource_context_ = - evas_gl_context_version_create(evas_gl_, gl_context_, EVAS_GL_GLES_2_X); - } - if (!gl_context_) { - FT_LOG(Fatal) << "Failed to create an Evas GL context."; - return false; - } - - EVAS_GL_GLOBAL_GLES3_USE(g_evas_gl, gl_context_); - - gl_surface_ = evas_gl_surface_create( - evas_gl_, gl_config_, initial_geometry_.w, initial_geometry_.h); - gl_resource_surface_ = evas_gl_pbuffer_surface_create( - evas_gl_, gl_config_, initial_geometry_.w, initial_geometry_.h, nullptr); - - Evas_Native_Surface native_surface; - evas_gl_native_surface_get(evas_gl_, gl_surface_, &native_surface); - evas_object_image_native_surface_set(graphics_adapter_, &native_surface); - - return true; -} - -bool TizenRendererEvasGL::SetupEvasWindow() { - elm_config_accel_preference_set("hw:opengl"); - - evas_window_ = elm_win_add(nullptr, nullptr, - top_level_ ? ELM_WIN_NOTIFICATION : ELM_WIN_BASIC); - if (!evas_window_) { - FT_LOG(Error) << "Could not create an Evas window."; - return false; - } - if (top_level_) { - efl_util_set_notification_window_level(evas_window_, - EFL_UTIL_NOTIFICATION_LEVEL_TOP); - } - // Please uncomment below and enable setWindowGeometry of window channel when - // Tizen 5.5 or later was chosen as default. - // elm_win_aux_hint_add(evas_window_, "wm.policy.win.user.geometry", "1"); - - Ecore_Evas* ecore_evas = - ecore_evas_ecore_evas_get(evas_object_evas_get(evas_window_)); - - int32_t width, height; - ecore_evas_screen_geometry_get(ecore_evas, nullptr, nullptr, &width, &height); - if (width == 0 || height == 0) { - FT_LOG(Error) << "Invalid screen size: " << width << " x " << height; - return false; - } - - if (initial_geometry_.w == 0) { - initial_geometry_.w = width; - } - if (initial_geometry_.h == 0) { - initial_geometry_.h = height; - } - - evas_object_move(evas_window_, initial_geometry_.x, initial_geometry_.y); - evas_object_resize(evas_window_, initial_geometry_.w, initial_geometry_.h); - evas_object_raise(evas_window_); - - elm_win_indicator_mode_set(evas_window_, ELM_WIN_INDICATOR_SHOW); - elm_win_indicator_opacity_set(evas_window_, ELM_WIN_INDICATOR_OPAQUE); - - if (transparent_) { - elm_win_alpha_set(evas_window_, EINA_TRUE); - } else { - elm_win_alpha_set(evas_window_, EINA_FALSE); - - Evas_Object* bg = elm_bg_add(evas_window_); - evas_object_color_set(bg, 0, 0, 0, 0); - - evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - elm_win_resize_object_add(evas_window_, bg); - } - - graphics_adapter_ = - evas_object_image_filled_add(evas_object_evas_get(evas_window_)); - evas_object_resize(graphics_adapter_, initial_geometry_.w, - initial_geometry_.h); - evas_object_move(graphics_adapter_, initial_geometry_.x, initial_geometry_.y); - evas_object_image_size_set(graphics_adapter_, initial_geometry_.w, - initial_geometry_.h); - evas_object_image_alpha_set(graphics_adapter_, EINA_TRUE); - elm_win_resize_object_add(evas_window_, graphics_adapter_); - - const int rotations[4] = {0, 90, 180, 270}; - elm_win_wm_rotation_available_rotations_set(evas_window_, &rotations[0], 4); - evas_object_smart_callback_add(evas_window_, "rotation,changed", - RotationEventCb, this); - - return true; -} - -void TizenRendererEvasGL::DestroyEvasWindow() { - evas_object_del(evas_window_); - evas_object_del(graphics_adapter_); -} - -void TizenRendererEvasGL::DestroyEvasGL() { - evas_gl_surface_destroy(evas_gl_, gl_surface_); - evas_gl_surface_destroy(evas_gl_, gl_resource_surface_); - - evas_gl_context_destroy(evas_gl_, gl_context_); - evas_gl_context_destroy(evas_gl_, gl_resource_context_); - - evas_gl_config_free(gl_config_); - evas_gl_free(evas_gl_); -} - -void TizenRendererEvasGL::RotationEventCb(void* data, - Evas_Object* obj, - void* event_info) { - auto* self = reinterpret_cast(data); - FT_UNIMPLEMENTED(); - self->delegate_.OnOrientationChange(0); -} - -void TizenRendererEvasGL::SetRotate(int angle) { - elm_win_rotation_set(evas_window_, angle); - received_rotation_ = true; -} - -void TizenRendererEvasGL::SetGeometry(int32_t x, - int32_t y, - int32_t width, - int32_t height) { - evas_object_move(evas_window_, x, y); - evas_object_resize(evas_window_, width, height); - - evas_object_resize(graphics_adapter_, width, height); - evas_object_image_native_surface_set(graphics_adapter_, nullptr); - - evas_gl_surface_destroy(evas_gl_, gl_surface_); - evas_gl_surface_destroy(evas_gl_, gl_resource_surface_); - - evas_object_image_size_set(graphics_adapter_, width, height); - gl_surface_ = evas_gl_surface_create(evas_gl_, gl_config_, width, height); - gl_resource_surface_ = evas_gl_pbuffer_surface_create(evas_gl_, gl_config_, - width, height, nullptr); - - Evas_Native_Surface native_surface; - evas_gl_native_surface_get(evas_gl_, gl_surface_, &native_surface); - evas_object_image_native_surface_set(graphics_adapter_, &native_surface); -} - -void TizenRendererEvasGL::ResizeWithRotation(int32_t x, - int32_t y, - int32_t width, - int32_t height, - int32_t angle) { - evas_object_move(evas_window_, x, y); - evas_object_resize(evas_window_, width, height); - SetRotate(angle); -} - -void TizenRendererEvasGL::SendRotationChangeDone() { - elm_win_wm_rotation_manual_rotation_done(evas_window_); -} - -void TizenRendererEvasGL::SetPreferredOrientations( - const std::vector& rotations) { - elm_win_wm_rotation_available_rotations_set( - evas_window_, static_cast(rotations.data()), - rotations.size()); -} - -bool TizenRendererEvasGL::IsSupportedExtension(const char* name) { - return strcmp(name, "EGL_TIZEN_image_native_surface") == 0; -} - -void TizenRendererEvasGL::BindKeys(const std::vector& keys) { - for (const std::string& key : keys) { - eext_win_keygrab_set(evas_window_, key.c_str()); - } -} - } // namespace flutter diff --git a/shell/platform/tizen/tizen_renderer_evas_gl.h b/shell/platform/tizen/tizen_renderer_evas_gl.h index eb1525ecad76f..badba04499004 100644 --- a/shell/platform/tizen/tizen_renderer_evas_gl.h +++ b/shell/platform/tizen/tizen_renderer_evas_gl.h @@ -5,8 +5,9 @@ #ifndef EMBEDDER_TIZEN_RENDERER_EVAS_GL_H_ #define EMBEDDER_TIZEN_RENDERER_EVAS_GL_H_ +#include + #undef EFL_BETA_API_SUPPORT -#include #include #include @@ -14,67 +15,51 @@ namespace flutter { +using OnPixelsDirty = std::function; + class TizenRendererEvasGL : public TizenRenderer { public: - explicit TizenRendererEvasGL(Geometry geometry, - bool transparent, - bool focusable, - bool top_level, - Delegate& delegate); + explicit TizenRendererEvasGL(); + virtual ~TizenRendererEvasGL(); + bool CreateSurface(void* render_target, + void* render_target_display, + int32_t width, + int32_t height) override; + + void DestroySurface() override; + bool OnMakeCurrent() override; + bool OnClearCurrent() override; - bool OnMakeResourceCurrent() override; - bool OnPresent() override; - uint32_t OnGetFBO() override; - void* OnProcResolver(const char* name) override; - Geometry GetWindowGeometry() override; - Geometry GetScreenGeometry() override; - int32_t GetDpi() override; - uintptr_t GetWindowId() override; + bool OnMakeResourceCurrent() override; - void* GetWindowHandle() override { return evas_window_; } + bool OnPresent() override; - Evas_Object* GetImageHandle() { return graphics_adapter_; } + uint32_t OnGetFBO() override; - void SetRotate(int angle) override; - void SetGeometry(int32_t x, - int32_t y, - int32_t width, - int32_t height) override; - void ResizeWithRotation(int32_t x, - int32_t y, - int32_t width, - int32_t height, - int32_t angle) override; - void SetPreferredOrientations(const std::vector& rotations) override; + void* OnProcResolver(const char* name) override; bool IsSupportedExtension(const char* name) override; - void BindKeys(const std::vector& keys) override; + void SetOnPixelsDirty(OnPixelsDirty callback) { on_pixels_dirty_ = callback; } - private: - void Show(); + void MarkPixelsDirty(); - bool SetupEvasWindow(); - bool SetupEvasGL(); - void DestroyEvasWindow(); - void DestroyEvasGL(); - - static void RotationEventCb(void* data, Evas_Object* obj, void* event_info); - void SendRotationChangeDone(); - - Evas_Object* evas_window_ = nullptr; - Evas_Object* graphics_adapter_ = nullptr; + void ResizeSurface(int32_t width, int32_t height); + private: Evas_GL* evas_gl_ = nullptr; Evas_GL_Config* gl_config_ = nullptr; Evas_GL_Context* gl_context_ = nullptr; Evas_GL_Context* gl_resource_context_ = nullptr; Evas_GL_Surface* gl_surface_ = nullptr; Evas_GL_Surface* gl_resource_surface_ = nullptr; + + Evas_Object* image_ = nullptr; + OnPixelsDirty on_pixels_dirty_; }; } // namespace flutter diff --git a/shell/platform/tizen/tizen_window.h b/shell/platform/tizen/tizen_window.h new file mode 100644 index 0000000000000..b4a6ed94d5d2b --- /dev/null +++ b/shell/platform/tizen/tizen_window.h @@ -0,0 +1,88 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// 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 EMBEDDER_TIZEN_WINDOW_H_ +#define EMBEDDER_TIZEN_WINDOW_H_ + +#include +#include +#include + +namespace flutter { + +class FlutterTizenView; + +class TizenWindow { + public: + struct Geometry { + int32_t left = 0, top = 0, width = 0, height = 0; + }; + + TizenWindow(); + + virtual ~TizenWindow() = default; + + // Sets the delegate used to communicate state changes from window to view + // such as key presses, mouse position updates etc. + void SetView(FlutterTizenView* view) { view_ = view; } + + // Returns the geometry of the current window. + virtual Geometry GetWindowGeometry() = 0; + + // Set the geometry of the current window. + virtual void SetWindowGeometry(Geometry geometry) = 0; + + // Returns the geometry of the display screen. + virtual Geometry GetScreenGeometry() = 0; + + // Returns a valid pointer the platform object that rendering can be bound to + // by rendering backend. + virtual void* GetRenderTarget() = 0; + + virtual void* GetRenderTargetDisplay() = 0; + + virtual int32_t GetRotation() = 0; + + // Returns the dpi of the screen. + virtual int32_t GetDpi() = 0; + + virtual uintptr_t GetWindowId() = 0; + + virtual void* GetWindowHandle() = 0; + + virtual void ResizeRenderTargetWithRotation(Geometry geometry, + int32_t degree) = 0; + + virtual void SetPreferredOrientations(const std::vector& rotations) = 0; + + virtual void BindKeys(const std::vector& keys) = 0; + + virtual void Show() = 0; + + // FIXME + // This is a temporary implementation that is only used by the window channel. + virtual void OnGeometryChanged(Geometry geometry) = 0; + + protected: + explicit TizenWindow(Geometry geometry, + bool transparent, + bool focusable, + bool top_level) + : initial_geometry_(geometry), + transparent_(transparent), + focusable_(focusable), + top_level_(top_level) {} + + Geometry initial_geometry_ = {0, 0, 0, 0}; + bool transparent_ = false; + bool focusable_ = false; + bool top_level_ = false; + + FlutterTizenView* view_ = nullptr; +}; + +} // namespace flutter + +#endif // EMBEDDER_TIZEN_WINDOW_H_ diff --git a/shell/platform/tizen/tizen_window_ecore_wl2.cc b/shell/platform/tizen/tizen_window_ecore_wl2.cc new file mode 100644 index 0000000000000..4353f4d30c256 --- /dev/null +++ b/shell/platform/tizen/tizen_window_ecore_wl2.cc @@ -0,0 +1,396 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// 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 "tizen_window_ecore_wl2.h" + +#include "flutter/shell/platform/tizen/flutter_tizen_view.h" +#include "flutter/shell/platform/tizen/logger.h" + +namespace { + +static const int kScrollDirectionVertical = 0; +static const int kScrollDirectionHorizontal = 1; +static const int kScrollOffsetMultiplier = 20; + +} // namespace + +namespace flutter { + +TizenWindowEcoreWl2::TizenWindowEcoreWl2(Geometry geometry, + bool transparent, + bool focusable, + bool top_level) + : TizenWindow(geometry, transparent, focusable, top_level) { + if (!CreateWindow()) { + FT_LOG(Error) << "Failed to create a platform window."; + return; + } + + SetWindowOptions(); + RegisterEventHandlers(); + Show(); +} + +TizenWindowEcoreWl2::~TizenWindowEcoreWl2() { + UnregisterEventHandlers(); + DestroyWindow(); +} + +bool TizenWindowEcoreWl2::CreateWindow() { + if (!ecore_wl2_init()) { + FT_LOG(Error) << "Could not initialize Ecore Wl2."; + return false; + } + + ecore_wl2_display_ = ecore_wl2_display_connect(nullptr); + if (!ecore_wl2_display_) { + FT_LOG(Error) << "Ecore Wl2 display not found."; + return false; + } + wl2_display_ = ecore_wl2_display_get(ecore_wl2_display_); + + ecore_wl2_sync(); + + int32_t width, height; + ecore_wl2_display_screen_size_get(ecore_wl2_display_, &width, &height); + if (width == 0 || height == 0) { + FT_LOG(Error) << "Invalid screen size: " << width << " x " << height; + return false; + } + + if (initial_geometry_.width == 0) { + initial_geometry_.width = width; + } + if (initial_geometry_.height == 0) { + initial_geometry_.height = height; + } + + ecore_wl2_window_ = ecore_wl2_window_new( + ecore_wl2_display_, nullptr, initial_geometry_.left, + initial_geometry_.top, initial_geometry_.width, initial_geometry_.height); + + ecore_wl2_egl_window_ = ecore_wl2_egl_window_create( + ecore_wl2_window_, initial_geometry_.width, initial_geometry_.height); + + return ecore_wl2_egl_window_ && wl2_display_; +} + +void TizenWindowEcoreWl2::SetWindowOptions() { + // Change the window type to use the tizen policy for notification window + // according to top_level_. + // Note: ECORE_WL2_WINDOW_TYPE_TOPLEVEL is similar to "ELM_WIN_BASIC" and it + // does not mean that the window always will be overlaid on other apps :( + ecore_wl2_window_type_set(ecore_wl2_window_, + top_level_ ? ECORE_WL2_WINDOW_TYPE_NOTIFICATION + : ECORE_WL2_WINDOW_TYPE_TOPLEVEL); + if (top_level_) { + SetTizenPolicyNotificationLevel(TIZEN_POLICY_LEVEL_TOP); + } + + ecore_wl2_window_position_set(ecore_wl2_window_, initial_geometry_.left, + initial_geometry_.top); + ecore_wl2_window_aux_hint_add(ecore_wl2_window_, 0, + "wm.policy.win.user.geometry", "1"); + + if (transparent_) { + ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_TRUE); + } else { + ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_FALSE); + } + + if (!focusable_) { + ecore_wl2_window_focus_skip_set(ecore_wl2_window_, EINA_TRUE); + } + + ecore_wl2_window_indicator_state_set(ecore_wl2_window_, + ECORE_WL2_INDICATOR_STATE_ON); + ecore_wl2_window_indicator_opacity_set(ecore_wl2_window_, + ECORE_WL2_INDICATOR_OPAQUE); + ecore_wl2_indicator_visible_type_set(ecore_wl2_window_, + ECORE_WL2_INDICATOR_VISIBLE_TYPE_SHOWN); + + int rotations[4] = {0, 90, 180, 270}; + ecore_wl2_window_available_rotations_set(ecore_wl2_window_, rotations, + sizeof(rotations) / sizeof(int)); +} + +void TizenWindowEcoreWl2::RegisterEventHandlers() { + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_WL2_EVENT_WINDOW_ROTATE, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* rotation_event = + reinterpret_cast(event); + if (rotation_event->win == self->GetWindowId()) { + int32_t degree = rotation_event->angle; + self->view_->OnRotate(degree); + Geometry geometry = self->GetWindowGeometry(); + ecore_wl2_window_rotation_change_done_send( + self->ecore_wl2_window_, rotation_event->rotation, + geometry.width, geometry.height); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); + + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_WL2_EVENT_WINDOW_CONFIGURE, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* configure_event = + reinterpret_cast(event); + if (configure_event->win == self->GetWindowId()) { + self->view_->OnResize(configure_event->x, configure_event->y, + configure_event->w, configure_event->h); + ecore_wl2_window_commit(self->ecore_wl2_window_, EINA_FALSE); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); + + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_MOUSE_BUTTON_DOWN, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* button_event = + reinterpret_cast(event); + if (button_event->window == self->GetWindowId()) { + self->view_->OnPointerDown( + button_event->x, button_event->y, button_event->timestamp, + kFlutterPointerDeviceKindTouch, button_event->multi.device); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); + + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_MOUSE_BUTTON_UP, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* button_event = + reinterpret_cast(event); + if (button_event->window == self->GetWindowId()) { + self->view_->OnPointerUp( + button_event->x, button_event->y, button_event->timestamp, + kFlutterPointerDeviceKindTouch, button_event->multi.device); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); + + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_MOUSE_MOVE, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* move_event = reinterpret_cast(event); + if (move_event->window == self->GetWindowId()) { + self->view_->OnPointerMove( + move_event->x, move_event->y, move_event->timestamp, + kFlutterPointerDeviceKindTouch, move_event->multi.device); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); + + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_MOUSE_WHEEL, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* wheel_event = reinterpret_cast(event); + if (wheel_event->window == self->GetWindowId()) { + double delta_x = 0.0; + double delta_y = 0.0; + + if (wheel_event->direction == kScrollDirectionVertical) { + delta_y += wheel_event->z; + } else if (wheel_event->direction == kScrollDirectionHorizontal) { + delta_x += wheel_event->z; + } + + self->view_->OnScroll(wheel_event->x, wheel_event->y, delta_x, + delta_y, kScrollOffsetMultiplier, + wheel_event->timestamp, + kFlutterPointerDeviceKindTouch, 0); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); + + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_KEY_DOWN, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* key_event = reinterpret_cast(event); + if (key_event->window == self->GetWindowId()) { + self->view_->OnKey(key_event, true); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); + + ecore_event_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_KEY_UP, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* key_event = reinterpret_cast(event); + if (key_event->window == self->GetWindowId()) { + self->view_->OnKey(key_event, false); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); +} + +void TizenWindowEcoreWl2::UnregisterEventHandlers() { + for (Ecore_Event_Handler* handler : ecore_event_handlers_) { + ecore_event_handler_del(handler); + } + ecore_event_handlers_.clear(); +} + +void TizenWindowEcoreWl2::DestroyWindow() { + if (ecore_wl2_egl_window_) { + ecore_wl2_egl_window_destroy(ecore_wl2_egl_window_); + ecore_wl2_egl_window_ = nullptr; + } + + if (ecore_wl2_window_) { + ecore_wl2_window_free(ecore_wl2_window_); + ecore_wl2_window_ = nullptr; + } + + if (ecore_wl2_display_) { + ecore_wl2_display_disconnect(ecore_wl2_display_); + ecore_wl2_display_ = nullptr; + } + ecore_wl2_shutdown(); +} + +TizenWindow::Geometry TizenWindowEcoreWl2::GetWindowGeometry() { + Geometry result; + ecore_wl2_window_geometry_get(ecore_wl2_window_, &result.left, &result.top, + &result.width, &result.height); + return result; +} + +void TizenWindowEcoreWl2::SetWindowGeometry(Geometry geometry) { + ecore_wl2_window_geometry_set(ecore_wl2_window_, geometry.left, geometry.top, + geometry.width, geometry.height); + // FIXME: The changes set in `ecore_wl2_window_geometry_set` seems to apply + // only after calling `ecore_wl2_window_position_set`. Call a more appropriate + // API that flushes geometry settings to the compositor. + ecore_wl2_window_position_set(ecore_wl2_window_, geometry.left, geometry.top); +} + +TizenWindow::Geometry TizenWindowEcoreWl2::GetScreenGeometry() { + Geometry result = {}; + ecore_wl2_display_screen_size_get(ecore_wl2_display_, &result.width, + &result.height); + return result; +} + +int32_t TizenWindowEcoreWl2::GetRotation() { + return ecore_wl2_window_rotation_get(ecore_wl2_window_); +} + +int32_t TizenWindowEcoreWl2::GetDpi() { + Ecore_Wl2_Output* output = ecore_wl2_window_output_find(ecore_wl2_window_); + if (!output) { + FT_LOG(Error) << "Could not find an output associated with the window."; + return 0; + } + return ecore_wl2_output_dpi_get(output); +} + +uintptr_t TizenWindowEcoreWl2::GetWindowId() { + return ecore_wl2_window_id_get(ecore_wl2_window_); +} + +void TizenWindowEcoreWl2::ResizeRenderTargetWithRotation(Geometry geometry, + int32_t angle) { + ecore_wl2_egl_window_resize_with_rotation( + ecore_wl2_egl_window_, geometry.left, geometry.top, geometry.width, + geometry.height, angle); +} + +void TizenWindowEcoreWl2::SetPreferredOrientations( + const std::vector& rotations) { + ecore_wl2_window_available_rotations_set(ecore_wl2_window_, rotations.data(), + rotations.size()); +} + +void TizenWindowEcoreWl2::BindKeys(const std::vector& keys) { + for (const std::string& key : keys) { + ecore_wl2_window_keygrab_set(ecore_wl2_window_, key.c_str(), 0, 0, 0, + ECORE_WL2_WINDOW_KEYGRAB_TOPMOST); + } +} + +void TizenWindowEcoreWl2::Show() { + ecore_wl2_window_show(ecore_wl2_window_); +} + +void TizenWindowEcoreWl2::OnGeometryChanged(Geometry geometry) { + // This implementation mimics the situation in which the handler of + // ECORE_WL2_EVENT_WINDOW_CONFIGURE is called. + SetWindowGeometry(geometry); + view_->OnResize(geometry.left, geometry.top, geometry.width, geometry.height); +} + +void TizenWindowEcoreWl2::SetTizenPolicyNotificationLevel(int level) { + Eina_Iterator* iter = ecore_wl2_display_globals_get(ecore_wl2_display_); + struct wl_registry* registry = + ecore_wl2_display_registry_get(ecore_wl2_display_); + + if (iter && registry) { + Ecore_Wl2_Global* global = nullptr; + + // Retrieve global objects to bind tizen policy + EINA_ITERATOR_FOREACH(iter, global) { + if (strcmp(global->interface, tizen_policy_interface.name) == 0) { + tizen_policy_ = static_cast( + wl_registry_bind(registry, global->id, &tizen_policy_interface, 1)); + break; + } + } + } + eina_iterator_free(iter); + + if (tizen_policy_ == nullptr) { + FT_LOG(Error) + << "Failed to initialize the tizen policy handle, the top_level " + "attribute is ignored."; + return; + } + + tizen_policy_set_notification_level( + tizen_policy_, ecore_wl2_window_surface_get(ecore_wl2_window_), level); +} + +} // namespace flutter diff --git a/shell/platform/tizen/tizen_window_ecore_wl2.h b/shell/platform/tizen/tizen_window_ecore_wl2.h new file mode 100644 index 0000000000000..25dc1f56f9287 --- /dev/null +++ b/shell/platform/tizen/tizen_window_ecore_wl2.h @@ -0,0 +1,80 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// 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 EMBEDDER_TIZEN_WINDOW_ECORE_WL2_H_ +#define EMBEDDER_TIZEN_WINDOW_ECORE_WL2_H_ + +#include "flutter/shell/platform/tizen/tizen_window.h" + +#define EFL_BETA_API_SUPPORT +#include +#include + +namespace flutter { + +class TizenWindowEcoreWl2 : public TizenWindow { + public: + TizenWindowEcoreWl2(Geometry geometry, + bool transparent, + bool focusable, + bool top_level); + + ~TizenWindowEcoreWl2(); + + Geometry GetWindowGeometry() override; + + void SetWindowGeometry(Geometry geometry) override; + + Geometry GetScreenGeometry() override; + + void* GetRenderTarget() override { return ecore_wl2_egl_window_; } + + void* GetRenderTargetDisplay() override { return wl2_display_; } + + int32_t GetRotation() override; + + int32_t GetDpi() override; + + uintptr_t GetWindowId() override; + + void* GetWindowHandle() override { return ecore_wl2_window_; } + + void ResizeRenderTargetWithRotation(Geometry geometry, + int32_t angle) override; + + void SetPreferredOrientations(const std::vector& rotations) override; + + void BindKeys(const std::vector& keys) override; + + void Show() override; + + void OnGeometryChanged(Geometry geometry) override; + + private: + bool CreateWindow(); + + void DestroyWindow(); + + void SetWindowOptions(); + + void RegisterEventHandlers(); + + void UnregisterEventHandlers(); + + void SetTizenPolicyNotificationLevel(int level); + + Ecore_Wl2_Display* ecore_wl2_display_ = nullptr; + Ecore_Wl2_Window* ecore_wl2_window_ = nullptr; + + Ecore_Wl2_Egl_Window* ecore_wl2_egl_window_ = nullptr; + wl_display* wl2_display_ = nullptr; + std::vector ecore_event_handlers_; + + tizen_policy* tizen_policy_ = nullptr; +}; + +} // namespace flutter + +#endif // EMBEDDER_TIZEN_WINDOW_ECORE_WL2_H_ diff --git a/shell/platform/tizen/tizen_window_elementary.cc b/shell/platform/tizen/tizen_window_elementary.cc new file mode 100644 index 0000000000000..49725fe0d6fc9 --- /dev/null +++ b/shell/platform/tizen/tizen_window_elementary.cc @@ -0,0 +1,348 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// 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 "tizen_window_elementary.h" + +#include "flutter/shell/platform/tizen/flutter_tizen_view.h" +#include "flutter/shell/platform/tizen/logger.h" + +#include +#include + +namespace { + +static const int kScrollDirectionVertical = 0; +static const int kScrollDirectionHorizontal = 1; +static const int kScrollOffsetMultiplier = 20; + +} // namespace + +namespace flutter { + +TizenWindowElementary::TizenWindowElementary(Geometry geometry, + bool transparent, + bool focusable, + bool top_level) + : TizenWindow(geometry, transparent, focusable, top_level) { + if (!CreateWindow()) { + FT_LOG(Error) << "Failed to create a platform window."; + return; + } + + SetWindowOptions(); + RegisterEventHandlers(); + Show(); +} + +TizenWindowElementary::~TizenWindowElementary() { + UnregisterEventHandlers(); + DestroyWindow(); +} + +bool TizenWindowElementary::CreateWindow() { + elm_config_accel_preference_set("hw:opengl"); + + elm_win_ = elm_win_add(nullptr, nullptr, + top_level_ ? ELM_WIN_NOTIFICATION : ELM_WIN_BASIC); + if (!elm_win_) { + FT_LOG(Error) << "Could not create an Evas window."; + return false; + } + + // Please uncomment below and enable setWindowGeometry of window channel when + // Tizen 5.5 or later was chosen as default. + // elm_win_aux_hint_add(elm_win_, "wm.policy.win.user.geometry", "1"); + + Ecore_Evas* ecore_evas = + ecore_evas_ecore_evas_get(evas_object_evas_get(elm_win_)); + + int32_t width, height; + ecore_evas_screen_geometry_get(ecore_evas, nullptr, nullptr, &width, &height); + if (width == 0 || height == 0) { + FT_LOG(Error) << "Invalid screen size: " << width << " x " << height; + return false; + } + + if (initial_geometry_.width == 0) { + initial_geometry_.width = width; + } + if (initial_geometry_.height == 0) { + initial_geometry_.height = height; + } + + evas_object_move(elm_win_, initial_geometry_.left, initial_geometry_.top); + evas_object_resize(elm_win_, initial_geometry_.width, + initial_geometry_.height); + evas_object_raise(elm_win_); + + image_ = evas_object_image_filled_add(evas_object_evas_get(elm_win_)); + evas_object_resize(image_, initial_geometry_.width, initial_geometry_.height); + evas_object_move(image_, initial_geometry_.left, initial_geometry_.top); + evas_object_image_size_set(image_, initial_geometry_.width, + initial_geometry_.height); + evas_object_image_alpha_set(image_, EINA_TRUE); + elm_win_resize_object_add(elm_win_, image_); + + return elm_win_ && image_; +} + +void TizenWindowElementary::DestroyWindow() { + evas_object_del(elm_win_); + evas_object_del(image_); +} + +void TizenWindowElementary::SetWindowOptions() { + if (top_level_) { + efl_util_set_notification_window_level(elm_win_, + EFL_UTIL_NOTIFICATION_LEVEL_TOP); + } + + if (transparent_) { + elm_win_alpha_set(elm_win_, EINA_TRUE); + } else { + elm_win_alpha_set(elm_win_, EINA_FALSE); + + Evas_Object* bg = elm_bg_add(elm_win_); + evas_object_color_set(bg, 0, 0, 0, 0); + + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(elm_win_, bg); + } + + elm_win_indicator_mode_set(elm_win_, ELM_WIN_INDICATOR_SHOW); + elm_win_indicator_opacity_set(elm_win_, ELM_WIN_INDICATOR_OPAQUE); + + // TODO: focusable_ + + const int rotations[4] = {0, 90, 180, 270}; + elm_win_wm_rotation_available_rotations_set(elm_win_, &rotations[0], 4); +} + +void TizenWindowElementary::RegisterEventHandlers() { + rotatoin_changed_callback_ = [](void* data, Evas_Object* object, + void* event_info) { + auto* self = reinterpret_cast(data); + if (self->view_) { + if (self->elm_win_ == object) { + // FIXME + FT_UNIMPLEMENTED(); + self->view_->OnRotate(self->GetRotation()); + elm_win_wm_rotation_manual_rotation_done(self->elm_win_); + } + } + }; + evas_object_smart_callback_add(elm_win_, "rotation,changed", + rotatoin_changed_callback_, this); + + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_DOWN] = + [](void* data, Evas* evas, Evas_Object* object, void* event_info) { + auto* self = reinterpret_cast(data); + if (self->view_) { + if (self->elm_win_ == object) { + auto* mouse_event = + reinterpret_cast(event_info); + self->view_->OnPointerDown( + mouse_event->canvas.x, mouse_event->canvas.y, + mouse_event->timestamp, kFlutterPointerDeviceKindTouch, + mouse_event->button); + } + } + }; + evas_object_event_callback_add( + elm_win_, EVAS_CALLBACK_MOUSE_DOWN, + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_DOWN], this); + + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_UP] = [](void* data, Evas* evas, + Evas_Object* object, + void* event_info) { + auto* self = reinterpret_cast(data); + if (self->view_) { + if (self->elm_win_ == object) { + auto* mouse_event = reinterpret_cast(event_info); + self->view_->OnPointerUp(mouse_event->canvas.x, mouse_event->canvas.y, + mouse_event->timestamp, + kFlutterPointerDeviceKindTouch, + mouse_event->button); + } + } + }; + evas_object_event_callback_add(elm_win_, EVAS_CALLBACK_MOUSE_UP, + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_UP], + this); + + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_MOVE] = + [](void* data, Evas* evas, Evas_Object* object, void* event_info) { + auto* self = reinterpret_cast(data); + if (self->view_) { + if (self->elm_win_ == object) { + auto* mouse_event = + reinterpret_cast(event_info); + self->view_->OnPointerMove( + mouse_event->cur.canvas.x, mouse_event->cur.canvas.y, + mouse_event->timestamp, kFlutterPointerDeviceKindTouch, + mouse_event->buttons); + } + } + }; + evas_object_event_callback_add( + elm_win_, EVAS_CALLBACK_MOUSE_MOVE, + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_MOVE], this); + + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_WHEEL] = [](void* data, Evas* evas, + Evas_Object* object, + void* event_info) { + auto* self = reinterpret_cast(data); + if (self->view_) { + if (self->elm_win_ == object) { + auto* wheel_event = + reinterpret_cast(event_info); + double delta_x = 0.0; + double delta_y = 0.0; + + if (wheel_event->direction == kScrollDirectionVertical) { + delta_y += wheel_event->z; + } else if (wheel_event->direction == kScrollDirectionHorizontal) { + delta_x += wheel_event->z; + } + + self->view_->OnScroll(wheel_event->x, wheel_event->y, delta_x, delta_y, + kScrollOffsetMultiplier, wheel_event->timestamp, + kFlutterPointerDeviceKindTouch, 0); + } + } + }; + evas_object_event_callback_add( + elm_win_, EVAS_CALLBACK_MOUSE_WHEEL, + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_WHEEL], this); + + // FIXME: ues EVAS_CALLBACK_KEY_DOWN, EVAS_CALLBACK_KEY_UP + ecore_event_key_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_KEY_DOWN, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* key_event = reinterpret_cast(event); + if (key_event->window == self->GetWindowId()) { + self->view_->OnKey(key_event, false); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); + + ecore_event_key_handlers_.push_back(ecore_event_handler_add( + ECORE_EVENT_KEY_UP, + [](void* data, int type, void* event) -> Eina_Bool { + auto* self = reinterpret_cast(data); + if (self->view_) { + auto* key_event = reinterpret_cast(event); + if (key_event->window == self->GetWindowId()) { + self->view_->OnKey(key_event, true); + return ECORE_CALLBACK_DONE; + } + } + return ECORE_CALLBACK_PASS_ON; + }, + this)); +} + +void TizenWindowElementary::UnregisterEventHandlers() { + evas_object_smart_callback_del(elm_win_, "rotation,changed", + rotatoin_changed_callback_); + + evas_object_event_callback_del( + elm_win_, EVAS_CALLBACK_MOUSE_DOWN, + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_DOWN]); + evas_object_event_callback_del( + elm_win_, EVAS_CALLBACK_MOUSE_UP, + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_UP]); + evas_object_event_callback_del( + elm_win_, EVAS_CALLBACK_MOUSE_MOVE, + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_MOVE]); + evas_object_event_callback_del( + elm_win_, EVAS_CALLBACK_MOUSE_WHEEL, + evas_object_callbacks_[EVAS_CALLBACK_MOUSE_WHEEL]); + + for (Ecore_Event_Handler* handler : ecore_event_key_handlers_) { + ecore_event_handler_del(handler); + } + ecore_event_key_handlers_.clear(); +} + +TizenWindow::Geometry TizenWindowElementary::GetWindowGeometry() { + // FIXME : evas_object_geometry_get() and ecore_wl2_window_geometry_get() are + // not equivalent. + Geometry result; + evas_object_geometry_get(elm_win_, &result.left, &result.top, &result.width, + &result.height); + return result; +} + +void TizenWindowElementary::SetWindowGeometry(Geometry geometry) { + evas_object_resize(elm_win_, geometry.width, geometry.height); + evas_object_move(elm_win_, geometry.left, geometry.top); + + evas_object_resize(image_, geometry.width, geometry.height); + evas_object_move(image_, geometry.left, geometry.top); +} + +TizenWindow::Geometry TizenWindowElementary::GetScreenGeometry() { + Geometry result; + Ecore_Evas* ecore_evas = + ecore_evas_ecore_evas_get(evas_object_evas_get(elm_win_)); + ecore_evas_screen_geometry_get(ecore_evas, nullptr, nullptr, &result.width, + &result.height); + return result; +} + +int32_t TizenWindowElementary::GetRotation() { + return elm_win_rotation_get(elm_win_); +} + +int32_t TizenWindowElementary::GetDpi() { + Ecore_Evas* ecore_evas = + ecore_evas_ecore_evas_get(evas_object_evas_get(elm_win_)); + int32_t xdpi, ydpi; + ecore_evas_screen_dpi_get(ecore_evas, &xdpi, &ydpi); + return xdpi; +} + +uintptr_t TizenWindowElementary::GetWindowId() { + return ecore_evas_window_get( + ecore_evas_ecore_evas_get(evas_object_evas_get(elm_win_))); +} + +void TizenWindowElementary::ResizeRenderTargetWithRotation(Geometry geometry, + int32_t angle) { + TizenRendererEvasGL* renderer_evas_gl = + reinterpret_cast(view_->engine()->renderer()); + renderer_evas_gl->ResizeSurface(geometry.width, geometry.height); +} + +void TizenWindowElementary::SetPreferredOrientations( + const std::vector& rotations) { + elm_win_wm_rotation_available_rotations_set( + elm_win_, reinterpret_cast(rotations.data()), + rotations.size()); +} + +void TizenWindowElementary::BindKeys(const std::vector& keys) { + for (const std::string& key : keys) { + eext_win_keygrab_set(elm_win_, key.c_str()); + } +} + +void TizenWindowElementary::Show() { + evas_object_show(image_); + evas_object_show(elm_win_); +} + +void TizenWindowElementary::OnGeometryChanged(Geometry geometry) { + SetWindowGeometry(geometry); + view_->OnResize(geometry.left, geometry.top, geometry.width, geometry.height); +} + +} // namespace flutter diff --git a/shell/platform/tizen/tizen_window_elementary.h b/shell/platform/tizen/tizen_window_elementary.h new file mode 100644 index 0000000000000..930cdc5c2f0ec --- /dev/null +++ b/shell/platform/tizen/tizen_window_elementary.h @@ -0,0 +1,79 @@ +// Copyright 2022 Samsung Electronics Co., Ltd. All rights reserved. +// 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 EMBEDDER_TIZEN_WINDOW_ELEMENTARY_H_ +#define EMBEDDER_TIZEN_WINDOW_ELEMENTARY_H_ + +#include "flutter/shell/platform/tizen/tizen_window.h" + +#define EFL_BETA_API_SUPPORT +#include +#include + +#include + +namespace flutter { + +class TizenWindowElementary : public TizenWindow { + public: + TizenWindowElementary(Geometry geometry, + bool transparent, + bool focusable, + bool top_level); + + ~TizenWindowElementary(); + + Geometry GetWindowGeometry() override; + + void SetWindowGeometry(Geometry geometry) override; + + Geometry GetScreenGeometry() override; + + void* GetRenderTarget() override { return elm_win_; } + + void* GetRenderTargetDisplay() override { return image_; } + + int32_t GetRotation() override; + + int32_t GetDpi() override; + + uintptr_t GetWindowId() override; + + void* GetWindowHandle() override { return elm_win_; } + + void ResizeRenderTargetWithRotation(Geometry geometry, + int32_t angle) override; + + void SetPreferredOrientations(const std::vector& rotations) override; + + void BindKeys(const std::vector& keys) override; + + void Show() override; + + void OnGeometryChanged(Geometry geometry) override; + + private: + bool CreateWindow(); + + void DestroyWindow(); + + void SetWindowOptions(); + + void RegisterEventHandlers(); + + void UnregisterEventHandlers(); + + Evas_Object* elm_win_ = nullptr; + Evas_Object* image_ = nullptr; + + Evas_Smart_Cb rotatoin_changed_callback_; + std::unordered_map + evas_object_callbacks_; + std::vector ecore_event_key_handlers_; +}; + +} // namespace flutter + +#endif // EMBEDDER_TIZEN_WINDOW_ELEMENTARY_H_ diff --git a/shell/platform/tizen/touch_event_handler.cc b/shell/platform/tizen/touch_event_handler.cc deleted file mode 100644 index 12e29d5f843fb..0000000000000 --- a/shell/platform/tizen/touch_event_handler.cc +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "touch_event_handler.h" - -#include "flutter/shell/platform/tizen/flutter_tizen_engine.h" - -static const int kScrollDirectionVertical = 0; -static const int kScrollDirectionHorizontal = 1; - -namespace flutter { - -TouchEventHandler::TouchEventHandler(FlutterTizenEngine* engine) - : engine_(engine) { - if (!engine->renderer() || !engine->renderer()->IsValid()) { - return; - } - touch_event_handlers_.push_back( - ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, OnTouch, this)); - touch_event_handlers_.push_back( - ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, OnTouch, this)); - touch_event_handlers_.push_back( - ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL, OnTouch, this)); - touch_event_handlers_.push_back( - ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, OnTouch, this)); -} - -TouchEventHandler::~TouchEventHandler() { - for (Ecore_Event_Handler* handler : touch_event_handlers_) { - ecore_event_handler_del(handler); - } - touch_event_handlers_.clear(); -} - -void TouchEventHandler::SendFlutterPointerEvent(FlutterPointerPhase phase, - double x, - double y, - double scroll_delta_x, - double scroll_delta_y, - size_t timestamp, - int device_id = 0) { - // Correct errors caused by window rotation. - TizenRenderer::Geometry geometry = engine_->renderer()->GetWindowGeometry(); - double new_x = x, new_y = y; - - if (rotation == 90) { - new_x = geometry.h - y; - new_y = x; - } else if (rotation == 180) { - new_x = geometry.w - x; - new_y = geometry.h - y; - } else if (rotation == 270) { - new_x = y; - new_y = geometry.w - x; - } - - FlutterPointerEvent event = {}; - event.struct_size = sizeof(event); - event.phase = phase; - event.x = new_x; - event.y = new_y; - if (scroll_delta_x != 0 || scroll_delta_y != 0) { - event.signal_kind = kFlutterPointerSignalKindScroll; - } - event.scroll_delta_x = scroll_delta_x * 2; - event.scroll_delta_y = scroll_delta_y * 2; - event.timestamp = timestamp * 1000; - event.device = device_id; - event.device_kind = kFlutterPointerDeviceKindTouch; - - engine_->SendPointerEvent(event); -} - -Eina_Bool TouchEventHandler::OnTouch(void* data, int type, void* event) { - auto* self = reinterpret_cast(data); - uintptr_t window_id = self->engine_->renderer()->GetWindowId(); - - if (type == ECORE_EVENT_MOUSE_BUTTON_DOWN) { - auto* button_event = reinterpret_cast(event); - if (window_id == button_event->window) { - self->pointer_state_ = true; - self->SendFlutterPointerEvent(kDown, button_event->x, button_event->y, 0, - 0, button_event->timestamp, - button_event->multi.device); - return ECORE_CALLBACK_DONE; - } - - } else if (type == ECORE_EVENT_MOUSE_BUTTON_UP) { - auto* button_event = reinterpret_cast(event); - if (window_id == button_event->window) { - self->pointer_state_ = false; - self->SendFlutterPointerEvent(kUp, button_event->x, button_event->y, 0, 0, - button_event->timestamp, - button_event->multi.device); - return ECORE_CALLBACK_DONE; - } - } else if (type == ECORE_EVENT_MOUSE_MOVE) { - auto* move_event = reinterpret_cast(event); - if (window_id == move_event->window) { - if (self->pointer_state_) { - self->SendFlutterPointerEvent(kMove, move_event->x, move_event->y, 0, 0, - move_event->timestamp, - move_event->multi.device); - return ECORE_CALLBACK_DONE; - } - } - } else if (type == ECORE_EVENT_MOUSE_WHEEL) { - auto* wheel_event = reinterpret_cast(event); - if (window_id == wheel_event->window) { - double scroll_delta_x = 0.0, scroll_delta_y = 0.0; - if (wheel_event->direction == kScrollDirectionVertical) { - scroll_delta_y += wheel_event->z; - } else if (wheel_event->direction == kScrollDirectionHorizontal) { - scroll_delta_x += wheel_event->z; - } - const int kScrollOffsetMultiplier = 20; - scroll_delta_x *= kScrollOffsetMultiplier; - scroll_delta_y *= kScrollOffsetMultiplier; - self->SendFlutterPointerEvent( - self->pointer_state_ ? kMove : kHover, wheel_event->x, wheel_event->y, - scroll_delta_x, scroll_delta_y, wheel_event->timestamp); - return ECORE_CALLBACK_DONE; - } - } - return ECORE_CALLBACK_PASS_ON; -} - -} // namespace flutter diff --git a/shell/platform/tizen/touch_event_handler.h b/shell/platform/tizen/touch_event_handler.h deleted file mode 100644 index e5f764af86e9a..0000000000000 --- a/shell/platform/tizen/touch_event_handler.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef EMBEDDER_TOUCH_EVENT_HANDLER_H_ -#define EMBEDDER_TOUCH_EVENT_HANDLER_H_ - -#include - -#include - -#include "flutter/shell/platform/embedder/embedder.h" - -namespace flutter { - -class FlutterTizenEngine; - -class TouchEventHandler { - public: - explicit TouchEventHandler(FlutterTizenEngine* engine); - virtual ~TouchEventHandler(); - - int32_t rotation = 0; - - private: - FlutterTizenEngine* engine_; - std::vector touch_event_handlers_; - bool pointer_state_ = false; - - void SendFlutterPointerEvent(FlutterPointerPhase phase, - double x, - double y, - double scroll_delta_x, - double scroll_delta_y, - size_t timestamp, - int device_id); - - static Eina_Bool OnTouch(void* data, int type, void* event); -}; - -} // namespace flutter - -#endif // EMBEDDER_TOUCH_EVENT_HANDLER_H_