From e75d0ecfd0c65bd2c13caf06ece6fe6828e9383e Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Wed, 31 Aug 2022 15:03:31 +0900 Subject: [PATCH] Introduce TizenViewNui (#328) This is a View Class that supports NUI UIFW that inherits TizenView. NUI is a UIFW based on the C# language that wrapping Dali UIFW. The mouse and the keyboard event callback handling for NUI is handled in embedding(C#). The embedder handles events related to event delivery and rendering. Basically draw a flutter on a NativeImageQueue created from embedding. This corresponds to tbm_surface_queue_h and is rendered flutter view using egl. (When taking tbm_surface_queue_h from NativeImageQueue, typeid() is used inside dali, so -rtti flag is absolutely necessary.) Co-authored-by: Swift Kim --- shell/platform/common/BUILD.gn | 2 + shell/platform/tizen/BUILD.gn | 83 +++++++++++----- shell/platform/tizen/flutter_tizen.cc | 33 +++++++ shell/platform/tizen/flutter_tizen_nui.cc | 58 +++++++++++ shell/platform/tizen/flutter_tizen_view.cc | 13 ++- shell/platform/tizen/public/flutter_tizen.h | 35 ++++++- shell/platform/tizen/tizen_renderer_egl.cc | 39 ++++++-- shell/platform/tizen/tizen_view_elementary.cc | 4 +- shell/platform/tizen/tizen_view_elementary.h | 1 - shell/platform/tizen/tizen_view_nui.cc | 98 +++++++++++++++++++ shell/platform/tizen/tizen_view_nui.h | 62 ++++++++++++ third_party/accessibility/ax/BUILD.gn | 2 + 12 files changed, 395 insertions(+), 35 deletions(-) create mode 100644 shell/platform/tizen/flutter_tizen_nui.cc create mode 100644 shell/platform/tizen/tizen_view_nui.cc create mode 100644 shell/platform/tizen/tizen_view_nui.h diff --git a/shell/platform/common/BUILD.gn b/shell/platform/common/BUILD.gn index 202e1c4b8fdb6..7e61d2ff387c6 100644 --- a/shell/platform/common/BUILD.gn +++ b/shell/platform/common/BUILD.gn @@ -91,6 +91,8 @@ source_set("common_cpp_accessibility") { public_configs = [ "//flutter/third_party/accessibility:accessibility_config" ] + configs -= [ "//build/config/compiler:no_rtti" ] + public_deps = [ "//flutter/fml:fml", "//flutter/shell/platform/embedder:embedder_headers", diff --git a/shell/platform/tizen/BUILD.gn b/shell/platform/tizen/BUILD.gn index 800800582e2ec..456ab84007dc6 100644 --- a/shell/platform/tizen/BUILD.gn +++ b/shell/platform/tizen/BUILD.gn @@ -42,6 +42,9 @@ config("rootstrap_include_dirs") { "$custom_sysroot/usr/include", "$custom_sysroot/usr/include/appfw", "$custom_sysroot/usr/include/base", + "$custom_sysroot/usr/include/dali", + "$custom_sysroot/usr/include/dali-adaptor", + "$custom_sysroot/usr/include/dali-toolkit", "$custom_sysroot/usr/include/dlog", "$custom_sysroot/usr/include/ecore-1", "$custom_sysroot/usr/include/ecore-imf-1", @@ -94,9 +97,14 @@ template("embedder") { forward_variables_from(invoker, [ "target_type", + "enable_nui_support", "defines", ]) + if (!defined(enable_nui_support)) { + enable_nui_support = false + } + target(target_type, target_name) { public = _public_headers @@ -133,13 +141,6 @@ template("embedder") { "tizen_window_elementary.cc", ] - if (target_name != "flutter_tizen_wearable") { - sources += [ - "accessibility_bridge_delegate_tizen.cc", - "flutter_platform_node_delegate_tizen.cc", - ] - } - libs = [ "base-utils-i18n", "capi-appfw-application", @@ -164,6 +165,26 @@ template("embedder") { "wayland-client", ] + if (target_name != "flutter_tizen_wearable") { + sources += [ + "accessibility_bridge_delegate_tizen.cc", + "external_texture_pixel_egl.cc", + "external_texture_surface_egl.cc", + "flutter_platform_node_delegate_tizen.cc", + "tizen_renderer_egl.cc", + "tizen_vsync_waiter.cc", + "tizen_window_ecore_wl2.cc", + ] + + libs += [ + "ecore_wl2", + "tdm-client", + "tizen-extension-client", + "EGL", + "GLESv2", + ] + } + if (target_name == "flutter_tizen_common") { sources += [ "channels/tizen_shell.cc" ] @@ -179,30 +200,28 @@ template("embedder") { configs += [ "//flutter/shell/platform/common:desktop_library_implementation" ] - public_configs = [ - ":relative_client_wrapper_headers", - ":rootstrap_include_dirs", - "//flutter:config", - ] - - if (target_name != "flutter_tizen_wearable") { + if (enable_nui_support) { sources += [ - "external_texture_pixel_egl.cc", - "external_texture_surface_egl.cc", - "tizen_renderer_egl.cc", - "tizen_vsync_waiter.cc", - "tizen_window_ecore_wl2.cc", + "flutter_tizen_nui.cc", + "tizen_view_nui.cc", ] libs += [ - "ecore_wl2", - "tdm-client", - "tizen-extension-client", - "EGL", - "GLESv2", + "dali2-adaptor", + "dali2-core", ] + + defines += [ "NUI_SUPPORT" ] + + configs -= [ "//build/config/compiler:no_rtti" ] } + public_configs = [ + ":relative_client_wrapper_headers", + ":rootstrap_include_dirs", + "//flutter:config", + ] + public_deps = [ ":flutter_engine" ] deps = [ @@ -226,6 +245,13 @@ embedder("flutter_tizen_mobile") { defines = [ "MOBILE_PROFILE" ] } +embedder("flutter_tizen_mobile_nui") { + target_type = "shared_library" + enable_nui_support = true + + defines = [ "MOBILE_PROFILE" ] +} + embedder("flutter_tizen_wearable") { target_type = "shared_library" @@ -238,6 +264,13 @@ embedder("flutter_tizen_tv") { defines = [ "TV_PROFILE" ] } +embedder("flutter_tizen_tv_nui") { + target_type = "shared_library" + enable_nui_support = true + + defines = [ "TV_PROFILE" ] +} + embedder("flutter_tizen_common") { target_type = "shared_library" @@ -316,7 +349,9 @@ group("tizen") { deps += [ ":flutter_tizen_common", ":flutter_tizen_mobile", + ":flutter_tizen_mobile_nui", ":flutter_tizen_tv", + ":flutter_tizen_tv_nui", ":flutter_tizen_wearable", ] } diff --git a/shell/platform/tizen/flutter_tizen.cc b/shell/platform/tizen/flutter_tizen.cc index af6266c456b1b..6907e68f8d06b 100644 --- a/shell/platform/tizen/flutter_tizen.cc +++ b/shell/platform/tizen/flutter_tizen.cc @@ -241,6 +241,39 @@ void FlutterDesktopViewResize(FlutterDesktopViewRef view, ViewFromHandle(view)->Resize(width, height); } +void FlutterDesktopViewOnPointerEvent(FlutterDesktopViewRef view, + FlutterDesktopPointerEventType type, + double x, + double y, + size_t timestamp, + int32_t device_id) { + switch (type) { + case FlutterDesktopPointerEventType::kMouseDown: + default: + ViewFromHandle(view)->OnPointerDown( + x, y, timestamp, kFlutterPointerDeviceKindTouch, device_id); + break; + case FlutterDesktopPointerEventType::kMouseUp: + ViewFromHandle(view)->OnPointerUp( + x, y, timestamp, kFlutterPointerDeviceKindTouch, device_id); + break; + case FlutterDesktopPointerEventType::kMouseMove: + ViewFromHandle(view)->OnPointerMove( + x, y, timestamp, kFlutterPointerDeviceKindTouch, device_id); + break; + } +} + +void FlutterDesktopViewOnKeyEvent(FlutterDesktopViewRef view, + const char* key, + const char* string, + uint32_t modifiers, + uint32_t scan_code, + bool is_down) { + ViewFromHandle(view)->OnKey(key, string, nullptr, modifiers, scan_code, + is_down); +} + void FlutterDesktopRegisterViewFactory( FlutterDesktopPluginRegistrarRef registrar, const char* view_type, diff --git a/shell/platform/tizen/flutter_tizen_nui.cc b/shell/platform/tizen/flutter_tizen_nui.cc new file mode 100644 index 0000000000000..f9ad52e11bf96 --- /dev/null +++ b/shell/platform/tizen/flutter_tizen_nui.cc @@ -0,0 +1,58 @@ +// 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 +#include + +#include + +#include "flutter/shell/platform/tizen/flutter_tizen_engine.h" +#include "flutter/shell/platform/tizen/flutter_tizen_view.h" +#include "flutter/shell/platform/tizen/tizen_view_nui.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 FlutterDesktopViewCreateFromImageView( + const FlutterDesktopViewProperties& view_properties, + FlutterDesktopEngineRef engine, + void* image_view, + void* native_image_queue, + int32_t default_window_id) { + std::unique_ptr tizen_view = + std::make_unique( + view_properties.width, view_properties.height, + reinterpret_cast(image_view), + reinterpret_cast(native_image_queue), + default_window_id); + + auto view = + std::make_unique(std::move(tizen_view)); + + // Take ownership of the engine, starting it if necessary. + view->SetEngine( + std::unique_ptr(EngineFromHandle(engine))); + view->CreateRenderSurface(FlutterDesktopRendererType::kEGL); + if (!view->engine()->IsRunning()) { + if (!view->engine()->RunEngine()) { + return nullptr; + } + } + + view->SendInitialGeometry(); + + return HandleForView(view.release()); +} diff --git a/shell/platform/tizen/flutter_tizen_view.cc b/shell/platform/tizen/flutter_tizen_view.cc index a552f35b89567..087e3dc60e3ce 100644 --- a/shell/platform/tizen/flutter_tizen_view.cc +++ b/shell/platform/tizen/flutter_tizen_view.cc @@ -7,6 +7,9 @@ #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_view.h" +#ifdef NUI_SUPPORT +#include "flutter/shell/platform/tizen/tizen_view_nui.h" +#endif #include "flutter/shell/platform/tizen/tizen_window.h" namespace { @@ -131,7 +134,15 @@ bool FlutterTizenView::OnMakeResourceCurrent() { } bool FlutterTizenView::OnPresent() { - return engine_->renderer()->OnPresent(); + bool result = engine_->renderer()->OnPresent(); +#ifdef NUI_SUPPORT + if (tizen_view_->GetType() == flutter::TizenViewType::kView && + engine_->renderer()->type() == FlutterDesktopRendererType::kEGL) { + auto* view = reinterpret_cast(tizen_view_.get()); + view->RequestRendering(); + } +#endif + return result; } uint32_t FlutterTizenView::OnGetFBO() { diff --git a/shell/platform/tizen/public/flutter_tizen.h b/shell/platform/tizen/public/flutter_tizen.h index 53ae6d3faa714..2597014b2b8c8 100644 --- a/shell/platform/tizen/public/flutter_tizen.h +++ b/shell/platform/tizen/public/flutter_tizen.h @@ -32,6 +32,12 @@ typedef enum { kEGL, } FlutterDesktopRendererType; +typedef enum { + kMouseDown, + kMouseUp, + kMouseMove, +} FlutterDesktopPointerEventType; + // Properties for configuring the initial settings of a Flutter window. typedef struct { // The x-coordinate of the top left corner of the window. @@ -154,13 +160,25 @@ FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopViewCreateFromNewWindow( // Creates a view that hosts and displays the given engine instance. // -// The type of parent should be Evas_Object*, Cast Evas_Object* to void*. +// The type of |parent| must be Evas_Object*. // @warning This API is a work-in-progress and may change. FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopViewCreateFromElmParent( const FlutterDesktopViewProperties& view_properties, FlutterDesktopEngineRef engine, void* parent); +// Creates a view that hosts and displays the given engine instance. +// +// The type of |image_view| must be Dali::Toolkit::ImageView*. +// The type of |native_image_queue| must be Dali::NativeImageSourceQueue*. +// @warning This API is a work-in-progress and may change. +FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopViewCreateFromImageView( + const FlutterDesktopViewProperties& view_properties, + FlutterDesktopEngineRef engine, + void* image_view, + void* native_image_queue, + int32_t default_window_id); + // Destroys the view. // // The engine owned by the view will also be shut down implicitly. @@ -183,6 +201,21 @@ FLUTTER_EXPORT void FlutterDesktopViewResize(FlutterDesktopViewRef view, int32_t width, int32_t height); +FLUTTER_EXPORT void FlutterDesktopViewOnPointerEvent( + FlutterDesktopViewRef view, + FlutterDesktopPointerEventType type, + double x, + double y, + size_t timestamp, + int32_t device_id); + +FLUTTER_EXPORT void FlutterDesktopViewOnKeyEvent(FlutterDesktopViewRef view, + const char* key, + const char* string, + uint32_t modifiers, + uint32_t scan_code, + bool is_down); + // ========== Plugin Registrar (extensions) ========== // Returns the view associated with this registrar's engine instance. diff --git a/shell/platform/tizen/tizen_renderer_egl.cc b/shell/platform/tizen/tizen_renderer_egl.cc index 4054787c7b5e3..f090da5020d9a 100644 --- a/shell/platform/tizen/tizen_renderer_egl.cc +++ b/shell/platform/tizen/tizen_renderer_egl.cc @@ -8,6 +8,12 @@ #include #include #include +#ifdef NUI_SUPPORT +#include +#endif +#include +#include +#include #include "flutter/shell/platform/tizen/logger.h" @@ -25,7 +31,12 @@ 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 (render_target_display) { + egl_display_ = + eglGetDisplay(static_cast(render_target_display)); + } else { + egl_display_ = eglGetDisplay(tbm_dummy_display_create()); + } if (egl_display_ == EGL_NO_DISPLAY) { PrintEGLError(); @@ -63,11 +74,27 @@ bool TizenRendererEgl::CreateSurface(void* render_target, { 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 (render_target_display) { + 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); + } else { +#ifdef NUI_SUPPORT + Dali::NativeImageSourceQueuePtr dali_native_image_queue = + static_cast(render_target); + tbm_surface_queue_h tbm_surface_queue_ = + static_cast*>( + dali_native_image_queue->GetNativeImageSourceQueue().mContainer) + ->GetValue(); + auto* egl_window = + reinterpret_cast(tbm_surface_queue_); + egl_surface_ = eglCreateWindowSurface(egl_display_, egl_config_, + egl_window, attribs); +#endif + } + if (egl_surface_ == EGL_NO_SURFACE) { FT_LOG(Error) << "Could not create an onscreen window surface."; return false; diff --git a/shell/platform/tizen/tizen_view_elementary.cc b/shell/platform/tizen/tizen_view_elementary.cc index 82aa00e43d196..e4ecd0bf266e8 100644 --- a/shell/platform/tizen/tizen_view_elementary.cc +++ b/shell/platform/tizen/tizen_view_elementary.cc @@ -4,8 +4,8 @@ #include "tizen_view_elementary.h" -#include -#include +#include +#include #include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" diff --git a/shell/platform/tizen/tizen_view_elementary.h b/shell/platform/tizen/tizen_view_elementary.h index 5304d9b8c5dd4..94e596c723b35 100644 --- a/shell/platform/tizen/tizen_view_elementary.h +++ b/shell/platform/tizen/tizen_view_elementary.h @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/shell/platform/tizen/tizen_view_nui.cc b/shell/platform/tizen/tizen_view_nui.cc new file mode 100644 index 0000000000000..2cb180738ec77 --- /dev/null +++ b/shell/platform/tizen/tizen_view_nui.cc @@ -0,0 +1,98 @@ +// 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 "flutter/shell/platform/tizen/tizen_view_nui.h" + +#include + +#include + +#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_view_event_handler_delegate.h" + +namespace flutter { + +TizenViewNui::TizenViewNui(int32_t width, + int32_t height, + Dali::Toolkit::ImageView* image_view, + Dali::NativeImageSourceQueuePtr native_image_queue, + int32_t default_window_id) + : TizenView(width, height), + image_view_(image_view), + native_image_queue_(native_image_queue), + default_window_id_(default_window_id) { + RegisterEventHandlers(); + PrepareInputMethod(); + Show(); +} + +TizenViewNui::~TizenViewNui() { + UnregisterEventHandlers(); +} + +void TizenViewNui::RegisterEventHandlers() { + rendering_callback_ = std::make_unique( + Dali::MakeCallback(this, &TizenViewNui::RenderOnce)); +} + +void TizenViewNui::UnregisterEventHandlers() { + rendering_callback_.release(); +} + +TizenGeometry TizenViewNui::GetGeometry() { + Dali::Vector2 size = image_view_->GetProperty(Dali::Actor::Property::SIZE) + .Get(); + TizenGeometry result = {0, 0, static_cast(size.width), + static_cast(size.height)}; + return result; +} + +bool TizenViewNui::SetGeometry(TizenGeometry geometry) { + view_delegate_->OnResize(0, 0, geometry.width, geometry.height); + + image_view_->SetProperty(Dali::Actor::Property::SIZE, + Dali::Vector2(geometry.width, geometry.height)); + + native_image_queue_->SetSize(geometry.width, geometry.height); + return true; +} + +int32_t TizenViewNui::GetDpi() { + return Dali::Stage::GetCurrent().GetDpi().width; +} + +uintptr_t TizenViewNui::GetWindowId() { + return default_window_id_; +} + +void TizenViewNui::Show() { + // Do nothing. +} + +void TizenViewNui::RequestRendering() { + rendering_callback_->Trigger(); +} + +void TizenViewNui::PrepareInputMethod() { + input_method_context_ = + std::make_unique(GetWindowId()); + + // Set input method callbacks. + input_method_context_->SetOnPreeditStart( + [this]() { view_delegate_->OnComposeBegin(); }); + input_method_context_->SetOnPreeditChanged( + [this](std::string str, int cursor_pos) { + view_delegate_->OnComposeChange(str, cursor_pos); + }); + input_method_context_->SetOnPreeditEnd( + [this]() { view_delegate_->OnComposeEnd(); }); + input_method_context_->SetOnCommit( + [this](std::string str) { view_delegate_->OnCommit(str); }); +} + +void TizenViewNui::RenderOnce() { + Dali::Stage::GetCurrent().KeepRendering(0.0f); +} + +} // namespace flutter diff --git a/shell/platform/tizen/tizen_view_nui.h b/shell/platform/tizen/tizen_view_nui.h new file mode 100644 index 0000000000000..83d39e65e0f78 --- /dev/null +++ b/shell/platform/tizen/tizen_view_nui.h @@ -0,0 +1,62 @@ +// 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. + +#ifndef EMBEDDER_TIZEN_VIEW_NUI_H_ +#define EMBEDDER_TIZEN_VIEW_NUI_H_ + +#include +#include +#include +#include + +#include + +#include "flutter/shell/platform/tizen/tizen_view.h" + +namespace flutter { + +class TizenViewNui : public TizenView { + public: + TizenViewNui(int32_t width, + int32_t height, + Dali::Toolkit::ImageView* image_view, + Dali::NativeImageSourceQueuePtr native_image_queue, + int32_t default_window_id); + + ~TizenViewNui(); + + TizenGeometry GetGeometry() override; + + bool SetGeometry(TizenGeometry geometry) override; + + void* GetRenderTarget() override { return native_image_queue_.Get(); } + + void* GetNativeHandle() override { return image_view_; } + + int32_t GetDpi() override; + + uintptr_t GetWindowId() override; + + void Show() override; + + void RequestRendering(); + + private: + void RegisterEventHandlers(); + + void UnregisterEventHandlers(); + + void PrepareInputMethod(); + + void RenderOnce(); + + Dali::Toolkit::ImageView* image_view_ = nullptr; + Dali::NativeImageSourceQueuePtr native_image_queue_; + int32_t default_window_id_; + std::unique_ptr rendering_callback_; +}; + +} // namespace flutter + +#endif // EMBEDDER_TIZEN_VIEW_NUI_H_ diff --git a/third_party/accessibility/ax/BUILD.gn b/third_party/accessibility/ax/BUILD.gn index 742dffd03c06f..5e78bec7c8de6 100644 --- a/third_party/accessibility/ax/BUILD.gn +++ b/third_party/accessibility/ax/BUILD.gn @@ -9,6 +9,8 @@ source_set("ax") { public_configs = [ "//flutter/third_party/accessibility:accessibility_config" ] + configs -= [ "//build/config/compiler:no_rtti" ] + sources = [ "platform/ax_platform_node.cc", "platform/ax_platform_node.h",