From 5a8d59082156e8ea01f817113f03e2a837feb20c Mon Sep 17 00:00:00 2001 From: Swift Kim Date: Mon, 15 Feb 2021 13:59:11 +0900 Subject: [PATCH] [Tizen] Cherrypicks from flutter-1.22-candidate.12-tizen * Fix memory corruption issue (#2) * Exit application method is replaced by 'ui_app_exit' (#3) * Fix launch failure in sleep mode (#4) * Fix scorll issue (#6) * Changed EGL settings to support more Tizen devices (#5) * Add touch events of platform view channel for tizen (#8) * Resize egl window when software keyboard is shown (#7) * Fix texture being not released issue (#9) * Remove tizen_tools dependency and update BUILD.gn (#11) * Refactor tizen surface (#10) * Fix a crash in stop phase of Tizen engine (#12) * Fix a crash during app shutdown (#13) * Fix a crash when TizenVsyncWaiter is destroyed. (#15) * Implement key events for tizen webview (#14) * Change method name starting with lower case (#16) * Remove not used code (#18) * Introduce assertion macros (#17) * Minor update to Misc (#19) * Add azure-pipelines.yml (#20) * Clean-up channel view resource upon exiting app (#22) * Call a method to set imf_context in platform view channel (#24) * Support Tizen 4.0 (#23) * Fix a focused platform view bug (#27) * Support screen rotations for Tizen 4.0 and Tizen 6.0 (#28) * Separate the embedder from the engine (#29) * Add profile build to the CI script (#30) * Share egl context to egl resource context (#31) * Implement message queue to handle vblank request (#32) * Fix a platform view bug (#33) * Convert timestamp to correct unit (#35) * Send locales to flutter including default locale (#38) * Enable FontConfig to improve font fallbacks (#40) Co-authored-by: Xiaowei Guan Co-authored-by: MuHong Byun Co-authored-by: Boram Bae Co-authored-by: Seungsoo Lee Co-authored-by: Hakkyu Kim <43136596+HakkyuKim@users.noreply.github.com> --- azure-pipelines.yml | 135 +++++ shell/platform/BUILD.gn | 4 + shell/platform/common/BUILD.gn | 2 +- shell/platform/tizen/BUILD.gn | 88 ++-- .../tizen/channels/key_event_channel.cc | 4 +- .../tizen/channels/lifecycle_channel.cc | 10 +- .../tizen/channels/localization_channel.cc | 64 ++- .../tizen/channels/platform_channel.cc | 8 +- .../tizen/channels/platform_view_channel.cc | 175 +++++-- .../tizen/channels/platform_view_channel.h | 14 +- .../tizen/channels/text_input_channel.cc | 268 ++++++---- .../tizen/channels/text_input_channel.h | 48 +- shell/platform/tizen/config.gni | 1 + shell/platform/tizen/external_texture_gl.cc | 37 +- shell/platform/tizen/external_texture_gl.h | 6 +- shell/platform/tizen/flutter_tizen.cc | 35 +- shell/platform/tizen/key_event_handler.cc | 6 +- shell/platform/tizen/logger.h | 29 -- .../tizen/public/flutter_platform_view.h | 43 +- shell/platform/tizen/tizen_embedder_engine.cc | 127 +++-- shell/platform/tizen/tizen_embedder_engine.h | 20 +- shell/platform/tizen/tizen_log.h | 65 +++ shell/platform/tizen/tizen_renderer.cc | 460 ++++++++++++++++++ shell/platform/tizen/tizen_renderer.h | 66 +++ .../platform/tizen/tizen_renderer_ecore_wl.cc | 132 +++++ .../platform/tizen/tizen_renderer_ecore_wl.h | 43 ++ .../tizen/tizen_renderer_ecore_wl2.cc | 129 +++++ .../platform/tizen/tizen_renderer_ecore_wl2.h | 42 ++ shell/platform/tizen/tizen_surface.cc | 14 - shell/platform/tizen/tizen_surface.h | 31 -- shell/platform/tizen/tizen_surface_gl.cc | 247 ---------- shell/platform/tizen/tizen_surface_gl.h | 49 -- shell/platform/tizen/tizen_vsync_waiter.cc | 196 ++++---- shell/platform/tizen/tizen_vsync_waiter.h | 35 +- shell/platform/tizen/touch_event_handler.cc | 50 +- shell/platform/tizen/touch_event_handler.h | 4 +- tools/gn | 2 + 37 files changed, 1851 insertions(+), 838 deletions(-) create mode 100644 azure-pipelines.yml delete mode 100644 shell/platform/tizen/logger.h create mode 100644 shell/platform/tizen/tizen_log.h create mode 100644 shell/platform/tizen/tizen_renderer.cc create mode 100644 shell/platform/tizen/tizen_renderer.h create mode 100644 shell/platform/tizen/tizen_renderer_ecore_wl.cc create mode 100644 shell/platform/tizen/tizen_renderer_ecore_wl.h create mode 100644 shell/platform/tizen/tizen_renderer_ecore_wl2.cc create mode 100644 shell/platform/tizen/tizen_renderer_ecore_wl2.h delete mode 100644 shell/platform/tizen/tizen_surface.cc delete mode 100644 shell/platform/tizen/tizen_surface.h delete mode 100644 shell/platform/tizen/tizen_surface_gl.cc delete mode 100644 shell/platform/tizen/tizen_surface_gl.h diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000000..d6d6140d39414 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,135 @@ +# Azure Pipelines YAML pipeline. +# https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema +name: ninja + +trigger: +- flutter-*-tizen +pr: +- flutter-*-tizen + +jobs: +- job: build + strategy: + matrix: + tizen-arm-release: + arch: arm + mode: release + targetTriple: armv7l-tizen-linux-gnueabi + tizen-arm-profile: + arch: arm + mode: profile + targetTriple: armv7l-tizen-linux-gnueabi + tizen-arm-debug: + arch: arm + mode: debug + targetTriple: armv7l-tizen-linux-gnueabi + tizen-x86-debug: + arch: x86 + mode: debug + targetTriple: i586-tizen-linux-gnueabi + pool: + name: Default + demands: agent.os -equals Linux + timeoutInMinutes: 60 + cancelTimeoutInMinutes: 1 + variables: + - name: buildroot + value: $(Pipeline.Workspace)/src + steps: + - checkout: self + path: src/flutter + - bash: | + git reset --hard HEAD + gclient sync -D + sed -i 's/"-Wno-non-c-typedef-for-linkage",//g' build/config/compiler/BUILD.gn + displayName: Prepare for build + workingDirectory: $(buildroot) + failOnStderr: true + - bash: | + flutter/tools/gn \ + --target-os linux \ + --linux-cpu $(arch) \ + --target-toolchain `pwd`/tizen_tools/toolchains \ + --target-sysroot `pwd`/tizen_tools/sysroot/$(arch) \ + --target-triple $(targetTriple) \ + --runtime-mode $(mode) \ + --enable-fontconfig \ + --embedder-for-target \ + --disable-desktop-embeddings \ + --build-tizen-shell \ + --out-dir output/default + ninja -C output/default/out/linux_$(mode)_$(arch) + displayName: Build + workingDirectory: $(buildroot) + failOnStderr: true + - bash: | + flutter/tools/gn \ + --target-os linux \ + --linux-cpu $(arch) \ + --target-toolchain `pwd`/tizen_tools/toolchains \ + --target-sysroot `pwd`/tizen_tools/sysroot/$(arch)_40 \ + --target-triple $(targetTriple) \ + --runtime-mode $(mode) \ + --enable-fontconfig \ + --embedder-for-target \ + --disable-desktop-embeddings \ + --build-tizen-shell \ + --tizen-sdk-4 \ + --out-dir output/tizen40 + ninja -C output/tizen40/out/linux_$(mode)_$(arch) + displayName: Build for Tizen 4.0 + workingDirectory: $(buildroot) + failOnStderr: true + - bash: | + OUTDIR=$(Build.StagingDirectory) + cp default/out/linux_$(mode)_$(arch)/libflutter_tizen.so $OUTDIR + cp tizen40/out/linux_$(mode)_$(arch)/libflutter_tizen.so $OUTDIR/libflutter_tizen40.so + cp tizen40/out/linux_$(mode)_$(arch)/libflutter_engine.so $OUTDIR + displayName: Copy artifacts + workingDirectory: $(buildroot)/output + failOnStderr: true + - publish: $(Build.StagingDirectory) + artifact: $(System.JobName) +- job: release + dependsOn: build + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + pool: + name: Default + demands: agent.os -equals Linux + workspace: + clean: outputs + variables: + - name: upstreamVersion + value: 2f0af3715217a0c2ada72c717d4ed9178d68f6ed + steps: + - checkout: self + path: src/flutter + - download: current + - bash: | + mkdir -p common/client_wrapper + ROOT=$(Pipeline.Workspace)/src/flutter/shell/platform + cp $ROOT/common/cpp/client_wrapper/*.{h,cc} common/client_wrapper + rm common/client_wrapper/{*_unittests.*,engine_method_result.cc} + cp -r $ROOT/common/cpp/public common + cp -r $ROOT/common/cpp/client_wrapper/include common/client_wrapper + cp $ROOT/tizen/public/*.h common/public + cp $ROOT/tizen/LICENSE . + displayName: Copy headers + workingDirectory: $(Build.BinariesDirectory) + failOnStderr: true + - bash: | + cp $(Pipeline.Workspace)/src/third_party/icu/flutter/icudtl.dat common + mv $(Pipeline.Workspace)/tizen-* . + for platform in linux windows darwin; do + for mode in release profile; do + curl -o tmp.zip https://storage.googleapis.com/flutter_infra/flutter/$(upstreamVersion)/android-arm-$mode/$platform-x64.zip 2> /dev/null + unzip tmp.zip -d tizen-arm-$mode/$platform-x64 && rm tmp.zip + done + zip -r $(Build.StagingDirectory)/$platform-x64.zip * + rm -r tizen-arm-*/$platform-x64 + done + displayName: Create releases + workingDirectory: $(Build.BinariesDirectory) + failOnStderr: true + - publish: $(Build.StagingDirectory) + artifact: release diff --git a/shell/platform/BUILD.gn b/shell/platform/BUILD.gn index 66baf0e887fe1..45519610ae9f9 100644 --- a/shell/platform/BUILD.gn +++ b/shell/platform/BUILD.gn @@ -4,6 +4,7 @@ import("//build/fuchsia/sdk.gni") import("//flutter/shell/platform/config.gni") +import("//flutter/shell/platform/tizen/config.gni") group("platform") { if (is_mac || is_ios) { @@ -15,6 +16,9 @@ group("platform") { if (enable_desktop_embeddings) { deps += [ "linux" ] } + if (build_tizen_shell) { + deps += [ "tizen" ] + } } else if (is_win) { deps = [] if (enable_desktop_embeddings) { diff --git a/shell/platform/common/BUILD.gn b/shell/platform/common/BUILD.gn index 8b3cf4c25a597..5318aedfa81d6 100644 --- a/shell/platform/common/BUILD.gn +++ b/shell/platform/common/BUILD.gn @@ -111,7 +111,7 @@ source_set("common_cpp") { deps = [ ":common_cpp_library_headers", "//flutter/shell/platform/common/client_wrapper:client_wrapper", - "//flutter/shell/platform/embedder:embedder_as_internal_library", + # "//flutter/shell/platform/embedder:embedder_as_internal_library", ] public_deps = [ diff --git a/shell/platform/tizen/BUILD.gn b/shell/platform/tizen/BUILD.gn index b285f11b2260e..a0007768953d6 100644 --- a/shell/platform/tizen/BUILD.gn +++ b/shell/platform/tizen/BUILD.gn @@ -2,21 +2,28 @@ # Copyright 2013 The Flutter Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//flutter/shell/platform/tizen/config.gni") -_public_headers = [ "public/flutter_tizen.h" ] +group("tizen") { + deps = [ ":flutter_tizen_library" ] +} + +shared_library("flutter_tizen_library") { + output_name = "flutter_tizen" + + ldflags = [ "-Wl,-rpath,\$ORIGIN" ] + + deps = [ ":flutter_tizen" ] -# Any files that are built by clients (client_wrapper code, library headers for -# implementations using this shared code, etc.) include the public headers -# assuming they are in the include path. This configuration should be added to -# any such code that is also built by GN to make the includes work. -config("relative_flutter_tizen_headers") { - include_dirs = [ "public" ] + public_configs = [ "//flutter:config" ] } -# The headers are a separate source set since the client wrapper is allowed -# to depend on the public headers, but none of the rest of the code. source_set("flutter_tizen_headers") { - public = _public_headers + public = [ + "public/flutter_platform_view.h", + "public/flutter_texture_registrar.h", + "public/flutter_tizen.h", + ] public_deps = [ "//flutter/shell/platform/common/cpp:common_cpp_library_headers" ] @@ -43,8 +50,7 @@ source_set("flutter_tizen") { "key_event_handler.cc", "tizen_embedder_engine.cc", "tizen_event_loop.cc", - "tizen_surface.cc", - "tizen_surface_gl.cc", + "tizen_renderer.cc", "tizen_vsync_waiter.cc", "touch_event_handler.cc", ] @@ -57,30 +63,33 @@ source_set("flutter_tizen") { "//flutter/shell/platform/common/cpp:common_cpp", "//flutter/shell/platform/common/cpp:common_cpp_input", "//flutter/shell/platform/common/cpp/client_wrapper:client_wrapper", - "//flutter/shell/platform/embedder:embedder_as_internal_library", + "//flutter/shell/platform/embedder:flutter_engine", "//third_party/rapidjson", ] include_dirs = [ - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/base", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/dlog", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/ecore-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/ecore-evas-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/ecore-imf-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/ecore-imf-evas-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/ecore-input-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/ecore-wl2-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/efl-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/eina-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/eina-1/eina", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/emile-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/eo-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/evas-1", - "//third_party/tizen_tools/sysroot/$target_cpu/usr/include/system", + "$custom_sysroot/usr/include", + "$custom_sysroot/usr/include/appfw", + "$custom_sysroot/usr/include/base", + "$custom_sysroot/usr/include/dlog", + "$custom_sysroot/usr/include/ecore-1", + "$custom_sysroot/usr/include/ecore-evas-1", + "$custom_sysroot/usr/include/ecore-imf-1", + "$custom_sysroot/usr/include/ecore-imf-evas-1", + "$custom_sysroot/usr/include/ecore-input-1", + "$custom_sysroot/usr/include/ecore-wayland-1", + "$custom_sysroot/usr/include/ecore-wl2-1", + "$custom_sysroot/usr/include/efl-1", + "$custom_sysroot/usr/include/eina-1", + "$custom_sysroot/usr/include/eina-1/eina", + "$custom_sysroot/usr/include/emile-1", + "$custom_sysroot/usr/include/eo-1", + "$custom_sysroot/usr/include/evas-1", + "$custom_sysroot/usr/include/system", + "$custom_sysroot/usr/include/wayland-extension" ] - lib_dirs = [ "//third_party/tizen_tools/sysroot/$target_cpu/usr/lib" ] + lib_dirs = [ root_out_dir, "$custom_sysroot/usr/lib" ] cflags_cc = [ "-Wno-newline-eof", @@ -89,26 +98,29 @@ source_set("flutter_tizen") { libs = [ "base-utils-i18n", + "capi-appfw-application", "capi-system-info", "capi-system-system-settings", "dlog", "ecore", "ecore_imf", "ecore_input", - "ecore_wl2", + "eina", "EGL", "evas", + "flutter_engine", "GLESv2", "tbm", "tdm-client", "wayland-client", ] -} - -copy("publish_headers_tizen") { - sources = _public_headers - outputs = [ "$root_out_dir/{{source_file_part}}" ] - # The Tizen header assumes the presence of the common headers. - deps = [ "//flutter/shell/platform/common/cpp:publish_headers" ] + if (tizen_sdk_4) { + sources += [ "tizen_renderer_ecore_wl.cc" ] + libs += [ "ecore_wayland", "wayland-egl" ] + defines = [ "FLUTTER_TIZEN_4" ] + } else { + sources += [ "tizen_renderer_ecore_wl2.cc" ] + libs += [ "ecore_wl2" ] + } } diff --git a/shell/platform/tizen/channels/key_event_channel.cc b/shell/platform/tizen/channels/key_event_channel.cc index 58536c2af15fd..9f40869b0a8bf 100644 --- a/shell/platform/tizen/channels/key_event_channel.cc +++ b/shell/platform/tizen/channels/key_event_channel.cc @@ -6,7 +6,7 @@ #include -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_log.h" static constexpr char kChannelName[] = "flutter/keyevent"; @@ -221,7 +221,7 @@ KeyEventChannel::KeyEventChannel(flutter::BinaryMessenger* messenger) KeyEventChannel::~KeyEventChannel() {} void KeyEventChannel::SendKeyEvent(Ecore_Event_Key* key, bool is_down) { - LoggerD("code: %d, name: %s, mods: %d, type: %s", key->keycode, key->keyname, + FT_LOGD("code: %d, name: %s, mods: %d, type: %s", key->keycode, key->keyname, key->modifiers, is_down ? kKeyDown : kKeyUp); int gtk_keycode = 0; diff --git a/shell/platform/tizen/channels/lifecycle_channel.cc b/shell/platform/tizen/channels/lifecycle_channel.cc index 920b178ca4658..e8a4393e9bc9e 100644 --- a/shell/platform/tizen/channels/lifecycle_channel.cc +++ b/shell/platform/tizen/channels/lifecycle_channel.cc @@ -4,7 +4,7 @@ #include "lifecycle_channel.h" -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_log.h" static constexpr char kChannelName[] = "flutter/lifecycle"; static constexpr char kInactive[] = "AppLifecycleState.inactive"; @@ -29,21 +29,21 @@ void LifecycleChannel::SendLifecycleMessage(const char message[]) { } void LifecycleChannel::AppIsInactive() { - LoggerD("send app lifecycle state inactive."); + FT_LOGD("send app lifecycle state inactive."); SendLifecycleMessage(kInactive); } void LifecycleChannel::AppIsResumed() { - LoggerD("send app lifecycle state resumed."); + FT_LOGD("send app lifecycle state resumed."); SendLifecycleMessage(kResumed); } void LifecycleChannel::AppIsPaused() { - LoggerD("send app lifecycle state paused."); + FT_LOGD("send app lifecycle state paused."); SendLifecycleMessage(kPaused); } void LifecycleChannel::AppIsDetached() { - LoggerD("send app lifecycle state detached."); + FT_LOGD("send app lifecycle state detached."); SendLifecycleMessage(kDetached); } diff --git a/shell/platform/tizen/channels/localization_channel.cc b/shell/platform/tizen/channels/localization_channel.cc index 55c08cbb49986..fcd2d146dfba8 100644 --- a/shell/platform/tizen/channels/localization_channel.cc +++ b/shell/platform/tizen/channels/localization_channel.cc @@ -8,7 +8,7 @@ #include -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_log.h" #include "rapidjson/document.h" #include "rapidjson/writer.h" @@ -21,43 +21,61 @@ LocalizationChannel::LocalizationChannel(FLUTTER_API_SYMBOL(FlutterEngine) LocalizationChannel::~LocalizationChannel() {} void LocalizationChannel::SendLocales() { + const char* defualt_locale = nullptr; + FlutterLocale* flutter_locale = nullptr; + std::vector flutter_locales; + + int ret = i18n_ulocale_set_default(getenv("LANG")); + ret = i18n_ulocale_get_default(&defualt_locale); + if (ret != I18N_ERROR_NONE) { + FT_LOGE("i18n_ulocale_get_default() failed."); + return; + } + + std::string without_encoding_type(defualt_locale); + auto n = without_encoding_type.find('.'); + without_encoding_type.erase(n, without_encoding_type.length() - n); + + flutter_locale = GetFlutterLocale(without_encoding_type.data()); + if (flutter_locale) { + FT_LOGD("Choose Default locale[%s]", without_encoding_type.data()); + flutter_locales.push_back(flutter_locale); + } + int32_t count = i18n_ulocale_count_available(); - if (count > 0) { - FlutterLocale* flutterLocale = nullptr; - std::vector flutterLocales; - for (int i = 0; i < count; i++) { - const char* locale = i18n_ulocale_get_available(i); - flutterLocale = GetFlutterLocale(locale); - if (flutterLocale) { - flutterLocales.push_back(flutterLocale); + for (int i = 0; i < count; i++) { + const char* locale = i18n_ulocale_get_available(i); + if (without_encoding_type.compare(locale) != 0) { + flutter_locale = GetFlutterLocale(locale); + if (flutter_locale) { + flutter_locales.push_back(flutter_locale); } } + } - // send locales to engine - FlutterEngineUpdateLocales( - flutter_engine_, - const_cast(flutterLocales.data()), - flutterLocales.size()); + FT_LOGD("Send %zu available locales", flutter_locales.size()); + // send locales to engine + FlutterEngineUpdateLocales( + flutter_engine_, + const_cast(flutter_locales.data()), + flutter_locales.size()); - for (auto it : flutterLocales) { - DestroyFlutterLocale(it); - } + for (auto it : flutter_locales) { + DestroyFlutterLocale(it); } - - SendPlatformResolvedLocale(); } void LocalizationChannel::SendPlatformResolvedLocale() { const char* locale; int ret = i18n_ulocale_get_default(&locale); if (ret != I18N_ERROR_NONE) { - LoggerE("i18n_ulocale_get_default() failed."); + FT_LOGE("i18n_ulocale_get_default() failed."); return; } FlutterLocale* flutterLocale = GetFlutterLocale(locale); if (!flutterLocale) { - LoggerE("Language code is required but not present."); + FT_LOGE("Language code is required but not present."); return; } @@ -88,7 +106,7 @@ void LocalizationChannel::SendPlatformResolvedLocale() { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); if (!document.Accept(writer)) { - LoggerE("document.Accept failed!"); + FT_LOGE("document.Accept failed!"); return; } @@ -120,7 +138,7 @@ FlutterLocale* LocalizationChannel::GetFlutterLocale(const char* locale) { memcpy(language, buffer, bufSize); language[bufSize] = '\0'; } else { - LoggerE("i18n_ulocale_get_language failed!"); + FT_LOGE("i18n_ulocale_get_language failed!"); return nullptr; } diff --git a/shell/platform/tizen/channels/platform_channel.cc b/shell/platform/tizen/channels/platform_channel.cc index 65de673403c0e..b79f780af3a52 100644 --- a/shell/platform/tizen/channels/platform_channel.cc +++ b/shell/platform/tizen/channels/platform_channel.cc @@ -4,8 +4,10 @@ #include "platform_channel.h" +#include + #include "flutter/shell/platform/common/cpp/json_method_codec.h" -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_log.h" static constexpr char kChannelName[] = "flutter/platform"; @@ -28,7 +30,7 @@ void PlatformChannel::HandleMethodCall( const auto method = call.method_name(); if (method == "SystemNavigator.pop") { - exit(EXIT_SUCCESS); + ui_app_exit(); result->Success(); } else if (method == "SystemSound.play") { result->NotImplemented(); @@ -51,7 +53,7 @@ void PlatformChannel::HandleMethodCall( } else if (method == "SystemChrome.setSystemUIOverlayStyle") { result->NotImplemented(); } else { - LoggerI("Unimplemented method: %s", method.c_str()); + FT_LOGI("Unimplemented method: %s", method.c_str()); result->NotImplemented(); } } diff --git a/shell/platform/tizen/channels/platform_view_channel.cc b/shell/platform/tizen/channels/platform_view_channel.cc index 779b50e4d46b3..e2fc517712f9a 100644 --- a/shell/platform/tizen/channels/platform_view_channel.cc +++ b/shell/platform/tizen/channels/platform_view_channel.cc @@ -4,15 +4,17 @@ #include "platform_view_channel.h" #include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h" -#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/standard_method_codec.h" #include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/standard_message_codec.h" +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/standard_method_codec.h" #include "flutter/shell/platform/common/cpp/json_method_codec.h" -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/channels/text_input_channel.h" #include "flutter/shell/platform/tizen/public/flutter_platform_view.h" +#include "flutter/shell/platform/tizen/tizen_embedder_engine.h" +#include "flutter/shell/platform/tizen/tizen_log.h" static constexpr char kChannelName[] = "flutter/platform_views"; -std::string extractStringFromMap(const flutter::EncodableValue& arguments, +std::string ExtractStringFromMap(const flutter::EncodableValue& arguments, const char* key) { if (std::holds_alternative(arguments)) { flutter::EncodableMap values = std::get(arguments); @@ -22,7 +24,7 @@ std::string extractStringFromMap(const flutter::EncodableValue& arguments, } return std::string(); } -int extractIntFromMap(const flutter::EncodableValue& arguments, +int ExtractIntFromMap(const flutter::EncodableValue& arguments, const char* key) { if (std::holds_alternative(arguments)) { flutter::EncodableMap values = std::get(arguments); @@ -31,7 +33,7 @@ int extractIntFromMap(const flutter::EncodableValue& arguments, } return -1; } -double extractDoubleFromMap(const flutter::EncodableValue& arguments, +double ExtractDoubleFromMap(const flutter::EncodableValue& arguments, const char* key) { if (std::holds_alternative(arguments)) { flutter::EncodableMap values = std::get(arguments); @@ -41,7 +43,7 @@ double extractDoubleFromMap(const flutter::EncodableValue& arguments, return -1; } -flutter::EncodableMap extractMapFromMap( +flutter::EncodableMap ExtractMapFromMap( const flutter::EncodableValue& arguments, const char* key) { if (std::holds_alternative(arguments)) { flutter::EncodableMap values = std::get(arguments); @@ -52,8 +54,21 @@ flutter::EncodableMap extractMapFromMap( return flutter::EncodableMap(); } -PlatformViewChannel::PlatformViewChannel(flutter::BinaryMessenger* messenger) - : channel_( +flutter::EncodableList ExtractListFromMap( + const flutter::EncodableValue& arguments, const char* key) { + if (std::holds_alternative(arguments)) { + flutter::EncodableMap values = std::get(arguments); + flutter::EncodableValue value = values[flutter::EncodableValue(key)]; + if (std::holds_alternative(value)) + return std::get(value); + } + return flutter::EncodableList(); +} + +PlatformViewChannel::PlatformViewChannel(flutter::BinaryMessenger* messenger, + TizenEmbedderEngine* engine) + : engine_(engine), + channel_( std::make_unique>( messenger, kChannelName, &flutter::StandardMethodCodec::GetInstance())) { @@ -63,19 +78,41 @@ PlatformViewChannel::PlatformViewChannel(flutter::BinaryMessenger* messenger) result) { HandleMethodCall(call, std::move(result)); }); } -PlatformViewChannel::~PlatformViewChannel() { - // Clean-up view_factories_ - for (auto const& [viewType, viewFactory] : view_factories_) { - viewFactory->dispose(); - } - view_factories_.clear(); +PlatformViewChannel::~PlatformViewChannel() { Dispose(); } +void PlatformViewChannel::Dispose() { // Clean-up view_instances_ for (auto const& [viewId, viewInstance] : view_instances_) { - viewInstance->dispose(); delete viewInstance; } view_instances_.clear(); + + // Clean-up view_factories_ + for (auto const& [viewType, viewFactory] : view_factories_) { + viewFactory->Dispose(); + } + view_factories_.clear(); +} + +void PlatformViewChannel::SendKeyEvent(Ecore_Event_Key* key, bool is_down) { + auto instances = ViewInstances(); + auto it = instances.find(CurrentFocusedViewId()); + if (it != instances.end()) { + if (is_down) { + it->second->DispatchKeyDownEvent(key); + } else { + it->second->DispatchKeyUpEvent(key); + } + } +} + +int PlatformViewChannel::CurrentFocusedViewId() { + for (auto it = view_instances_.begin(); it != view_instances_.end(); it++) { + if (it->second->IsFocused()) { + return it->second->GetViewId(); + } + } + return -1; } void PlatformViewChannel::HandleMethodCall( @@ -84,13 +121,14 @@ void PlatformViewChannel::HandleMethodCall( const auto method = call.method_name(); const auto& arguments = *call.arguments(); + FT_LOGD("PlatformViewChannel method: %s", method.c_str()); if (method == "create") { - std::string viewType = extractStringFromMap(arguments, "viewType"); - int viewId = extractIntFromMap(arguments, "id"); - double width = extractDoubleFromMap(arguments, "width"); - double height = extractDoubleFromMap(arguments, "height"); + std::string viewType = ExtractStringFromMap(arguments, "viewType"); + int viewId = ExtractIntFromMap(arguments, "id"); + double width = ExtractDoubleFromMap(arguments, "width"); + double height = ExtractDoubleFromMap(arguments, "height"); - LoggerD( + FT_LOGD( "PlatformViewChannel create viewType: %s id: %d width: %f height: %f ", viewType.c_str(), viewId, width, height); @@ -102,46 +140,97 @@ void PlatformViewChannel::HandleMethodCall( } auto it = view_factories_.find(viewType); if (it != view_factories_.end()) { + auto focuesdView = view_instances_.find(CurrentFocusedViewId()); + if (focuesdView != view_instances_.end()) { + focuesdView->second->SetFocus(false); + } + auto viewInstance = - it->second->create(viewId, width, height, byteMessage); - view_instances_.insert( - std::pair(viewId, viewInstance)); - result->Success(flutter::EncodableValue(viewInstance->getTextureId())); + it->second->Create(viewId, width, height, byteMessage); + if (viewInstance) { + view_instances_.insert( + std::pair(viewId, viewInstance)); + + if (engine_ && engine_->text_input_channel) { + Ecore_IMF_Context* context = + engine_->text_input_channel->GetImfContext(); + viewInstance->SetSoftwareKeyboardContext(context); + } + result->Success(flutter::EncodableValue(viewInstance->GetTextureId())); + } else { + result->Error("Can't create a webview instance!!"); + } + } else { + FT_LOGE("can't find view type = %s", viewType.c_str()); + result->Error("Can't find view type"); + } + } else if (method == "clearFocus") { + int viewId = -1; + if (std::holds_alternative(arguments)) { + viewId = std::get(arguments); + }; + auto it = view_instances_.find(viewId); + if (viewId >= 0 && it != view_instances_.end()) { + it->second->SetFocus(false); + it->second->ClearFocus(); + result->Success(); } else { - LoggerE("can't find view type = %s", viewType.c_str()); - result->Error("0", "can't find view type"); + result->Error("Can't find view id"); } } else { - int viewId = extractIntFromMap(arguments, "id"); + int viewId = ExtractIntFromMap(arguments, "id"); auto it = view_instances_.find(viewId); if (viewId >= 0 && it != view_instances_.end()) { if (method == "dispose") { - LoggerD("PlatformViewChannel dispose"); - it->second->dispose(); + FT_LOGD("PlatformViewChannel dispose"); + it->second->Dispose(); result->Success(); } else if (method == "resize") { - LoggerD("PlatformViewChannel resize"); - double width = extractDoubleFromMap(arguments, "width"); - double height = extractDoubleFromMap(arguments, "height"); - it->second->resize(width, height); + double width = ExtractDoubleFromMap(arguments, "width"); + double height = ExtractDoubleFromMap(arguments, "height"); + it->second->Resize(width, height); result->NotImplemented(); } else if (method == "touch") { - LoggerD("PlatformViewChannel touch"); - result->NotImplemented(); + int type, button; + double x, y, dx, dy; + + flutter::EncodableList event = ExtractListFromMap(arguments, "event"); + if (event.size() != 6) { + result->Error("Invalid Arguments"); + return; + } + type = std::get(event[0]); + button = std::get(event[1]); + x = std::get(event[2]); + y = std::get(event[3]); + dx = std::get(event[4]); + dy = std::get(event[5]); + + it->second->Touch(type, button, x, y, dx, dy); + + if (!it->second->IsFocused()) { + auto focuesdView = view_instances_.find(CurrentFocusedViewId()); + if (focuesdView != view_instances_.end()) { + focuesdView->second->SetFocus(false); + } + + it->second->SetFocus(true); + if (channel_ != nullptr) { + auto id = std::make_unique(viewId); + channel_->InvokeMethod("viewFocused", std::move(id)); + } + } + + result->Success(); } else if (method == "setDirection") { - LoggerD("PlatformViewChannel setDirection"); - result->NotImplemented(); - } else if (method == "clearFocus") { - LoggerD("PlatformViewChannel clearFocus"); - it->second->clearFocus(); + FT_LOGD("PlatformViewChannel setDirection"); result->NotImplemented(); } else { - LoggerD("Unimplemented method: %s", method.c_str()); + FT_LOGD("Unimplemented method: %s", method.c_str()); result->NotImplemented(); } } else { - LoggerE("can't find view id"); - result->Error("0", "can't find view id"); + result->Error("Can't find view id"); } } } diff --git a/shell/platform/tizen/channels/platform_view_channel.h b/shell/platform/tizen/channels/platform_view_channel.h index ecd437d7053df..bb8f9494e87e4 100644 --- a/shell/platform/tizen/channels/platform_view_channel.h +++ b/shell/platform/tizen/channels/platform_view_channel.h @@ -5,23 +5,33 @@ #ifndef EMBEDDER_PLATFORM_VIEW_CHANNEL_H_ #define EMBEDDER_PLATFORM_VIEW_CHANNEL_H_ +#include + #include #include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h" #include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/method_channel.h" #include "rapidjson/document.h" +class TizenEmbedderEngine; class PlatformView; class PlatformViewFactory; class PlatformViewChannel { public: - explicit PlatformViewChannel(flutter::BinaryMessenger* messenger); + explicit PlatformViewChannel(flutter::BinaryMessenger* messenger, + TizenEmbedderEngine* engine); virtual ~PlatformViewChannel(); - std::map>& viewFactories() { + void Dispose(); + std::map>& ViewFactories() { return view_factories_; } + std::map& ViewInstances() { return view_instances_; } + + void SendKeyEvent(Ecore_Event_Key* key, bool is_down); + int CurrentFocusedViewId(); private: + TizenEmbedderEngine* engine_; std::unique_ptr> channel_; std::map> view_factories_; std::map view_instances_; diff --git a/shell/platform/tizen/channels/text_input_channel.cc b/shell/platform/tizen/channels/text_input_channel.cc index dd4eec438e35b..d59e2adabd297 100644 --- a/shell/platform/tizen/channels/text_input_channel.cc +++ b/shell/platform/tizen/channels/text_input_channel.cc @@ -4,9 +4,11 @@ #include "text_input_channel.h" +#include #include -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_embedder_engine.h" +#include "flutter/shell/platform/tizen/tizen_log.h" #include "stdlib.h" #include "string.h" @@ -19,6 +21,8 @@ static constexpr char kMultilineInputType[] = "TextInputType.multiline"; static constexpr char kUpdateEditingStateMethod[] = "TextInputClient.updateEditingState"; static constexpr char kPerformActionMethod[] = "TextInputClient.performAction"; +static constexpr char kSetPlatformViewClient[] = + "TextInput.setPlatformViewClient"; static constexpr char kTextInputAction[] = "inputAction"; static constexpr char kTextInputType[] = "inputType"; static constexpr char kTextInputTypeName[] = "name"; @@ -35,7 +39,7 @@ static constexpr char kBadArgumentError[] = "Bad Arguments"; static constexpr char kInternalConsistencyError[] = "Internal Consistency Error"; -static const char* getImfMethod() { +static const char* GetImfMethod() { Eina_List* modules; modules = ecore_imf_context_available_ids_get(); @@ -54,15 +58,15 @@ static bool IsASCIIPrintableKey(char c) { return false; } -static void CommitCallback(void* data, Ecore_IMF_Context* ctx, - void* event_info) { +void TextInputChannel::CommitCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info) { TextInputChannel* self = (TextInputChannel*)data; char* str = (char*)event_info; self->OnCommit(str); } -static void PreeditCallback(void* data, Ecore_IMF_Context* ctx, - void* event_info) { +void TextInputChannel::PreeditCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info) { TextInputChannel* self = (TextInputChannel*)data; char* preedit_string = nullptr; int cursor_pos; @@ -73,46 +77,90 @@ static void PreeditCallback(void* data, Ecore_IMF_Context* ctx, } } -static void PrivateCommandCallback(void* data, Ecore_IMF_Context* ctx, - void* event_info) { +void TextInputChannel::PrivateCommandCallback(void* data, + Ecore_IMF_Context* ctx, + void* event_info) { // TODO - LoggerD("Unimplemented"); + FT_LOGD_UNIMPLEMENTED(); } -static void DeleteSurroundingCallback(void* data, Ecore_IMF_Context* ctx, - void* event_info) { +void TextInputChannel::DeleteSurroundingCallback(void* data, + Ecore_IMF_Context* ctx, + void* event_info) { // TODO - LoggerD("Unimplemented"); + FT_LOGD_UNIMPLEMENTED(); } -static void InputPanelStatChangedCallback(void* data, - Ecore_IMF_Context* context, - int value) { +void TextInputChannel::InputPanelStateChangedCallback( + void* data, Ecore_IMF_Context* context, int value) { if (!data) { - LoggerD("[No Data]\n"); + FT_LOGD("[No Data]\n"); return; } TextInputChannel* self = (TextInputChannel*)data; switch (value) { - case ECORE_IMF_INPUT_PANEL_STATE_SHOW: - LoggerD("[PANEL_STATE_SHOW]\n"); - self->ShowSoftwareKeyboard(); - break; + case ECORE_IMF_INPUT_PANEL_STATE_SHOW: { + FT_LOGD("[PANEL_STATE_SHOW]\n"); + if (self->engine_->device_profile == + "mobileD") { // FIXME : Needs improvement on other devices. + ecore_timer_add( + 0.25, + [](void* data) -> Eina_Bool { + TextInputChannel* self = (TextInputChannel*)data; + auto window_geometry = + self->engine_->tizen_renderer->GetGeometry(); + int32_t surface_w = window_geometry.w; + int32_t surface_h = + window_geometry.h - self->current_keyboard_geometry_.h; + + self->engine_->tizen_renderer->ResizeWithRotation(0, 0, surface_w, + surface_h, 0); + if (self->rotation == 90 || self->rotation == 270) { + self->engine_->SendWindowMetrics(surface_h, surface_w, 0); + } else { + self->engine_->SendWindowMetrics(surface_w, surface_h, 0); + } + + return ECORE_CALLBACK_CANCEL; + }, + self); + } + } break; case ECORE_IMF_INPUT_PANEL_STATE_HIDE: - LoggerD("[PANEL_STATE_HIDE]\n"); - self->HideSoftwareKeyboard(); + self->HideSoftwareKeyboard(); // FIXME: Fallback for HW back-key + FT_LOGD("[PANEL_STATE_HIDE]\n"); break; case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW: - LoggerD("[PANEL_STATE_WILL_SHOW]\n"); + FT_LOGD("[PANEL_STATE_WILL_SHOW]\n"); break; default: - LoggerD("[PANEL_STATE_EVENT (default: %d)]\n", value); + FT_LOGD("[PANEL_STATE_EVENT (default: %d)]\n", value); break; } } -static Eina_Bool RetrieveSurroundingCallback(void* data, Ecore_IMF_Context* ctx, - char** text, int* cursor_pos) { +void TextInputChannel::InputPanelGeometryChangedCallback( + void* data, Ecore_IMF_Context* context, int value) { + if (!data) { + FT_LOGD("[No Data]\n"); + return; + } + TextInputChannel* self = (TextInputChannel*)data; + ecore_imf_context_input_panel_geometry_get( + self->imf_context_, &self->current_keyboard_geometry_.x, + &self->current_keyboard_geometry_.y, &self->current_keyboard_geometry_.w, + &self->current_keyboard_geometry_.h); + + FT_LOGD( + "[Current keyboard geometry] x:%d y:%d w:%d h:%d\n", + self->current_keyboard_geometry_.x, self->current_keyboard_geometry_.y, + self->current_keyboard_geometry_.w, self->current_keyboard_geometry_.h); +} + +Eina_Bool TextInputChannel::RetrieveSurroundingCallback(void* data, + Ecore_IMF_Context* ctx, + char** text, + int* cursor_pos) { // TODO if (text) { *text = strdup(""); @@ -218,7 +266,7 @@ Ecore_IMF_Device_Subclass EoreDeviceSubClassToEcoreIMFDeviceSubClass( return ECORE_IMF_DEVICE_SUBCLASS_TRACKBALL; case ECORE_DEVICE_SUBCLASS_REMOCON: case ECORE_DEVICE_SUBCLASS_VIRTUAL_KEYBOARD: - // LoggerW("There is no corresponding type"); + // FT_LOGW("There is no corresponding type"); case ECORE_DEVICE_SUBCLASS_NONE: default: return ECORE_IMF_DEVICE_SUBCLASS_NONE; @@ -226,21 +274,15 @@ Ecore_IMF_Device_Subclass EoreDeviceSubClassToEcoreIMFDeviceSubClass( } TextInputChannel::TextInputChannel(flutter::BinaryMessenger* messenger, - Ecore_Wl2_Window* ecoreWindow) + TizenEmbedderEngine* engine) : channel_(std::make_unique>( messenger, kChannelName, &flutter::JsonMethodCodec::GetInstance())), active_model_(nullptr), - isSoftwareKeyboardShowing_(false), - lastPreeditStringLength_(0), - imfContext_(nullptr), - isWearable_(false), - inSelectMode_(false) { - const char* elmProfile = getenv("ELM_PROFILE"); - if (!elmProfile || strcmp(elmProfile, "wearable") == 0) { - LoggerD("ELM_PROFILE is wearable"); - isWearable_ = true; - } - + is_software_keyboard_showing_(false), + last_preedit_string_length_(0), + imf_context_(nullptr), + in_select_mode_(false), + engine_(engine) { channel_->SetMethodCallHandler( [this]( const flutter::MethodCall& call, @@ -251,23 +293,23 @@ TextInputChannel::TextInputChannel(flutter::BinaryMessenger* messenger, ecore_imf_init(); // Register IMF callbacks if (ecore_imf_context_default_id_get()) { - imfContext_ = ecore_imf_context_add(ecore_imf_context_default_id_get()); - } else if (getImfMethod() != nullptr) { - imfContext_ = ecore_imf_context_add(getImfMethod()); + imf_context_ = ecore_imf_context_add(ecore_imf_context_default_id_get()); + } else if (GetImfMethod() != nullptr) { + imf_context_ = ecore_imf_context_add(GetImfMethod()); } - if (imfContext_) { + if (imf_context_) { ecore_imf_context_client_window_set( - imfContext_, (void*)ecore_wl2_window_id_get(ecoreWindow)); - RegisterIMFCallback(ecoreWindow); + imf_context_, (void*)engine_->tizen_renderer->GetEcoreWindowId()); + RegisterIMFCallback(); } else { - LoggerE("Failed to create imfContext"); + FT_LOGE("Failed to create imfContext"); } } TextInputChannel::~TextInputChannel() { - if (imfContext_) { + if (imf_context_) { UnregisterIMFCallback(); - ecore_imf_context_del(imfContext_); + ecore_imf_context_del(imf_context_); ecore_imf_shutdown(); } } @@ -283,12 +325,14 @@ void TextInputChannel::HandleMethodCall( std::unique_ptr> result) { const std::string& method = method_call.method_name(); - LoggerD("Method : %s", method.data()); + FT_LOGD("Method : %s", method.data()); if (method.compare(kShowMethod) == 0) { ShowSoftwareKeyboard(); } else if (method.compare(kHideMethod) == 0) { HideSoftwareKeyboard(); + } else if (method.compare(kSetPlatformViewClient) == 0) { + // TODO: implement if necessary } else if (method.compare(kClearClientMethod) == 0) { active_model_ = nullptr; } else if (method.compare(kSetClientMethod) == 0) { @@ -391,8 +435,8 @@ void TextInputChannel::SendStateUpdate(const flutter::TextInputModel& model) { } bool TextInputChannel::FilterEvent(Ecore_Event_Key* keyDownEvent) { + FT_LOGD("NonIMFFallback key name [%s]", keyDownEvent->keyname); bool handled = false; - const char* device = ecore_device_name_get(keyDownEvent->dev); Ecore_IMF_Event_Key_Down ecoreKeyDownEvent; @@ -410,12 +454,14 @@ bool TextInputChannel::FilterEvent(Ecore_Event_Key* keyDownEvent) { ecore_device_class_get(keyDownEvent->dev)); ecoreKeyDownEvent.dev_subclass = EoreDeviceSubClassToEcoreIMFDeviceSubClass( ecore_device_subclass_get(keyDownEvent->dev)); +#ifndef FLUTTER_TIZEN_4 ecoreKeyDownEvent.keycode = keyDownEvent->keycode; +#endif bool isIME = strcmp(device, "ime") == 0; if (isIME && strcmp(keyDownEvent->key, "Select") == 0) { - if (isWearable_) { - inSelectMode_ = true; + if (engine_->device_profile == "wearable") { + in_select_mode_ = true; } else { SelectPressed(active_model_.get()); return true; @@ -452,16 +498,16 @@ bool TextInputChannel::FilterEvent(Ecore_Event_Key* keyDownEvent) { } } else { handled = ecore_imf_context_filter_event( - imfContext_, ECORE_IMF_EVENT_KEY_DOWN, + imf_context_, ECORE_IMF_EVENT_KEY_DOWN, reinterpret_cast(&ecoreKeyDownEvent)); } if (!handled && !strcmp(keyDownEvent->key, "Return")) { - if (inSelectMode_) { - inSelectMode_ = false; + if (in_select_mode_) { + in_select_mode_ = false; handled = true; } else { - ecore_imf_context_reset(imfContext_); + ecore_imf_context_reset(imf_context_); EnterPressed(active_model_.get()); } } @@ -470,7 +516,7 @@ bool TextInputChannel::FilterEvent(Ecore_Event_Key* keyDownEvent) { } void TextInputChannel::NonIMFFallback(Ecore_Event_Key* keyDownEvent) { - LoggerD("NonIMFFallback key name [%s]", keyDownEvent->keyname); + FT_LOGD("NonIMFFallback key name [%s]", keyDownEvent->keyname); if (strcmp(keyDownEvent->key, "Left") == 0) { if (active_model_->MoveCursorBack()) { SendStateUpdate(*active_model_); @@ -525,93 +571,123 @@ void TextInputChannel::SelectPressed(flutter::TextInputModel* model) { } void TextInputChannel::OnCommit(const char* str) { - for (int i = lastPreeditStringLength_; i > 0; i--) { + for (int i = last_preedit_string_length_; i > 0; i--) { active_model_->Backspace(); } active_model_->AddText(str); SendStateUpdate(*active_model_); - lastPreeditStringLength_ = 0; + last_preedit_string_length_ = 0; } void TextInputChannel::OnPredit(const char* str, int cursorPos) { if (strcmp(str, "") == 0) { - lastPreeditStringLength_ = 0; + last_preedit_string_length_ = 0; return; } - for (int i = lastPreeditStringLength_; i > 0; i--) { + for (int i = last_preedit_string_length_; i > 0; i--) { active_model_->Backspace(); } active_model_->AddText(str); SendStateUpdate(*active_model_); - lastPreeditStringLength_ = cursorPos; + last_preedit_string_length_ = cursorPos; } void TextInputChannel::ShowSoftwareKeyboard() { - LoggerD("ShowPanel() [isSoftwareKeyboardShowing_:%d] \n", - isSoftwareKeyboardShowing_); - if (imfContext_ && !isSoftwareKeyboardShowing_) { - isSoftwareKeyboardShowing_ = true; - ecore_imf_context_input_panel_show(imfContext_); - ecore_imf_context_focus_in(imfContext_); + FT_LOGD("ShowPanel() [is_software_keyboard_showing_:%d] \n", + is_software_keyboard_showing_); + if (imf_context_ && !is_software_keyboard_showing_) { + is_software_keyboard_showing_ = true; + ecore_imf_context_input_panel_show(imf_context_); + ecore_imf_context_focus_in(imf_context_); } } void TextInputChannel::HideSoftwareKeyboard() { - LoggerD("HidePanel() [isSoftwareKeyboardShowing_:%d] \n", - isSoftwareKeyboardShowing_); - if (imfContext_ && isSoftwareKeyboardShowing_) { - isSoftwareKeyboardShowing_ = false; - ecore_imf_context_reset(imfContext_); - ecore_imf_context_focus_out(imfContext_); - ecore_imf_context_input_panel_hide(imfContext_); + FT_LOGD("HidePanel() [is_software_keyboard_showing_:%d] \n", + is_software_keyboard_showing_); + if (imf_context_ && is_software_keyboard_showing_) { + is_software_keyboard_showing_ = false; + + if (engine_->device_profile == + "mobileD") { // FIXME : Needs improvement on other devices. + auto window_geometry = engine_->tizen_renderer->GetGeometry(); + + if (rotation == 90 || rotation == 270) { + engine_->SendWindowMetrics(window_geometry.h, window_geometry.w, 0); + } else { + engine_->SendWindowMetrics(window_geometry.w, window_geometry.h, 0); + } + engine_->tizen_renderer->ResizeWithRotation(0, 0, window_geometry.w, + window_geometry.h, 0); + ecore_timer_add( + 0.05, + [](void* data) -> Eina_Bool { + Ecore_IMF_Context* imfContext = (Ecore_IMF_Context*)data; + ecore_imf_context_reset(imfContext); + ecore_imf_context_focus_out(imfContext); + ecore_imf_context_input_panel_hide(imfContext); + return ECORE_CALLBACK_CANCEL; + }, + imf_context_); + } else { + ecore_imf_context_reset(imf_context_); + ecore_imf_context_focus_out(imf_context_); + ecore_imf_context_input_panel_hide(imf_context_); + } } } -void TextInputChannel::RegisterIMFCallback(Ecore_Wl2_Window* ecoreWindow) { - // ecore_imf_context_input_panel_enabled_set(imfContext_, false); - ecore_imf_context_event_callback_add(imfContext_, ECORE_IMF_CALLBACK_COMMIT, +void TextInputChannel::RegisterIMFCallback() { + // ecore_imf_context_input_panel_enabled_set(imf_context_, false); + ecore_imf_context_event_callback_add(imf_context_, ECORE_IMF_CALLBACK_COMMIT, CommitCallback, this); ecore_imf_context_event_callback_add( - imfContext_, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreeditCallback, this); - ecore_imf_context_event_callback_add(imfContext_, + imf_context_, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreeditCallback, this); + ecore_imf_context_event_callback_add(imf_context_, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, DeleteSurroundingCallback, this); - ecore_imf_context_event_callback_add(imfContext_, + ecore_imf_context_event_callback_add(imf_context_, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommandCallback, this); ecore_imf_context_input_panel_event_callback_add( - imfContext_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, - InputPanelStatChangedCallback, this); + imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, + InputPanelStateChangedCallback, this); + ecore_imf_context_input_panel_event_callback_add( + imf_context_, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, + InputPanelGeometryChangedCallback, this); ecore_imf_context_retrieve_surrounding_callback_set( - imfContext_, RetrieveSurroundingCallback, this); + imf_context_, RetrieveSurroundingCallback, this); // These APIs have to be set when IMF's setting status is changed. - ecore_imf_context_autocapital_type_set(imfContext_, + ecore_imf_context_autocapital_type_set(imf_context_, ECORE_IMF_AUTOCAPITAL_TYPE_NONE); - ecore_imf_context_prediction_allow_set(imfContext_, EINA_FALSE); - ecore_imf_context_input_panel_layout_set(imfContext_, + ecore_imf_context_prediction_allow_set(imf_context_, EINA_FALSE); + ecore_imf_context_input_panel_layout_set(imf_context_, ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL); ecore_imf_context_input_panel_return_key_type_set( - imfContext_, ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT); - ecore_imf_context_input_panel_layout_variation_set(imfContext_, 0); + imf_context_, ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT); + ecore_imf_context_input_panel_layout_variation_set(imf_context_, 0); ecore_imf_context_input_panel_language_set( - imfContext_, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC); + imf_context_, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC); } void TextInputChannel::UnregisterIMFCallback() { - ecore_imf_context_event_callback_del(imfContext_, ECORE_IMF_CALLBACK_COMMIT, + ecore_imf_context_event_callback_del(imf_context_, ECORE_IMF_CALLBACK_COMMIT, CommitCallback); ecore_imf_context_event_callback_del( - imfContext_, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreeditCallback); - ecore_imf_context_event_callback_del(imfContext_, + imf_context_, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, PreeditCallback); + ecore_imf_context_event_callback_del(imf_context_, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, DeleteSurroundingCallback); - ecore_imf_context_event_callback_del(imfContext_, + ecore_imf_context_event_callback_del(imf_context_, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommandCallback); ecore_imf_context_input_panel_event_callback_del( - imfContext_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, - InputPanelStatChangedCallback); + imf_context_, ECORE_IMF_INPUT_PANEL_STATE_EVENT, + InputPanelStateChangedCallback); + ecore_imf_context_input_panel_event_callback_del( + imf_context_, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, + InputPanelGeometryChangedCallback); } diff --git a/shell/platform/tizen/channels/text_input_channel.h b/shell/platform/tizen/channels/text_input_channel.h index b8d8985bcadf2..f2290d02c9e98 100644 --- a/shell/platform/tizen/channels/text_input_channel.h +++ b/shell/platform/tizen/channels/text_input_channel.h @@ -8,7 +8,6 @@ #define EFL_BETA_API_SUPPORT #include #include -#include #include @@ -17,17 +16,28 @@ #include "flutter/shell/platform/common/cpp/json_method_codec.h" #include "flutter/shell/platform/common/cpp/text_input_model.h" +class TizenEmbedderEngine; class TextInputChannel { public: + struct SoftwareKeyboardGeometry { + int32_t x = 0, y = 0, w = 0, h = 0; + }; explicit TextInputChannel(flutter::BinaryMessenger* messenger, - Ecore_Wl2_Window* ecoreWindow); + TizenEmbedderEngine* engine); virtual ~TextInputChannel(); void OnKeyDown(Ecore_Event_Key* key); void OnCommit(const char* str); void OnPredit(const char* str, int cursorPos); void ShowSoftwareKeyboard(); void HideSoftwareKeyboard(); - bool isSoftwareKeyboardShowing() { return isSoftwareKeyboardShowing_; } + bool IsSoftwareKeyboardShowing() { return is_software_keyboard_showing_; } + SoftwareKeyboardGeometry GetCurrentKeyboardGeometry() { + return current_keyboard_geometry_; + } + + Ecore_IMF_Context* GetImfContext() { return imf_context_; } + + int32_t rotation = 0; private: void HandleMethodCall( @@ -38,20 +48,38 @@ class TextInputChannel { void NonIMFFallback(Ecore_Event_Key* keyDownEvent); void EnterPressed(flutter::TextInputModel* model); void SelectPressed(flutter::TextInputModel* model); - void RegisterIMFCallback(Ecore_Wl2_Window* ecoreWindow); + void RegisterIMFCallback(); void UnregisterIMFCallback(); std::unique_ptr> channel_; std::unique_ptr active_model_; - private: + static void CommitCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info); + static void PreeditCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info); + static void PrivateCommandCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info); + static void DeleteSurroundingCallback(void* data, Ecore_IMF_Context* ctx, + void* event_info); + static void InputPanelStateChangedCallback(void* data, + Ecore_IMF_Context* context, + int value); + static void InputPanelGeometryChangedCallback(void* data, + Ecore_IMF_Context* context, + int value); + static Eina_Bool RetrieveSurroundingCallback(void* data, + Ecore_IMF_Context* ctx, + char** text, int* cursor_pos); + int client_id_; std::string input_type_; std::string input_action_; - bool isSoftwareKeyboardShowing_; - int lastPreeditStringLength_; - Ecore_IMF_Context* imfContext_; - bool isWearable_; - bool inSelectMode_; + bool is_software_keyboard_showing_; + int last_preedit_string_length_; + Ecore_IMF_Context* imf_context_; + bool in_select_mode_; + TizenEmbedderEngine* engine_; + SoftwareKeyboardGeometry current_keyboard_geometry_; }; #endif diff --git a/shell/platform/tizen/config.gni b/shell/platform/tizen/config.gni index 245032c3255cd..ffd4d2b766659 100644 --- a/shell/platform/tizen/config.gni +++ b/shell/platform/tizen/config.gni @@ -10,4 +10,5 @@ declare_args() { # as an extra build artifact with this flag. The native toolkit shell will # still be built as well. build_tizen_shell = false + tizen_sdk_4 = false } diff --git a/shell/platform/tizen/external_texture_gl.cc b/shell/platform/tizen/external_texture_gl.cc index 3f826d9c74cbb..d7078978f5685 100644 --- a/shell/platform/tizen/external_texture_gl.cc +++ b/shell/platform/tizen/external_texture_gl.cc @@ -13,7 +13,7 @@ #include #include -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_log.h" struct ExternalTextureGLState { GLuint gl_texture; @@ -32,27 +32,24 @@ ExternalTextureGL::~ExternalTextureGL() { glDeleteTextures(1, &state_->gl_texture); } state_.release(); - if (texture_tbm_surface_) { - tbm_surface_internal_unref(texture_tbm_surface_); - texture_tbm_surface_ = NULL; - } + DestructionTbmSurface(); mutex_.unlock(); } bool ExternalTextureGL::OnFrameAvailable(tbm_surface_h tbm_surface) { mutex_.lock(); if (!tbm_surface) { - LoggerE("tbm_surface is null"); + FT_LOGE("tbm_surface is null"); mutex_.unlock(); return false; } if (texture_tbm_surface_) { - LoggerE("texture_tbm_surface_ does not destruction, discard"); + FT_LOGD("texture_tbm_surface_ does not destruction, discard"); mutex_.unlock(); return false; } if (!tbm_surface_internal_is_valid(tbm_surface)) { - LoggerE("tbm_surface not valid, pass"); + FT_LOGD("tbm_surface not valid, pass"); mutex_.unlock(); return false; } @@ -66,12 +63,13 @@ bool ExternalTextureGL::PopulateTextureWithIdentifier( size_t width, size_t height, FlutterOpenGLTexture* opengl_texture) { mutex_.lock(); if (!texture_tbm_surface_) { - LoggerE("texture_tbm_surface_ is NULL"); + FT_LOGD("texture_tbm_surface_ is NULL"); mutex_.unlock(); return false; } if (!tbm_surface_internal_is_valid(texture_tbm_surface_)) { - LoggerE("tbm_surface not valid"); + FT_LOGD("tbm_surface not valid"); + DestructionTbmSurface(); mutex_.unlock(); return false; } @@ -84,7 +82,7 @@ bool ExternalTextureGL::PopulateTextureWithIdentifier( eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_SURFACE_TIZEN, (EGLClientBuffer)texture_tbm_surface_, attrs); if (!eglSrcImage) { - LoggerE("eglSrcImage create fail!!, errorcode == %d", eglGetError()); + FT_LOGE("eglSrcImage create fail!!, errorcode == %d", eglGetError()); mutex_.unlock(); return false; } @@ -114,7 +112,7 @@ bool ExternalTextureGL::PopulateTextureWithIdentifier( opengl_texture->target = GL_TEXTURE_EXTERNAL_OES; opengl_texture->name = state_->gl_texture; opengl_texture->format = GL_RGBA8; - opengl_texture->destruction_callback = (VoidCallback)destructionCallback; + opengl_texture->destruction_callback = (VoidCallback)DestructionCallback; opengl_texture->user_data = static_cast(this); opengl_texture->width = width; opengl_texture->height = height; @@ -122,20 +120,23 @@ bool ExternalTextureGL::PopulateTextureWithIdentifier( return true; } -void ExternalTextureGL::DestructionTbmSurface() { +void ExternalTextureGL::DestructionTbmSurfaceWithLock() { mutex_.lock(); + DestructionTbmSurface(); + mutex_.unlock(); +} + +void ExternalTextureGL::DestructionTbmSurface() { if (!texture_tbm_surface_) { - LoggerE("tbm_surface_h is NULL"); - mutex_.unlock(); + FT_LOGE("tbm_surface_h is NULL"); return; } tbm_surface_internal_unref(texture_tbm_surface_); texture_tbm_surface_ = NULL; - mutex_.unlock(); } -void ExternalTextureGL::destructionCallback(void* user_data) { +void ExternalTextureGL::DestructionCallback(void* user_data) { ExternalTextureGL* externalTextureGL = reinterpret_cast(user_data); - externalTextureGL->DestructionTbmSurface(); + externalTextureGL->DestructionTbmSurfaceWithLock(); } diff --git a/shell/platform/tizen/external_texture_gl.h b/shell/platform/tizen/external_texture_gl.h index 2defe2800b382..e0bf689758ecd 100644 --- a/shell/platform/tizen/external_texture_gl.h +++ b/shell/platform/tizen/external_texture_gl.h @@ -6,7 +6,6 @@ #define FLUTTER_SHELL_PLATFORM_TIZEN_EXTERNAL_TEXTURE_GL_H_ #include -#include #include #include #include @@ -29,7 +28,7 @@ class ExternalTextureGL { /** * Returns the unique id for the ExternalTextureGL instance. */ - int64_t texture_id() { return (int64_t)texture_id_; } + int64_t TextureId() { return (int64_t)texture_id_; } /** * Accepts texture buffer copy request from the Flutter engine. @@ -43,12 +42,13 @@ class ExternalTextureGL { FlutterOpenGLTexture* opengl_texture); bool OnFrameAvailable(tbm_surface_h tbm_surface); void DestructionTbmSurface(); + void DestructionTbmSurfaceWithLock(); private: std::unique_ptr state_; std::mutex mutex_; tbm_surface_h texture_tbm_surface_; - static void destructionCallback(void* user_data); + static void DestructionCallback(void* user_data); const long texture_id_; }; diff --git a/shell/platform/tizen/flutter_tizen.cc b/shell/platform/tizen/flutter_tizen.cc index a945cb3776ef2..7810bcf9095c0 100644 --- a/shell/platform/tizen/flutter_tizen.cc +++ b/shell/platform/tizen/flutter_tizen.cc @@ -6,13 +6,15 @@ #include "public/flutter_tizen.h" #include +#include + #include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h" -#include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h" #include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/standard_message_codec.h" -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h" +#include "flutter/shell/platform/tizen/public/flutter_platform_view.h" #include "flutter/shell/platform/tizen/public/flutter_texture_registrar.h" #include "flutter/shell/platform/tizen/tizen_embedder_engine.h" -#include "flutter/shell/platform/tizen/public/flutter_platform_view.h" +#include "flutter/shell/platform/tizen/tizen_log.h" // Opaque reference to a Tizen embedder engine. struct FlutterWindowControllerState { @@ -44,28 +46,28 @@ static void* LoggingFunction(void*) { // tools. bool InitializeLogging() { if (logging_thread) { - LoggerD("The logging thread already exists."); + FT_LOGD("The logging thread already exists."); return true; } if (pipe(logging_pipe) < 0) { - LoggerE("Failed to create a pipe."); + FT_LOGE("Failed to create a pipe."); return false; } if (dup2(logging_pipe[1], 1) < 0 || dup2(logging_pipe[1], 2) < 0) { - LoggerE("Failed to duplicate file descriptors."); + FT_LOGE("Failed to duplicate file descriptors."); return false; } if (pthread_create(&logging_thread, 0, LoggingFunction, 0) != 0) { - LoggerE("Failed to create a logging thread."); + FT_LOGE("Failed to create a logging thread."); logging_thread = 0; return false; } if (pthread_detach(logging_thread) != 0) { - LoggerE("Failed to detach the logging thread."); + FT_LOGE("Failed to detach the logging thread."); return false; } return true; @@ -80,7 +82,7 @@ FlutterWindowControllerRef FlutterCreateWindow( state->engine = std::make_unique(window_properties); if (!state->engine->RunEngine(engine_properties)) { - LoggerE("Failed to run the Flutter engine."); + FT_LOGE("Failed to run the Flutter engine."); return nullptr; } @@ -145,7 +147,7 @@ bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger, FlutterEngineResult result = FlutterPlatformMessageCreateResponseHandle( messenger->engine->flutter_engine, reply, user_data, &response_handle); if (result != kSuccess) { - LoggerE("Failed to create response handle"); + FT_LOGE("Failed to create response handle"); return false; } } @@ -219,16 +221,13 @@ void FlutterNotifyLowMemoryWarning(FlutterWindowControllerRef controller) { void FlutterRotateWindow(FlutterWindowControllerRef controller, int32_t degree) { - if (controller->engine) { - controller->engine->SetWindowOrientation(degree); - } } int64_t FlutterRegisterExternalTexture( FlutterTextureRegistrarRef texture_registrar) { - LoggerD("FlutterDesktopRegisterExternalTexture"); + FT_LOGD("FlutterDesktopRegisterExternalTexture"); auto texture_gl = std::make_unique(); - int64_t texture_id = texture_gl->texture_id(); + int64_t texture_id = texture_gl->TextureId(); texture_registrar->textures[texture_id] = std::move(texture_gl); if (FlutterEngineRegisterExternalTexture(texture_registrar->flutter_engine, texture_id) == kSuccess) { @@ -251,12 +250,12 @@ bool FlutterMarkExternalTextureFrameAvailable( void* tbm_surface) { auto it = texture_registrar->textures.find(texture_id); if (it == texture_registrar->textures.end()) { - LoggerE("can't find texture texture_id = %lld", texture_id); + FT_LOGE("can't find texture texture_id = %lld", texture_id); return false; } if (!texture_registrar->textures[texture_id]->OnFrameAvailable( (tbm_surface_h)tbm_surface)) { - LoggerE("OnFrameAvailable fail texture_id = %lld", texture_id); + FT_LOGE("OnFrameAvailable fail texture_id = %lld", texture_id); return false; } return (FlutterEngineMarkExternalTextureFrameAvailable( @@ -266,7 +265,7 @@ bool FlutterMarkExternalTextureFrameAvailable( void FlutterRegisterViewFactory( FlutterDesktopPluginRegistrarRef registrar, const char* view_type, std::unique_ptr view_factory) { - registrar->engine->platform_view_channel->viewFactories().insert( + registrar->engine->platform_view_channel->ViewFactories().insert( std::pair>( view_type, std::move(view_factory))); } diff --git a/shell/platform/tizen/key_event_handler.cc b/shell/platform/tizen/key_event_handler.cc index ced29bc34b345..aab40b1c22906 100644 --- a/shell/platform/tizen/key_event_handler.cc +++ b/shell/platform/tizen/key_event_handler.cc @@ -4,7 +4,6 @@ #include "key_event_handler.h" -#include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_embedder_engine.h" static constexpr char kPlatformBackButtonName[] = "XF86Back"; @@ -40,13 +39,16 @@ Eina_Bool KeyEventHandler::OnKey(void *data, int type, void *event) { if (is_down) { engine->text_input_channel->OnKeyDown(key); } - if (engine->text_input_channel->isSoftwareKeyboardShowing()) { + if (engine->text_input_channel->IsSoftwareKeyboardShowing()) { return ECORE_CALLBACK_PASS_ON; } } if (engine->key_event_channel) { engine->key_event_channel->SendKeyEvent(key, is_down); } + if (engine->platform_view_channel) { + engine->platform_view_channel->SendKeyEvent(key, is_down); + } } return ECORE_CALLBACK_PASS_ON; } diff --git a/shell/platform/tizen/logger.h b/shell/platform/tizen/logger.h deleted file mode 100644 index 1a1be983d277e..0000000000000 --- a/shell/platform/tizen/logger.h +++ /dev/null @@ -1,29 +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_LOGGER_H_ -#define EMBEDDER_LOGGER_H_ -#include - -#include - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "ConsoleMessage" - -#undef LOG_ -#define LOG_(id, prio, tag, fmt, arg...) \ - __dlog_print(id, prio, tag, "%s: %s(%d) > " fmt, __FILE__, __func__, \ - __LINE__, ##arg); - -#define _LOGGER_LOG(prio, fmt, args...) \ - LOG_(LOG_ID_MAIN, prio, LOG_TAG, fmt, ##args) - -#define LoggerD(fmt, args...) _LOGGER_LOG(DLOG_DEBUG, fmt, ##args) -#define LoggerI(fmt, args...) _LOGGER_LOG(DLOG_INFO, fmt, ##args) -#define LoggerW(fmt, args...) _LOGGER_LOG(DLOG_WARN, fmt, ##args) -#define LoggerE(fmt, args...) _LOGGER_LOG(DLOG_ERROR, fmt, ##args) - -#endif // EMBEDDER_LOGGER_H_ diff --git a/shell/platform/tizen/public/flutter_platform_view.h b/shell/platform/tizen/public/flutter_platform_view.h index b86b2f9ccccb9..6201cf2840b6a 100644 --- a/shell/platform/tizen/public/flutter_platform_view.h +++ b/shell/platform/tizen/public/flutter_platform_view.h @@ -5,6 +5,8 @@ #ifndef FLUTTER_SHELL_PLATFORM_TIZEN_PUBLIC_FLUTTER_PLATFORM_VIEW_H_ #define FLUTTER_SHELL_PLATFORM_TIZEN_PUBLIC_FLUTTER_PLATFORM_VIEW_H_ +#include +#include #include #include @@ -15,22 +17,35 @@ using ByteMessage = std::vector; class PlatformView { public: PlatformView(flutter::PluginRegistrar* registrar, int viewId) - : registrar_(registrar), viewId_(viewId), textureId_(0) {} + : registrar_(registrar), + viewId_(viewId), + textureId_(0), + isFocused_(false) {} virtual ~PlatformView() {} - int getViewId() { return viewId_; } - int getTextureId() { return textureId_; } - void setTextureId(int textureId) { textureId_ = textureId; } - flutter::PluginRegistrar* getPluginRegistrar() { return registrar_; } - virtual void dispose() = 0; - virtual void resize(double width, double height) = 0; - virtual void touch() = 0; - virtual void setDirection(int direction) = 0; - virtual void clearFocus() = 0; + int GetViewId() { return viewId_; } + int GetTextureId() { return textureId_; } + void SetTextureId(int textureId) { textureId_ = textureId; } + flutter::PluginRegistrar* GetPluginRegistrar() { return registrar_; } + virtual void Dispose() = 0; + virtual void Resize(double width, double height) = 0; + virtual void Touch(int type, int button, double x, double y, double dx, + double dy) = 0; + virtual void SetDirection(int direction) = 0; + virtual void ClearFocus() = 0; + void SetFocus(bool f) { isFocused_ = f; } + bool IsFocused() { return isFocused_; } + + // Key input event + virtual void DispatchKeyDownEvent(Ecore_Event_Key* key) = 0; + virtual void DispatchKeyUpEvent(Ecore_Event_Key* key) = 0; + + virtual void SetSoftwareKeyboardContext(Ecore_IMF_Context* context) = 0; private: flutter::PluginRegistrar* registrar_; int viewId_; int textureId_; + bool isFocused_; }; class PlatformViewFactory { @@ -39,13 +54,13 @@ class PlatformViewFactory { : registrar_(registrar), codec_(flutter::StandardMessageCodec::GetInstance(nullptr)) {} virtual ~PlatformViewFactory() {} - flutter::PluginRegistrar* getPluginRegistrar() { return registrar_; } - const flutter::MessageCodec& getCodec() { + flutter::PluginRegistrar* GetPluginRegistrar() { return registrar_; } + const flutter::MessageCodec& GetCodec() { return codec_; } - virtual PlatformView* create(int viewId, double width, double height, + virtual PlatformView* Create(int viewId, double width, double height, const ByteMessage& createParams) = 0; - virtual void dispose() = 0; + virtual void Dispose() = 0; private: flutter::PluginRegistrar* registrar_; diff --git a/shell/platform/tizen/tizen_embedder_engine.cc b/shell/platform/tizen/tizen_embedder_engine.cc index cebf3f6ae6b97..b62a93891c634 100644 --- a/shell/platform/tizen/tizen_embedder_engine.cc +++ b/shell/platform/tizen/tizen_embedder_engine.cc @@ -11,16 +11,39 @@ #include #include -#include "flutter/shell/platform/tizen/logger.h" +#include "flutter/shell/platform/tizen/tizen_log.h" // Unique number associated with platform tasks. static constexpr size_t kPlatformTaskRunnerIdentifier = 1; +static std::string GetDeviceProfile() { + char* feature_profile; + system_info_get_platform_string("http://tizen.org/feature/profile", + &feature_profile); + std::string profile(feature_profile); + free(feature_profile); + return profile; +} + +static double GetDeviceDpi() { + int feature_dpi; + system_info_get_platform_int("http://tizen.org/feature/screen.dpi", + &feature_dpi); + return (double)feature_dpi; +} + TizenEmbedderEngine::TizenEmbedderEngine( - const FlutterWindowProperties& window_properties) { - tizen_surface = std::make_unique( - window_properties.x, window_properties.y, window_properties.width, + const FlutterWindowProperties& window_properties) + : device_profile(GetDeviceProfile()), device_dpi(GetDeviceDpi()) { +#ifdef FLUTTER_TIZEN_4 + tizen_renderer = std::make_unique( + *this, window_properties.x, window_properties.y, window_properties.width, + window_properties.height); +#else + tizen_renderer = std::make_unique( + *this, window_properties.x, window_properties.y, window_properties.width, window_properties.height); +#endif // Run flutter task on Tizen main loop. // Tizen engine has four threads (GPU thread, UI thread, IO thread, platform @@ -29,7 +52,7 @@ TizenEmbedderEngine::TizenEmbedderEngine( std::this_thread::get_id(), // main thread [this](const auto* task) { if (FlutterEngineRunTask(this->flutter_engine, task) != kSuccess) { - LoggerE("Could not post an engine task."); + FT_LOGE("Could not post an engine task."); } }); @@ -38,21 +61,24 @@ TizenEmbedderEngine::TizenEmbedderEngine( message_dispatcher = std::make_unique(messenger.get()); - tizen_vsync_waiter_ = std::make_unique(); + tizen_vsync_waiter_ = std::make_unique(this); } -TizenEmbedderEngine::~TizenEmbedderEngine() {} +TizenEmbedderEngine::~TizenEmbedderEngine() { + FT_LOGD("Destroy"); + tizen_renderer = nullptr; +} // Attempts to load AOT data from the given path, which must be absolute and // non-empty. Logs and returns nullptr on failure. UniqueAotDataPtr LoadAotData(std::string aot_data_path) { if (aot_data_path.empty()) { - LoggerE( + FT_LOGE( "Attempted to load AOT data, but no aot_library_path was provided."); return nullptr; } if (!std::filesystem::exists(aot_data_path)) { - LoggerE("Can't load AOT data from %s; no such file.", + FT_LOGE("Can't load AOT data from %s; no such file.", aot_data_path.c_str()); return nullptr; } @@ -62,7 +88,7 @@ UniqueAotDataPtr LoadAotData(std::string aot_data_path) { FlutterEngineAOTData data = nullptr; auto result = FlutterEngineCreateAOTData(&source, &data); if (result != kSuccess) { - LoggerE("Failed to load AOT data from: %s", aot_data_path.c_str()); + FT_LOGE("Failed to load AOT data from: %s", aot_data_path.c_str()); return nullptr; } return UniqueAotDataPtr(data); @@ -70,8 +96,8 @@ UniqueAotDataPtr LoadAotData(std::string aot_data_path) { bool TizenEmbedderEngine::RunEngine( const FlutterEngineProperties& engine_properties) { - if (!tizen_surface->IsValid()) { - LoggerE("The display was not valid."); + if (!tizen_renderer->IsValid()) { + FT_LOGE("The display was not valid."); return false; } @@ -127,7 +153,7 @@ bool TizenEmbedderEngine::RunEngine( if (FlutterEngineRunsAOTCompiledDartCode()) { aot_data_ = LoadAotData(engine_properties.aot_library_path); if (!aot_data_) { - LoggerE("Unable to start engine without AOT data."); + FT_LOGE("Unable to start engine without AOT data."); return false; } args.aot_data = aot_data_.get(); @@ -136,14 +162,12 @@ bool TizenEmbedderEngine::RunEngine( auto result = FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, &args, this, &flutter_engine); if (result == kSuccess && flutter_engine != nullptr) { - LoggerI("FlutterEngineRun Success!"); + FT_LOGD("FlutterEngineRun Success!"); } else { - LoggerE("FlutterEngineRun Failure! result: %d", result); + FT_LOGE("FlutterEngineRun Failure! result: %d", result); return false; } - tizen_vsync_waiter_->AsyncWaitForRunEngineSuccess(flutter_engine); - std::unique_ptr textures = std::make_unique(); textures->flutter_engine = flutter_engine; @@ -163,24 +187,29 @@ bool TizenEmbedderEngine::RunEngine( settings_channel = std::make_unique( internal_plugin_registrar_->messenger()); text_input_channel = std::make_unique( - internal_plugin_registrar_->messenger(), - ((TizenSurfaceGL*)tizen_surface.get())->wl2_window()); + internal_plugin_registrar_->messenger(), this); localization_channel = std::make_unique(flutter_engine); localization_channel->SendLocales(); lifecycle_channel = std::make_unique(flutter_engine); platform_view_channel = std::make_unique( - internal_plugin_registrar_->messenger()); + internal_plugin_registrar_->messenger(), this); key_event_handler_ = std::make_unique(this); touch_event_handler_ = std::make_unique(this); SetWindowOrientation(0); - return true; } +void TizenEmbedderEngine::OnRotationChange(int angle) { + SetWindowOrientation(angle); +} + bool TizenEmbedderEngine::StopEngine() { if (flutter_engine) { + if (platform_view_channel) { + platform_view_channel->Dispose(); + } if (plugin_registrar_destruction_callback_) { plugin_registrar_destruction_callback_(plugin_registrar_.get()); } @@ -210,22 +239,6 @@ bool TizenEmbedderEngine::OnAcquireExternalTexture( ->PopulateTextureWithIdentifier(width, height, texture); } -std::string GetDeviceProfile() { - char* feature_profile; - system_info_get_platform_string("http://tizen.org/feature/profile", - &feature_profile); - std::string profile(feature_profile); - free(feature_profile); - return profile; -} - -double GetDeviceDpi() { - int feature_dpi; - system_info_get_platform_int("http://tizen.org/feature/screen.dpi", - &feature_dpi); - return (double)feature_dpi; -} - void TizenEmbedderEngine::SendWindowMetrics(int32_t width, int32_t height, double pixel_ratio) { FlutterWindowMetricsEvent event; @@ -236,16 +249,15 @@ void TizenEmbedderEngine::SendWindowMetrics(int32_t width, int32_t height, // 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 - std::string profile = GetDeviceProfile(); double profile_factor = 1.0; - if (profile == "wearable") { + if (device_profile == "wearable") { profile_factor = 0.4; - } else if (profile == "mobile") { + } else if (device_profile == "mobile") { profile_factor = 0.7; - } else if (profile == "tv") { + } else if (device_profile == "tv") { profile_factor = 2.0; } - double dpi = profile == "tv" ? 72.0 : GetDeviceDpi(); + double dpi = device_profile == "tv" ? 72.0 : device_dpi; double scale_factor = dpi / 90.0 * profile_factor; event.pixel_ratio = std::max(scale_factor, 1.0); } else { @@ -257,14 +269,17 @@ void TizenEmbedderEngine::SendWindowMetrics(int32_t width, int32_t height, // This must be called at least once in order to initialize the value of // transformation_. void TizenEmbedderEngine::SetWindowOrientation(int32_t degree) { - if (!tizen_surface) { + if (!tizen_renderer) { return; } + tizen_renderer->SetRotate(degree); // Compute renderer transformation based on the angle of rotation. double rad = (360 - degree) * M_PI / 180; - double width = tizen_surface->GetWidth(); - double height = tizen_surface->GetHeight(); + auto geometry = tizen_renderer->GetGeometry(); + double width = geometry.w; + double height = geometry.h; + double trans_x = 0.0, trans_y = 0.0; if (degree == 90) { trans_y = height; @@ -280,10 +295,14 @@ void TizenEmbedderEngine::SetWindowOrientation(int32_t degree) { 0.0, 0.0, 1.0 // perspective }; touch_event_handler_->rotation = degree; - + text_input_channel->rotation = degree; if (degree == 90 || degree == 270) { + tizen_renderer->ResizeWithRotation(geometry.x, geometry.y, height, width, + degree); SendWindowMetrics(height, width, 0.0); } else { + tizen_renderer->ResizeWithRotation(geometry.x, geometry.y, width, height, + degree); SendWindowMetrics(width, height, 0.0); } } @@ -305,11 +324,11 @@ void TizenEmbedderEngine::AppIsDetached() { void TizenEmbedderEngine::OnFlutterPlatformMessage( const FlutterPlatformMessage* engine_message, void* user_data) { if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { - LoggerE("Invalid message size received. Expected: %zu, received %zu", + FT_LOGE("Invalid message size received. Expected: %zu, received %zu", sizeof(FlutterPlatformMessage), engine_message->struct_size); return; } - LoggerD("%s", engine_message->channel); + FT_LOGD("%s", engine_message->channel); TizenEmbedderEngine* tizen_embedder_engine = reinterpret_cast(user_data); auto message = @@ -337,27 +356,27 @@ FlutterDesktopMessage TizenEmbedderEngine::ConvertToDesktopMessage( bool TizenEmbedderEngine::MakeContextCurrent(void* user_data) { return reinterpret_cast(user_data) - ->tizen_surface->OnMakeCurrent(); + ->tizen_renderer->OnMakeCurrent(); } bool TizenEmbedderEngine::ClearContext(void* user_data) { return reinterpret_cast(user_data) - ->tizen_surface->OnClearCurrent(); + ->tizen_renderer->OnClearCurrent(); } bool TizenEmbedderEngine::Present(void* user_data) { return reinterpret_cast(user_data) - ->tizen_surface->OnPresent(); + ->tizen_renderer->OnPresent(); } bool TizenEmbedderEngine::MakeResourceCurrent(void* user_data) { return reinterpret_cast(user_data) - ->tizen_surface->OnMakeResourceCurrent(); + ->tizen_renderer->OnMakeResourceCurrent(); } uint32_t TizenEmbedderEngine::GetActiveFbo(void* user_data) { return reinterpret_cast(user_data) - ->tizen_surface->OnGetFBO(); + ->tizen_renderer->OnGetFBO(); } FlutterTransformation TizenEmbedderEngine::Transformation(void* user_data) { @@ -366,5 +385,5 @@ FlutterTransformation TizenEmbedderEngine::Transformation(void* user_data) { void* TizenEmbedderEngine::GlProcResolver(void* user_data, const char* name) { return reinterpret_cast(user_data) - ->tizen_surface->OnProcResolver(name); + ->tizen_renderer->OnProcResolver(name); } diff --git a/shell/platform/tizen/tizen_embedder_engine.h b/shell/platform/tizen/tizen_embedder_engine.h index d7156d6074c34..e96f49e6647d8 100644 --- a/shell/platform/tizen/tizen_embedder_engine.h +++ b/shell/platform/tizen/tizen_embedder_engine.h @@ -23,8 +23,12 @@ #include "flutter/shell/platform/tizen/public/flutter_texture_registrar.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_surface.h" -#include "flutter/shell/platform/tizen/tizen_surface_gl.h" +#include "flutter/shell/platform/tizen/tizen_renderer.h" +#ifdef FLUTTER_TIZEN_4 +#include "flutter/shell/platform/tizen/tizen_renderer_ecore_wl.h" +#else +#include "flutter/shell/platform/tizen/tizen_renderer_ecore_wl2.h" +#endif #include "flutter/shell/platform/tizen/tizen_vsync_waiter.h" #include "flutter/shell/platform/tizen/touch_event_handler.h" @@ -61,7 +65,7 @@ struct FlutterTextureRegistrar { using UniqueAotDataPtr = std::unique_ptr<_FlutterEngineAOTData, AOTDataDeleter>; // Manages state associated with the underlying FlutterEngine. -class TizenEmbedderEngine { +class TizenEmbedderEngine : public TizenRenderer::Delegate { public: explicit TizenEmbedderEngine( const FlutterWindowProperties& window_properties); @@ -76,12 +80,14 @@ class TizenEmbedderEngine { void SetPluginRegistrarDestructionCallback( FlutterDesktopOnPluginRegistrarDestroyed callback); + void SendWindowMetrics(int32_t width, int32_t height, double pixel_ratio); void SetWindowOrientation(int32_t degree); void SendLocales(); void AppIsInactive(); void AppIsResumed(); void AppIsPaused(); void AppIsDetached(); + void OnRotationChange(int degree) override; // The Flutter engine instance. FLUTTER_API_SYMBOL(FlutterEngine) flutter_engine; @@ -93,7 +99,7 @@ class TizenEmbedderEngine { std::unique_ptr message_dispatcher; // The interface between the Flutter rasterizer and the platform. - std::unique_ptr tizen_surface; + std::unique_ptr tizen_renderer; // The system channels for communicating between Flutter and the platform. std::unique_ptr key_event_channel; @@ -105,6 +111,9 @@ class TizenEmbedderEngine { std::unique_ptr text_input_channel; std::unique_ptr platform_view_channel; + const std::string device_profile; + const double device_dpi; + private: static bool MakeContextCurrent(void* user_data); static bool ClearContext(void* user_data); @@ -117,7 +126,6 @@ class TizenEmbedderEngine { const FlutterPlatformMessage* engine_message, void* user_data); static void OnVsyncCallback(void* user_data, intptr_t baton); - void SendWindowMetrics(int32_t width, int32_t height, double pixel_ratio); FlutterDesktopMessage ConvertToDesktopMessage( const FlutterPlatformMessage& engine_message); static bool OnAcquireExternalTexture(void* user_data, int64_t texture_id, @@ -134,7 +142,7 @@ class TizenEmbedderEngine { // A callback to be called when the engine (and thus the plugin registrar) // is being destroyed. FlutterDesktopOnPluginRegistrarDestroyed - plugin_registrar_destruction_callback_; + plugin_registrar_destruction_callback_{nullptr}; // The plugin registrar managing internal plugins. std::unique_ptr internal_plugin_registrar_; diff --git a/shell/platform/tizen/tizen_log.h b/shell/platform/tizen/tizen_log.h new file mode 100644 index 0000000000000..f26814dccb046 --- /dev/null +++ b/shell/platform/tizen/tizen_log.h @@ -0,0 +1,65 @@ +// 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_LOG_H_ +#define EMBEDDER_TIZEN_LOG_H_ +#include + +#include +#include +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "ConsoleMessage" + +#undef __LOG +#define __LOG(id, prio, tag, fmt, arg...) \ + __dlog_print(id, prio, tag, "%s: %s(%d) > " fmt, __FILE__, __func__, \ + __LINE__, ##arg); + +#define __FT_LOG(prio, fmt, args...) \ + __LOG(LOG_ID_MAIN, prio, LOG_TAG, fmt, ##args) + +#define FT_LOGD(fmt, args...) __FT_LOG(DLOG_DEBUG, fmt, ##args) +#define FT_LOGI(fmt, args...) __FT_LOG(DLOG_INFO, fmt, ##args) +#define FT_LOGW(fmt, args...) __FT_LOG(DLOG_WARN, fmt, ##args) +#define FT_LOGE(fmt, args...) __FT_LOG(DLOG_ERROR, fmt, ##args) + +#if defined(NDEBUG) +#define FT_ASSERT(assertion) ((void)0) +#define FT_ASSERT_NOT_REACHED() ((void)0) +#define FT_ASSERT_STATIC(assertion, reason) +#else +#define FT_ASSERT(assertion) assert(assertion); +#define FT_ASSERT_NOT_REACHED() \ + do { \ + assert(false); \ + } while (0) +#define FT_ASSERT_STATIC(assertion, reason) static_assert(assertion, reason) +#endif + +#define FT_RELEASE_ASSERT(assertion) \ + do { \ + if (!(assertion)) { \ + FT_LOGE("RELEASE_ASSERT"); \ + abort(); \ + } \ + } while (0); + +#define FT_RELEASE_ASSERT_NOT_REACHED() \ + do { \ + FT_LOGE("RELEASE_ASSERT_NOT_REACHED"); \ + abort(); \ + } while (0) + +/* COMPILE_ASSERT */ +#ifndef FT_COMPILE_ASSERT +#define FT_COMPILE_ASSERT(exp, name) static_assert((exp), #name) +#endif + +#define FT_LOGD_UNIMPLEMENTED() FT_LOGD("UNIMPLEMENTED") + +#endif // EMBEDDER_TIZEN_LOG_H_ diff --git a/shell/platform/tizen/tizen_renderer.cc b/shell/platform/tizen/tizen_renderer.cc new file mode 100644 index 0000000000000..1354a7648b119 --- /dev/null +++ b/shell/platform/tizen/tizen_renderer.cc @@ -0,0 +1,460 @@ +// 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 "tizen_renderer.h" + +#include +#include + +#include "flutter/shell/platform/tizen/tizen_log.h" + +TizenRenderer::TizenRenderer(TizenRenderer::Delegate& delegate) + : delegate_(delegate) {} + +TizenRenderer::~TizenRenderer() = default; + +bool TizenRenderer::OnMakeCurrent() { + if (!IsValid()) { + FT_LOGE("Invalid TizenRenderer"); + return false; + } + if (eglMakeCurrent(egl_display_, egl_surface_, egl_surface_, egl_context_) != + EGL_TRUE) { + FT_LOGE("Could not make the onscreen context current"); + PrintEGLError(); + return false; + } + return true; +} + +bool TizenRenderer::OnClearCurrent() { + if (!IsValid()) { + FT_LOGE("Invalid TizenRenderer"); + return false; + } + if (eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT) != EGL_TRUE) { + FT_LOGE("Could not clear context"); + PrintEGLError(); + return false; + } + return true; +} + +bool TizenRenderer::OnMakeResourceCurrent() { + if (!IsValid()) { + FT_LOGE("Invalid TizenRenderer"); + return false; + } + if (eglMakeCurrent(egl_display_, egl_resource_surface_, egl_resource_surface_, + egl_resource_context_) != EGL_TRUE) { + FT_LOGE("Could not make the offscreen context current"); + PrintEGLError(); + return false; + } + return true; +} + +bool TizenRenderer::OnPresent() { + if (!is_valid_) { + FT_LOGE("Invalid TizenRenderer"); + return false; + } + + if (received_rotation) { + SendRotationChangeDone(); + received_rotation = false; + } + + if (eglSwapBuffers(egl_display_, egl_surface_) != EGL_TRUE) { + FT_LOGE("Could not swap EGl buffer"); + PrintEGLError(); + return false; + } + return true; +} + +uint32_t TizenRenderer::OnGetFBO() { + if (!is_valid_) { + FT_LOGE("Invalid TizenRenderer"); + return 999; + } + FT_LOGD("OnGetFBO"); + return 0; +} + +#define GL_FUNC(FunctionName) \ + else if (strcmp(name, #FunctionName) == 0) { \ + return reinterpret_cast(FunctionName); \ + } +void* TizenRenderer::OnProcResolver(const char* name) { + auto address = eglGetProcAddress(name); + if (address != nullptr) { + return reinterpret_cast(address); + } + GL_FUNC(eglGetCurrentDisplay) + GL_FUNC(eglQueryString) + GL_FUNC(glActiveTexture) + GL_FUNC(glAttachShader) + GL_FUNC(glBindAttribLocation) + GL_FUNC(glBindBuffer) + GL_FUNC(glBindFramebuffer) + GL_FUNC(glBindRenderbuffer) + GL_FUNC(glBindTexture) + GL_FUNC(glBlendColor) + GL_FUNC(glBlendEquation) + GL_FUNC(glBlendFunc) + GL_FUNC(glBufferData) + GL_FUNC(glBufferSubData) + GL_FUNC(glCheckFramebufferStatus) + GL_FUNC(glClear) + GL_FUNC(glClearColor) + GL_FUNC(glClearStencil) + GL_FUNC(glColorMask) + GL_FUNC(glCompileShader) + GL_FUNC(glCompressedTexImage2D) + GL_FUNC(glCompressedTexSubImage2D) + GL_FUNC(glCopyTexSubImage2D) + GL_FUNC(glCreateProgram) + GL_FUNC(glCreateShader) + GL_FUNC(glCullFace) + GL_FUNC(glDeleteBuffers) + GL_FUNC(glDeleteFramebuffers) + GL_FUNC(glDeleteProgram) + GL_FUNC(glDeleteRenderbuffers) + GL_FUNC(glDeleteShader) + GL_FUNC(glDeleteTextures) + GL_FUNC(glDepthMask) + GL_FUNC(glDisable) + GL_FUNC(glDisableVertexAttribArray) + GL_FUNC(glDrawArrays) + GL_FUNC(glDrawElements) + GL_FUNC(glEnable) + GL_FUNC(glEnableVertexAttribArray) + GL_FUNC(glFinish) + GL_FUNC(glFlush) + GL_FUNC(glFramebufferRenderbuffer) + GL_FUNC(glFramebufferTexture2D) + GL_FUNC(glFrontFace) + GL_FUNC(glGenBuffers) + GL_FUNC(glGenerateMipmap) + GL_FUNC(glGenFramebuffers) + GL_FUNC(glGenRenderbuffers) + GL_FUNC(glGenTextures) + GL_FUNC(glGetBufferParameteriv) + GL_FUNC(glGetError) + GL_FUNC(glGetFramebufferAttachmentParameteriv) + GL_FUNC(glGetIntegerv) + GL_FUNC(glGetProgramInfoLog) + GL_FUNC(glGetProgramiv) + GL_FUNC(glGetRenderbufferParameteriv) + GL_FUNC(glGetShaderInfoLog) + GL_FUNC(glGetShaderiv) + GL_FUNC(glGetShaderPrecisionFormat) + GL_FUNC(glGetString) + GL_FUNC(glGetUniformLocation) + GL_FUNC(glIsTexture) + GL_FUNC(glLineWidth) + GL_FUNC(glLinkProgram) + GL_FUNC(glPixelStorei) + GL_FUNC(glReadPixels) + GL_FUNC(glRenderbufferStorage) + GL_FUNC(glScissor) + GL_FUNC(glShaderSource) + GL_FUNC(glStencilFunc) + GL_FUNC(glStencilFuncSeparate) + GL_FUNC(glStencilMask) + GL_FUNC(glStencilMaskSeparate) + GL_FUNC(glStencilOp) + GL_FUNC(glStencilOpSeparate) + GL_FUNC(glTexImage2D) + GL_FUNC(glTexParameterf) + GL_FUNC(glTexParameterfv) + GL_FUNC(glTexParameteri) + GL_FUNC(glTexParameteriv) + GL_FUNC(glTexSubImage2D) + GL_FUNC(glUniform1f) + GL_FUNC(glUniform1fv) + GL_FUNC(glUniform1i) + GL_FUNC(glUniform1iv) + GL_FUNC(glUniform2f) + GL_FUNC(glUniform2fv) + GL_FUNC(glUniform2i) + GL_FUNC(glUniform2iv) + GL_FUNC(glUniform3f) + GL_FUNC(glUniform3fv) + GL_FUNC(glUniform3i) + GL_FUNC(glUniform3iv) + GL_FUNC(glUniform4f) + GL_FUNC(glUniform4fv) + GL_FUNC(glUniform4i) + GL_FUNC(glUniform4iv) + GL_FUNC(glUniformMatrix2fv) + GL_FUNC(glUniformMatrix3fv) + GL_FUNC(glUniformMatrix4fv) + GL_FUNC(glUseProgram) + GL_FUNC(glVertexAttrib1f) + GL_FUNC(glVertexAttrib2fv) + GL_FUNC(glVertexAttrib3fv) + GL_FUNC(glVertexAttrib4fv) + GL_FUNC(glVertexAttribPointer) + GL_FUNC(glViewport) + + FT_LOGW("Could not resolve: %s", name); + return nullptr; +} +#undef GL_FUNC + +bool TizenRenderer::InitializeRenderer(int32_t x, int32_t y, int32_t w, + int32_t h) { + if (!SetupDisplay()) { + FT_LOGE("setupDisplay fail"); + return false; + } + if (!SetupEcoreWlWindow(x, y, w, h)) { + FT_LOGE("SetupEcoreWlWindow fail"); + return false; + } + + if (!SetupEglWindow(w, h)) { + FT_LOGE("SetupEglWindow fail"); + return false; + } + + if (!SetupEglSurface()) { + FT_LOGE("setupEglSurface fail"); + return false; + } + Show(); + is_valid_ = true; + return true; +} + +bool TizenRenderer::IsValid() { return is_valid_; } + +bool TizenRenderer::SetupEglSurface() { + if (!ChooseEGLConfiguration()) { + FT_LOGE("ChooseEGLConfiguration fail"); + return false; + } + const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + egl_context_ = eglCreateContext(egl_display_, egl_config_, EGL_NO_CONTEXT, + contextAttribs); + if (EGL_NO_CONTEXT == egl_context_) { + PrintEGLError(); + return false; + } + + egl_resource_context_ = + eglCreateContext(egl_display_, egl_config_, egl_context_, contextAttribs); + if (EGL_NO_CONTEXT == egl_resource_context_) { + PrintEGLError(); + return false; + } + EGLint* ptr = nullptr; + const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + egl_surface_ = eglCreateWindowSurface(egl_display_, egl_config_, + GetEGLNativeWindowType(), ptr); + if (egl_surface_ == EGL_NO_SURFACE) { + FT_LOGE("eglCreateWindowSurface failed"); + return false; + } + egl_resource_surface_ = + eglCreatePbufferSurface(egl_display_, egl_config_, attribs); + if (egl_resource_surface_ == EGL_NO_SURFACE) { + FT_LOGE("eglCreatePbufferSurface is Failed"); + return false; + } + return true; +} + +bool TizenRenderer::ChooseEGLConfiguration() { + // egl CONTEXT + EGLint configAttribs[] = { + // 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 + }; + + EGLint major = 0; + EGLint minor = 0; + int bufferSize = 32; + egl_display_ = GetEGLDisplay(); + if (EGL_NO_DISPLAY == egl_display_) { + FT_LOGE("EGL Get Display is failed"); + return false; + } + + if (!eglInitialize(egl_display_, &major, &minor)) { + FT_LOGE("EGL Intialize is Failed major [%d] minor [%d]", major, minor); + PrintEGLError(); + return false; + } + + if (!eglBindAPI(EGL_OPENGL_ES_API)) { + PrintEGLError(); + return false; + } + + EGLint numOfConfig = 0; + // Query all framebuffer configurations + if (!eglGetConfigs(egl_display_, NULL, 0, &numOfConfig)) { + FT_LOGE("eglGetConfigs is Failed!!"); + PrintEGLError(); + return false; + } + EGLConfig* configs = (EGLConfig*)calloc(numOfConfig, sizeof(EGLConfig)); + EGLint n; + // Get the List of EGL framebuffer configuration matches with configAttribs in + // list "configs" + if (!eglChooseConfig(egl_display_, configAttribs, configs, numOfConfig, &n)) { + free(configs); + configs = NULL; + PrintEGLError(); + return false; + } + + EGLint size; + for (int i = 0; i < n; i++) { + eglGetConfigAttrib(egl_display_, configs[i], EGL_BUFFER_SIZE, &size); + if (bufferSize == size) { + egl_config_ = configs[i]; + break; + } + } + free(configs); + configs = NULL; + return true; +} + +void TizenRenderer::PrintEGLError() { + EGLint error = eglGetError(); + switch (error) { + case EGL_BAD_DISPLAY: { + FT_LOGE("EGL_BAD_DISPLAY : Display is not an EGL display connection"); + break; + } + case EGL_NOT_INITIALIZED: { + FT_LOGE("EGL_NOT_INITIALIZED : Display has not been initialized"); + break; + } + case EGL_BAD_SURFACE: { + FT_LOGE("EGL_BAD_SURFACE : Draw or read is not an EGL surface"); + break; + } + case EGL_BAD_CONTEXT: { + FT_LOGE("EGL_BAD_CONTEXT : Context is not an EGL rendering context"); + break; + } + case EGL_BAD_CONFIG: { + FT_LOGE( + "EGL_BAD_CONFIG : Config is not an EGL frame buffer configuration"); + break; + } + case EGL_BAD_MATCH: { + FT_LOGE( + "EGL_BAD_MATCH : Draw or read are not compatible with context, or if " + "context is set to EGL_NO_CONTEXT and draw or read are not set to " + "EGL_NO_SURFACE, or if draw or read are set to EGL_NO_SURFACE and " + "context is not set to EGL_NO_CONTEXT\n"); + break; + } + case EGL_BAD_ACCESS: { + FT_LOGE("EGL_BAD_ACCESS : Context is current to some other thread"); + break; + } + case EGL_BAD_NATIVE_PIXMAP: { + FT_LOGE( + "EGL_BAD_NATIVE_PIXMAP : A native pixmap underlying either draw or " + "read is no longer valid"); + break; + } + case EGL_BAD_NATIVE_WINDOW: { + FT_LOGE( + "EGL_BAD_NATIVE_WINDOW : A native window underlying either draw or " + "read is no longer valid"); + break; + } + case EGL_BAD_CURRENT_SURFACE: { + FT_LOGE( + "EGL_BAD_CURRENT_SURFACE : The previous context has unflushed " + "commands and the previous surface is no longer valid"); + break; + } + case EGL_BAD_ALLOC: { + FT_LOGE( + "EGL_BAD_ALLOC : Allocation of ancillary buffers for draw or read " + "were delayed until eglMakeCurrent is called, and there are not " + "enough resources to allocate them"); + break; + } + case EGL_CONTEXT_LOST: { + FT_LOGE( + "EGL_CONTEXT_LOST : A power management event has occurred. The " + "application must destroy all contexts and reinitialise OpenGL ES " + "state and objects to continue rendering"); + break; + } + case EGL_BAD_PARAMETER: { + FT_LOGE("Invalid parameter is passed"); + break; + } + case EGL_BAD_ATTRIBUTE: { + FT_LOGE( + "The parameter configAttribs contains an invalid frame buffer " + "configuration attribute or an attribute value that is unrecognized " + "or out of range"); + break; + } + default: { + FT_LOGE("Unknown error with code: %d", error); + break; + } + } +} + +void TizenRenderer::DestoryRenderer() { + DestoryEglSurface(); + DestoryEglWindow(); + DestoryEcoreWlWindow(); + ShutdownDisplay(); +} + +void TizenRenderer::DestoryEglSurface() { + if (EGL_NO_DISPLAY != 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; + } +} diff --git a/shell/platform/tizen/tizen_renderer.h b/shell/platform/tizen/tizen_renderer.h new file mode 100644 index 0000000000000..28079f390770d --- /dev/null +++ b/shell/platform/tizen/tizen_renderer.h @@ -0,0 +1,66 @@ +// 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_H +#define EMBEDDER_TIZEN_RENDERER_H + +#include + +class TizenRenderer { + public: + struct TizenWindowGeometry { + int32_t x{0}, y{0}, w{0}, h{0}; + }; + + class Delegate { + public: + virtual void OnRotationChange(int angle) = 0; + }; + + TizenRenderer(TizenRenderer::Delegate& deleget); + virtual ~TizenRenderer(); + bool OnMakeCurrent(); + bool OnClearCurrent(); + bool OnMakeResourceCurrent(); + bool OnPresent(); + uint32_t OnGetFBO(); + void* OnProcResolver(const char* name); + virtual TizenWindowGeometry GetGeometry() = 0; + bool IsValid(); + virtual void Show() = 0; + virtual void SetRotate(int angle) = 0; + virtual int GetEcoreWindowId() = 0; + virtual void ResizeWithRotation(int32_t x, int32_t y, int32_t width, + int32_t height, int32_t degree) = 0; + + protected: + bool received_rotation{false}; + TizenRenderer::Delegate& delegate_; + bool InitializeRenderer(int32_t x, int32_t y, int32_t w, int32_t h); + virtual bool SetupDisplay() = 0; + virtual bool SetupEcoreWlWindow(int32_t x, int32_t y, int32_t w, + int32_t h) = 0; + virtual bool SetupEglWindow(int32_t w, int32_t h) = 0; + bool SetupEglSurface(); + virtual EGLDisplay GetEGLDisplay() = 0; + virtual EGLNativeWindowType GetEGLNativeWindowType() = 0; + void DestoryRenderer(); + void DestoryEglSurface(); + virtual void DestoryEglWindow() = 0; + virtual void DestoryEcoreWlWindow() = 0; + virtual void ShutdownDisplay() = 0; + virtual void SendRotationChangeDone() = 0; + + private: + bool is_valid_ = false; + EGLConfig egl_config_; + 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; + bool ChooseEGLConfiguration(); + void PrintEGLError(); +}; +#endif //EMBEDDER_TIZEN_RENDERER_H diff --git a/shell/platform/tizen/tizen_renderer_ecore_wl.cc b/shell/platform/tizen/tizen_renderer_ecore_wl.cc new file mode 100644 index 0000000000000..f094d6d776a2d --- /dev/null +++ b/shell/platform/tizen/tizen_renderer_ecore_wl.cc @@ -0,0 +1,132 @@ +// 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 "tizen_renderer_ecore_wl.h" + +#include "flutter/shell/platform/tizen/tizen_log.h" + +TizenRendererEcoreWl::TizenRendererEcoreWl(TizenRenderer::Delegate &delegate, + int32_t x, int32_t y, int32_t w, + int32_t h) + : TizenRenderer(delegate) { + InitializeRenderer(x, y, w, h); +} + +TizenRendererEcoreWl::~TizenRendererEcoreWl() { DestoryRenderer(); } + +bool TizenRendererEcoreWl::SetupDisplay() { + // ecore_wl INIT + if (!ecore_wl_init(NULL)) { + FT_LOGE("Could not initialize ecore_wl"); + return false; + } + wl_display_ = ecore_wl_display_get(); + if (nullptr == wl_display_) { + FT_LOGE("ecore_wl_display_get failed"); + return false; + } + return true; +} + +bool TizenRendererEcoreWl::SetupEcoreWlWindow(int32_t x, int32_t y, int32_t w, + int32_t h) { + if (w == 0 || h == 0) { + FT_LOGE("Failed to create because of the wrong size"); + return false; + } + + ecore_wl_window_ = ecore_wl_window_new( + nullptr, x, y, w, h, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW); + FT_LOGD("ecore_wl_window_: %p", ecore_wl_window_); + if (ecore_wl_window_ == nullptr) { + FT_LOGE("ecore_wl_window_new fail"); + return false; + } + ecore_wl_window_type_set(ecore_wl_window_, ECORE_WL_WINDOW_TYPE_TOPLEVEL); + // ecore_wl_window_alpha_set(ecore_wl_window_, EINA_FALSE); + ecore_wl_window_aux_hint_add(ecore_wl_window_, 0, + "wm.policy.win.user.geometry", "1"); + ecore_wl_window_show(ecore_wl_window_); + int rotations[4] = {0, 90, 180, 270}; + ecore_wl_window_rotation_available_rotations_set( + ecore_wl_window_, rotations, sizeof(rotations) / sizeof(int)); + ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_ROTATE, RotationEventCb, this); + return true; +} + +Eina_Bool TizenRendererEcoreWl::RotationEventCb(void *data, int type, + void *event) { + auto *self = reinterpret_cast(data); + Ecore_Wl_Event_Window_Rotate *ev = + reinterpret_cast(event); + self->delegate_.OnRotationChange(ev->angle); + return ECORE_CALLBACK_PASS_ON; +} + +void TizenRendererEcoreWl::Show() { ecore_wl_window_show(ecore_wl_window_); } +void TizenRendererEcoreWl::SetRotate(int degree) { + ecore_wl_window_rotation_set(ecore_wl_window_, degree); + received_rotation = true; +} + +void TizenRendererEcoreWl::ResizeWithRotation(int32_t x, int32_t y, + int32_t width, int32_t height, + int32_t degree) { + wl_egl_window_set_buffer_transform(wl_egl_window_, degree / 90); + wl_egl_window_set_window_transform(wl_egl_window_, degree / 90); + + if ((degree == 90) || (degree == 270)) + wl_egl_window_resize(wl_egl_window_, height, width, x, y); + else + wl_egl_window_resize(wl_egl_window_, width, height, x, y); +} + +void TizenRendererEcoreWl::SendRotationChangeDone() { + ecore_wl_window_rotation_change_done_send(ecore_wl_window_); +} + +bool TizenRendererEcoreWl::SetupEglWindow(int32_t w, int32_t h) { + wl_egl_window_ = + wl_egl_window_create(ecore_wl_window_surface_get(ecore_wl_window_), w, h); + if (nullptr == wl_egl_window_) { + FT_LOGE("wl_egl_window_create is Failed"); + return false; + } + return true; +} + +EGLDisplay TizenRendererEcoreWl::GetEGLDisplay() { + return eglGetDisplay((EGLNativeDisplayType)wl_display_); +} + +EGLNativeWindowType TizenRendererEcoreWl::GetEGLNativeWindowType() { + return (EGLNativeWindowType)wl_egl_window_; +} + +void TizenRendererEcoreWl::DestoryEglWindow() { + if (wl_egl_window_) { + wl_egl_window_destroy(wl_egl_window_); + wl_egl_window_ = nullptr; + } +} + +void TizenRendererEcoreWl::DestoryEcoreWlWindow() { + if (ecore_wl_window_) { + ecore_wl_window_free(ecore_wl_window_); + ecore_wl_window_ = nullptr; + } +} + +void TizenRendererEcoreWl::ShutdownDisplay() { ecore_wl_shutdown(); } + +TizenRenderer::TizenWindowGeometry TizenRendererEcoreWl::GetGeometry() { + TizenWindowGeometry result; + ecore_wl_window_geometry_get(ecore_wl_window_, &result.x, &result.y, + &result.w, &result.h); + return result; +} + +int TizenRendererEcoreWl::GetEcoreWindowId() { + return ecore_wl_window_id_get(ecore_wl_window_); +} \ No newline at end of file diff --git a/shell/platform/tizen/tizen_renderer_ecore_wl.h b/shell/platform/tizen/tizen_renderer_ecore_wl.h new file mode 100644 index 0000000000000..e0566b971aaf3 --- /dev/null +++ b/shell/platform/tizen/tizen_renderer_ecore_wl.h @@ -0,0 +1,43 @@ +// 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_WL_H +#define EMBEDDER_TIZEN_RENDERER_ECORE_WL_H + +#include +#include + +#include "tizen_renderer.h" +#define EFL_BETA_API_SUPPORT +#include +class TizenRendererEcoreWl : public TizenRenderer { + public: + TizenRendererEcoreWl(TizenRenderer::Delegate& delegate, int32_t x, int32_t y, + int32_t w, int32_t h); + ~TizenRendererEcoreWl(); + TizenRenderer::TizenWindowGeometry GetGeometry() override; + void Show() override; + void SetRotate(int angle) override; + void ResizeWithRotation(int32_t x, int32_t y, int32_t width, int32_t height, + int32_t degree) override; + int GetEcoreWindowId() override; + + protected: + void DestoryEglWindow() override; + void DestoryEcoreWlWindow() override; + EGLDisplay GetEGLDisplay() override; + EGLNativeWindowType GetEGLNativeWindowType() override; + bool SetupDisplay() override; + bool SetupEcoreWlWindow(int32_t x, int32_t y, int32_t w, int32_t h) override; + bool SetupEglWindow(int32_t w, int32_t h) override; + void ShutdownDisplay() override; + void SendRotationChangeDone() override; + + private: + Ecore_Wl_Window* ecore_wl_window_ = nullptr; + wl_egl_window* wl_egl_window_ = nullptr; + wl_display* wl_display_ = nullptr; + static Eina_Bool RotationEventCb(void* data, int type, void* event); +}; +#endif //EMBEDDER_TIZEN_RENDERER_ECORE_WL_H diff --git a/shell/platform/tizen/tizen_renderer_ecore_wl2.cc b/shell/platform/tizen/tizen_renderer_ecore_wl2.cc new file mode 100644 index 0000000000000..d4f14194ff3ec --- /dev/null +++ b/shell/platform/tizen/tizen_renderer_ecore_wl2.cc @@ -0,0 +1,129 @@ +// 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 "tizen_renderer_ecore_wl2.h" + +#include "flutter/shell/platform/tizen/tizen_log.h" + +TizenRendererEcoreWl2::TizenRendererEcoreWl2(TizenRenderer::Delegate &delegate, + int32_t x, int32_t y, int32_t w, + int32_t h) + : TizenRenderer(delegate) { + InitializeRenderer(x, y, w, h); +} + +TizenRendererEcoreWl2::~TizenRendererEcoreWl2() { DestoryRenderer(); } +bool TizenRendererEcoreWl2::SetupDisplay() { + if (!ecore_wl2_init()) { + FT_LOGE("Could not initialize ecore_wl2"); + return false; + } + ecore_wl2_display_ = ecore_wl2_display_connect(nullptr); + if (ecore_wl2_display_ == nullptr) { + FT_LOGE("Disyplay not found"); + return false; + } + FT_LOGD("ecore_wl2_display_: %p", ecore_wl2_display_); + ecore_wl2_sync(); + return true; +} + +bool TizenRendererEcoreWl2::SetupEcoreWlWindow(int32_t x, int32_t y, int32_t w, + int32_t h) { + if (w == 0 || h == 0) { + FT_LOGE("Failed to create because of the wrong size"); + return false; + } + ecore_wl2_window_ = + ecore_wl2_window_new(ecore_wl2_display_, nullptr, x, y, w, h); + ecore_wl2_window_type_set(ecore_wl2_window_, ECORE_WL2_WINDOW_TYPE_TOPLEVEL); + ecore_wl2_window_alpha_set(ecore_wl2_window_, EINA_FALSE); + ecore_wl2_window_position_set(ecore_wl2_window_, x, y); + ecore_wl2_window_aux_hint_add(ecore_wl2_window_, 0, + "wm.policy.win.user.geometry", "1"); + 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; +} + +Eina_Bool TizenRendererEcoreWl2::RotationEventCb(void *data, int type, + void *event) { + auto *self = reinterpret_cast(data); + Ecore_Wl2_Event_Window_Rotation *ev = + reinterpret_cast(event); + self->delegate_.OnRotationChange(ev->angle); + return ECORE_CALLBACK_PASS_ON; +} + +void TizenRendererEcoreWl2::Show() { ecore_wl2_window_show(ecore_wl2_window_); } + +void TizenRendererEcoreWl2::SetRotate(int angle) { + ecore_wl2_window_rotation_set(ecore_wl2_window_, angle); + received_rotation = true; +} + +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); +} + +bool TizenRendererEcoreWl2::SetupEglWindow(int32_t w, int32_t h) { + ecore_wl2_egl_window_ = ecore_wl2_egl_window_create(ecore_wl2_window_, w, h); + return ecore_wl2_egl_window_ != nullptr; +} + +EGLDisplay TizenRendererEcoreWl2::GetEGLDisplay() { + return eglGetDisplay( + (EGLNativeDisplayType)ecore_wl2_display_get(ecore_wl2_display_)); +} + +EGLNativeWindowType TizenRendererEcoreWl2::GetEGLNativeWindowType() { + return (EGLNativeWindowType)ecore_wl2_egl_window_native_get( + ecore_wl2_egl_window_); +} + +void TizenRendererEcoreWl2::DestoryEglWindow() { + if (ecore_wl2_egl_window_) { + ecore_wl2_egl_window_destroy(ecore_wl2_egl_window_); + ecore_wl2_egl_window_ = nullptr; + } +} + +void TizenRendererEcoreWl2::DestoryEcoreWlWindow() { + if (ecore_wl2_window_) { + ecore_wl2_window_free(ecore_wl2_window_); + ecore_wl2_window_ = nullptr; + } +} + +void TizenRendererEcoreWl2::ShutdownDisplay() { + if (ecore_wl2_display_) { + ecore_wl2_display_disconnect(ecore_wl2_display_); + ecore_wl2_display_ = nullptr; + } + ecore_wl2_shutdown(); +} + +TizenRenderer::TizenWindowGeometry TizenRendererEcoreWl2::GetGeometry() { + TizenWindowGeometry result; + ecore_wl2_window_geometry_get(ecore_wl2_window_, &result.x, &result.y, + &result.w, &result.h); + return result; +} + +int TizenRendererEcoreWl2::GetEcoreWindowId() { + return ecore_wl2_window_id_get(ecore_wl2_window_); +} diff --git a/shell/platform/tizen/tizen_renderer_ecore_wl2.h b/shell/platform/tizen/tizen_renderer_ecore_wl2.h new file mode 100644 index 0000000000000..5fe84c162dcc9 --- /dev/null +++ b/shell/platform/tizen/tizen_renderer_ecore_wl2.h @@ -0,0 +1,42 @@ +// 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 + +#include "tizen_renderer.h" + +#define EFL_BETA_API_SUPPORT +#include + +class TizenRendererEcoreWl2 : public TizenRenderer { + public: + TizenRendererEcoreWl2(TizenRenderer::Delegate &delegate, int32_t x, int32_t y, + int32_t w, int32_t h); + ~TizenRendererEcoreWl2(); + TizenWindowGeometry GetGeometry() override; + int GetEcoreWindowId() override; + void ResizeWithRotation(int32_t x, int32_t y, int32_t width, int32_t height, + int32_t angle) override; + void Show() override; + void SetRotate(int angle) override; + + protected: + void DestoryEglWindow() override; + void DestoryEcoreWlWindow() override; + EGLDisplay GetEGLDisplay() override; + EGLNativeWindowType GetEGLNativeWindowType() override; + bool SetupDisplay() override; + bool SetupEcoreWlWindow(int32_t x, int32_t y, int32_t w, int32_t h) override; + bool SetupEglWindow(int32_t w, int32_t h) override; + void ShutdownDisplay() override; + void SendRotationChangeDone() override; + + private: + Ecore_Wl2_Display *ecore_wl2_display_ = nullptr; + Ecore_Wl2_Window *ecore_wl2_window_ = nullptr; + Ecore_Wl2_Egl_Window *ecore_wl2_egl_window_ = nullptr; + static Eina_Bool RotationEventCb(void *data, int type, void *event); +}; +#endif //EMBEDDER_TIZEN_RENDERER_ECORE_WL2_H diff --git a/shell/platform/tizen/tizen_surface.cc b/shell/platform/tizen/tizen_surface.cc deleted file mode 100644 index d841054efdb07..0000000000000 --- a/shell/platform/tizen/tizen_surface.cc +++ /dev/null @@ -1,14 +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 "tizen_surface.h" - -TizenSurface::TizenSurface(int32_t x, int32_t y, int32_t width, int32_t height) - : window_width_(width), window_height_(height), x_(x), y_(y) {} - -TizenSurface::~TizenSurface() {} - -uint32_t TizenSurface::GetWidth() { return window_width_; } - -uint32_t TizenSurface::GetHeight() { return window_height_; } diff --git a/shell/platform/tizen/tizen_surface.h b/shell/platform/tizen/tizen_surface.h deleted file mode 100644 index 736eb5b593de4..0000000000000 --- a/shell/platform/tizen/tizen_surface.h +++ /dev/null @@ -1,31 +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_SURFACE_H_ -#define EMBEDDER_TIZEN_SURFACE_H_ - -#include - -class TizenSurface { - public: - TizenSurface(int32_t x, int32_t y, int32_t width, int32_t height); - virtual ~TizenSurface(); - 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; - virtual bool IsValid() = 0; - uint32_t GetWidth(); - uint32_t GetHeight(); - - protected: - const int32_t window_width_; - const int32_t window_height_; - int32_t x_; - int32_t y_; -}; - -#endif // EMBEDDER_TIZEN_SURFACE_H_ diff --git a/shell/platform/tizen/tizen_surface_gl.cc b/shell/platform/tizen/tizen_surface_gl.cc deleted file mode 100644 index 40cc9852f80a1..0000000000000 --- a/shell/platform/tizen/tizen_surface_gl.cc +++ /dev/null @@ -1,247 +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 "tizen_surface_gl.h" - -#include "flutter/shell/platform/tizen/logger.h" - -TizenSurfaceGL::TizenSurfaceGL(int32_t x, int32_t y, int32_t width, - int32_t height) - : TizenSurface(x, y, width, height) { - LoggerD("x =[%d] y = [%d], width = [%d], height = [%d]", x, y, width, height); - InitalizeDisplay(); -} - -bool TizenSurfaceGL::IsValid() { return display_valid_; } - -bool TizenSurfaceGL::OnMakeCurrent() { - if (!display_valid_) { - LoggerE("Invalid Display"); - return false; - } - if (eglMakeCurrent(egl_display_, egl_surface_, egl_surface_, egl_context_) != - EGL_TRUE) { - LoggerE("Could not make the onscreen context current"); - return false; - } - return true; -} - -bool TizenSurfaceGL::OnMakeResourceCurrent() { - if (!display_valid_) { - LoggerE("Invalid Display"); - return false; - } - if (eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, - egl_resource_context_) != EGL_TRUE) { - LoggerE("Could not make the onscreen context current"); - return false; - } - return true; -} - -bool TizenSurfaceGL::OnClearCurrent() { - if (!display_valid_) { - LoggerE("Invalid display"); - return false; - } - - if (eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT) != EGL_TRUE) { - LoggerE("Could not clear context"); - return false; - } - return true; -} - -bool TizenSurfaceGL::OnPresent() { - if (!display_valid_) { - LoggerE("Invalid display"); - return false; - } - - if (eglSwapBuffers(egl_display_, egl_surface_) != EGL_TRUE) { - LoggerE("Could not swap EGl buffer"); - return false; - } - return true; -} - -uint32_t TizenSurfaceGL::OnGetFBO() { - if (!display_valid_) { - LoggerE("Invalid display"); - return 999; - } - LoggerD("OnApplicationGetOnscreenFBO"); - return 0; // FBO0 -} - -void* TizenSurfaceGL::OnProcResolver(const char* name) { - auto address = eglGetProcAddress(name); - if (address != nullptr) { - return reinterpret_cast(address); - } - LoggerW("Could not resolve: %s", name); - return nullptr; -} - -TizenSurfaceGL::~TizenSurfaceGL() { - if (IsValid()) { - display_valid_ = false; - Destroy(); - } -} - -bool TizenSurfaceGL::InitalizeDisplay() { - LoggerD("x =[%d] y = [%d], width = [%d], height = [%d]", x_, y_, - window_width_, window_height_); - if (window_width_ == 0 || window_height_ == 0) { - return false; - } - - // ecore_wl2 INIT - if (!ecore_wl2_init()) { - LoggerE("Could not initialize ecore_wl2"); - return false; - } - - // ecore_wl2 DISPLAY - wl2_display_ = ecore_wl2_display_connect(nullptr); - if (nullptr == wl2_display_) { - LoggerE("Display not found"); - return false; - } - LoggerD("wl2_display_: %p", wl2_display_); - ecore_wl2_sync(); - - // ecore_wl2 WINDOW - wl2_window_ = ecore_wl2_window_new(wl2_display_, nullptr, x_, y_, - window_width_, window_height_); - LoggerD("wl2_window_: %p", wl2_window_); - - ecore_wl2_window_type_set(wl2_window_, ECORE_WL2_WINDOW_TYPE_TOPLEVEL); - ecore_wl2_window_alpha_set(wl2_window_, EINA_FALSE); - // ecore_wl2_sync(); - - // ecore_wl2 SHOW - ecore_wl2_window_show(wl2_window_); - - ecore_wl2_window_position_set(wl2_window_, x_, y_); - ecore_wl2_window_geometry_set(wl2_window_, x_, y_, window_width_, - window_height_); - - // egl WINDOW - egl_window_ = - ecore_wl2_egl_window_create(wl2_window_, window_width_, window_height_); - LoggerD("egl_window_: %p", egl_window_); - - if (!egl_window_) { - LoggerE("Could not create EGL window"); - return false; - } - - // egl DISPLAY - egl_display_ = - eglGetDisplay((EGLNativeDisplayType)ecore_wl2_display_get(wl2_display_)); - if (egl_display_ == EGL_NO_DISPLAY) { - LoggerE("Could not access EGL display"); - return false; - } - LoggerD("egl_display_: %p", egl_display_); - - // egl INTIALIZE - EGLint majorVersion; - EGLint minorVersion; - if (eglInitialize(egl_display_, &majorVersion, &minorVersion) != EGL_TRUE) { - LoggerE("Could not initialize EGL display"); - return false; - } - LoggerD("eglInitialized: %d.%d", majorVersion, minorVersion); - - // egl BINDAPI - if (eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE) { - LoggerE("Could not bind API"); - return false; - } - - // egl CONFIG - EGLint config_count; - eglGetConfigs(egl_display_, NULL, 0, &config_count); - LoggerD("config_count: %d", config_count); - - EGLConfig egl_config = nullptr; - - { - EGLint attribs[] = { - // clang-format off - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_DEPTH_SIZE, 0, - EGL_STENCIL_SIZE, 0, - EGL_NONE, // termination sentinel - // clang-format on - }; - - if (eglChooseConfig(egl_display_, attribs, &egl_config, 1, &config_count) != - EGL_TRUE) { - LoggerE("Error when attempting to choose an EGL surface config"); - return false; - } - - if (config_count == 0 || egl_config == nullptr) { - LoggerE("No matching config"); - return false; - } - } - - // egl CONTEXT - const EGLint attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - - egl_context_ = eglCreateContext(egl_display_, egl_config, nullptr, attribs); - if (egl_context_ == EGL_NO_CONTEXT) { - LoggerE("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) { - LoggerE("Could not create an resource context"); - return false; - } - - // egl SURFACE - { - egl_surface_ = eglCreateWindowSurface( - egl_display_, egl_config, ecore_wl2_egl_window_native_get(egl_window_), - nullptr); - - if (egl_surface_ == EGL_NO_SURFACE) { - return false; - } - } - LoggerD("egl_surface_: %p", egl_surface_); - display_valid_ = true; - return true; -} - -void TizenSurfaceGL::Destroy() { - if (egl_window_) { - ecore_wl2_egl_window_destroy(egl_window_); - egl_window_ = nullptr; - } - if (wl2_window_) { - ecore_wl2_window_free(wl2_window_); - wl2_window_ = nullptr; - } - if (wl2_display_) { - ecore_wl2_display_destroy(wl2_display_); - wl2_display_ = nullptr; - } - ecore_wl2_shutdown(); -} diff --git a/shell/platform/tizen/tizen_surface_gl.h b/shell/platform/tizen/tizen_surface_gl.h deleted file mode 100644 index 9fb35d308212f..0000000000000 --- a/shell/platform/tizen/tizen_surface_gl.h +++ /dev/null @@ -1,49 +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_SURFACE_GL_H_ -#define EMBEDDER_TIZEN_SURFACE_GL_H_ - -#include -#include -#include -#include - -#include -#include -#include -#define EFL_BETA_API_SUPPORT -#include -#include - -#include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/tizen/tizen_surface.h" - -class TizenSurfaceGL : public TizenSurface { - public: - TizenSurfaceGL(int32_t x, int32_t y, int32_t width, int32_t height); - ~TizenSurfaceGL(); - bool OnMakeCurrent(); - bool OnClearCurrent(); - bool OnMakeResourceCurrent(); - bool OnPresent(); - uint32_t OnGetFBO(); - void* OnProcResolver(const char* name); - bool IsValid(); - bool InitalizeDisplay(); - void Destroy(); - Ecore_Wl2_Window* wl2_window() { return wl2_window_; } - - private: - bool display_valid_ = false; - EGLDisplay egl_display_ = EGL_NO_DISPLAY; - EGLSurface egl_surface_ = nullptr; - EGLContext egl_context_ = EGL_NO_CONTEXT; - EGLContext egl_resource_context_ = EGL_NO_CONTEXT; - Ecore_Wl2_Egl_Window* egl_window_ = nullptr; - Ecore_Wl2_Display* wl2_display_ = nullptr; - Ecore_Wl2_Window* wl2_window_ = nullptr; -}; - -#endif // EMBEDDER_TIZEN_SURFACE_GL_H_ diff --git a/shell/platform/tizen/tizen_vsync_waiter.cc b/shell/platform/tizen/tizen_vsync_waiter.cc index 01bbda4c341e6..bb88d0fe09180 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.cc +++ b/shell/platform/tizen/tizen_vsync_waiter.cc @@ -4,142 +4,154 @@ #include "tizen_vsync_waiter.h" -#include "flutter/shell/platform/tizen/logger.h" - -TizenVsyncWaiter::TizenVsyncWaiter() - : client_(NULL), - output_(NULL), - vblank_(NULL), - flutter_engine_(nullptr), - baton_(0), - vblank_ecore_pipe_(NULL) { - if (CreateTDMVblank()) { - std::thread t(CreateVblankEventLoop, this); - t.join(); +#include + +#include "flutter/shell/platform/tizen/tizen_embedder_engine.h" +#include "flutter/shell/platform/tizen/tizen_log.h" + +static const int QUEUE_QUIT = -1; +static const int QUEUE_REQUEST_VBLANK = 0; + +typedef struct { + Eina_Thread_Queue_Msg head; + int value; +} Msg; + +static Eina_Thread_Queue* vblank_thread_queue{nullptr}; + +TizenVsyncWaiter::TizenVsyncWaiter(TizenEmbedderEngine* engine) + : engine_(engine) { + if (!CreateTDMVblank()) { + FT_LOGE("Failed to create TDM vblank"); + DestoryTDMVblank(); } else { - LoggerE("CreateVsyncVaiter fail"); + vblank_thread_queue = eina_thread_queue_new(); + vblank_thread_ = + ecore_thread_feedback_run(RequestVblankLoop, NULL, VblankLoopFinish, + VblankLoopFinish, this, EINA_TRUE); } } -void TizenVsyncWaiter::CreateVblankEventLoop(void* data) { - TizenVsyncWaiter* tizen_vsync_waiter = - reinterpret_cast(data); - if (!ecore_init()) { - LoggerE("ERROR: Cannot init Ecore!"); - return; +TizenVsyncWaiter::~TizenVsyncWaiter() { + SendMessage(QUEUE_QUIT); + if (vblank_thread_) { + ecore_thread_cancel(vblank_thread_); + vblank_thread_ = nullptr; } - tizen_vsync_waiter->vblank_ecore_pipe_ = - ecore_pipe_add(VblankEventLoopCallback, tizen_vsync_waiter); - LoggerD("ecore_init successful"); - ecore_main_loop_begin(); - ecore_shutdown(); + DestoryTDMVblank(); } -void TizenVsyncWaiter::VblankEventLoopCallback(void* data, void* buffer, - unsigned int nbyte) { - TizenVsyncWaiter* tizen_vsync_waiter = - reinterpret_cast(data); - int* event_type = reinterpret_cast(buffer); - if ((*event_type) == VBLANK_LOOP_REQUEST) { - tizen_vsync_waiter->AsyncWaitForVsyncCallback(); - } else if ((*event_type) == VBLANK_LOOP_DEL_PIPE) { - tizen_vsync_waiter->DeleteVblankEventPipe(); +void TizenVsyncWaiter::AsyncWaitForVsync(intptr_t baton) { + baton_ = baton; + if (TDMValid()) { + SendMessage(QUEUE_REQUEST_VBLANK); } } -void TizenVsyncWaiter::AsyncWaitForVsyncCallback() { - tdm_error ret; - ret = tdm_client_vblank_wait(vblank_, 1, TdmClientVblankCallback, this); - if (ret != TDM_ERROR_NONE) { - LoggerE("ERROR, ret = %d", ret); +void TizenVsyncWaiter::SendMessage(int val) { + if (!vblank_thread_queue || !vblank_thread_) { + FT_LOGE("vblank thread or vblank thread queue not valid"); return; } - tdm_client_handle_events(client_); + Msg* msg; + void* ref; + msg = (Msg*)eina_thread_queue_send(vblank_thread_queue, sizeof(Msg), &ref); + msg->value = val; + eina_thread_queue_send_done(vblank_thread_queue, ref); } -void TizenVsyncWaiter::DeleteVblankEventPipe() { - if (vblank_ecore_pipe_) { - ecore_pipe_del(vblank_ecore_pipe_); - vblank_ecore_pipe_ = NULL; +void TizenVsyncWaiter::RequestVblankLoop(void* data, Ecore_Thread* thread) { + TizenVsyncWaiter* tizen_vsync_waiter = + reinterpret_cast(data); + void* ref; + Msg* msg; + while (!ecore_thread_check(thread)) { + if (!vblank_thread_queue) { + FT_LOGE("Vblank thread queue is not valid"); + return; + } + msg = (Msg*)eina_thread_queue_wait(vblank_thread_queue, &ref); + if (msg) { + eina_thread_queue_wait_done(vblank_thread_queue, ref); + } else { + FT_LOGE("Message is null"); + continue; + } + if (msg->value == QUEUE_QUIT) { + FT_LOGD("Message queue quit"); + return; + } + if (!tizen_vsync_waiter->TDMValid()) { + FT_LOGE("TDM not valid"); + return; + } + tdm_error error = tdm_client_vblank_wait(tizen_vsync_waiter->vblank_, 1, + TdmClientVblankCallback, data); + if (error != TDM_ERROR_NONE) { + FT_LOGE("tdm_client_vblank_wait error %d", error); + continue; + } + tdm_client_handle_events(tizen_vsync_waiter->client_); + } +} + +void TizenVsyncWaiter::VblankLoopFinish(void* data, Ecore_Thread* thread) { + FT_LOGD("VblankLoopFinish."); + if (vblank_thread_queue) { + eina_thread_queue_free(vblank_thread_queue); + vblank_thread_queue = nullptr; } - ecore_main_loop_quit(); } bool TizenVsyncWaiter::CreateTDMVblank() { tdm_error ret; client_ = tdm_client_create(&ret); if (ret != TDM_ERROR_NONE && client_ != NULL) { - LoggerE("create client fail"); + FT_LOGE("create client fail"); return false; } output_ = tdm_client_get_output(client_, const_cast("default"), &ret); if (ret != TDM_ERROR_NONE && output_ != NULL) { - LoggerE("get output fail"); + FT_LOGE("get output fail"); return false; } vblank_ = tdm_client_output_create_vblank(output_, &ret); if (ret != TDM_ERROR_NONE && vblank_ != NULL) { - LoggerE("create vblank fail"); + FT_LOGE("create vblank fail"); return false; } + tdm_client_vblank_set_enable_fake(vblank_, 1); return true; } -void TizenVsyncWaiter::TdmClientVblankCallback( - tdm_client_vblank* vblank, tdm_error error, unsigned int sequence, - unsigned int tv_sec, unsigned int tv_usec, void* user_data) { - TizenVsyncWaiter* tizen_vsync_waiter = - reinterpret_cast(user_data); - if (tizen_vsync_waiter == nullptr) { - LoggerE("tizen_vsync_waiter is null"); - return; - } - if (tizen_vsync_waiter->flutter_engine_ == nullptr) { - LoggerI("flutter engine creation is not completed"); - return; - } - uint64_t frame_start_time_nanos = tv_sec * 1e9 + tv_usec * 1e3; - uint64_t frame_target_time_nanos = 16.6 * 1e6 + frame_start_time_nanos; - FlutterEngineOnVsync(tizen_vsync_waiter->flutter_engine_, - tizen_vsync_waiter->baton_, frame_start_time_nanos, - frame_target_time_nanos); -} - -bool TizenVsyncWaiter::AsyncWaitForVsync() { - if (vblank_ecore_pipe_) { - int event_type = VBLANK_LOOP_REQUEST; - ecore_pipe_write(vblank_ecore_pipe_, &event_type, sizeof(event_type)); - } - return true; -} - -TizenVsyncWaiter::~TizenVsyncWaiter() { - if (vblank_ecore_pipe_) { - int event_type = VBLANK_LOOP_DEL_PIPE; - ecore_pipe_write(vblank_ecore_pipe_, &event_type, sizeof(event_type)); - } +void TizenVsyncWaiter::DestoryTDMVblank() { if (vblank_) { tdm_client_vblank_destroy(vblank_); + vblank_ = nullptr; } + output_ = nullptr; if (client_) { tdm_client_destroy(client_); + client_ = nullptr; } } -void TizenVsyncWaiter::AsyncWaitForVsync(intptr_t baton) { - baton_ = baton; - AsyncWaitForVsync(); -} +bool TizenVsyncWaiter::TDMValid() { return vblank_ && client_; } -void TizenVsyncWaiter::AsyncWaitForRunEngineSuccess( - FLUTTER_API_SYMBOL(FlutterEngine) flutter_engine) { - flutter_engine_ = flutter_engine; - if (baton_ == 0) { - LoggerD("baton_ == 0"); - return; - } - AsyncWaitForVsync(); +void TizenVsyncWaiter::TdmClientVblankCallback( + tdm_client_vblank* vblank, tdm_error error, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void* user_data) { + TizenVsyncWaiter* tizen_vsync_waiter = + reinterpret_cast(user_data); + FT_ASSERT(tizen_vsync_waiter != nullptr); + FT_ASSERT(tizen_vsync_waiter->engine_ != nullptr); + FT_ASSERT(tizen_vsync_waiter->engine_->flutter_engine != nullptr); + uint64_t frame_start_time_nanos = tv_sec * 1e9 + tv_usec * 1e3; + uint64_t frame_target_time_nanos = 16.6 * 1e6 + frame_start_time_nanos; + FlutterEngineOnVsync(tizen_vsync_waiter->engine_->flutter_engine, + tizen_vsync_waiter->baton_, frame_start_time_nanos, + frame_target_time_nanos); } diff --git a/shell/platform/tizen/tizen_vsync_waiter.h b/shell/platform/tizen/tizen_vsync_waiter.h index b7bb977fdd477..eb4826d4e7feb 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.h +++ b/shell/platform/tizen/tizen_vsync_waiter.h @@ -8,38 +8,33 @@ #include #include -#include - #include "flutter/shell/platform/embedder/embedder.h" +class TizenEmbedderEngine; + class TizenVsyncWaiter { public: - TizenVsyncWaiter(); + TizenVsyncWaiter(TizenEmbedderEngine* engine); virtual ~TizenVsyncWaiter(); - bool CreateTDMVblank(); - bool AsyncWaitForVsync(); void AsyncWaitForVsync(intptr_t baton); - void AsyncWaitForRunEngineSuccess(FLUTTER_API_SYMBOL(FlutterEngine) - flutter_engine); private: - static const int VBLANK_LOOP_REQUEST = 1; - static const int VBLANK_LOOP_DEL_PIPE = 2; - void AsyncWaitForVsyncCallback(); - void DeleteVblankEventPipe(); - static void CreateVblankEventLoop(void* data); + bool CreateTDMVblank(); + void DestoryTDMVblank(); + bool TDMValid(); + void SendMessage(int val); static void TdmClientVblankCallback(tdm_client_vblank* vblank, tdm_error error, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void* user_data); - static void VblankEventLoopCallback(void* data, void* buffer, - unsigned int nbyte); - tdm_client* client_; - tdm_client_output* output_; - tdm_client_vblank* vblank_; - FLUTTER_API_SYMBOL(FlutterEngine) flutter_engine_; - intptr_t baton_; - Ecore_Pipe* vblank_ecore_pipe_; + static void RequestVblankLoop(void* data, Ecore_Thread* thread); + static void VblankLoopFinish(void* data, Ecore_Thread* thread); + tdm_client* client_{nullptr}; + tdm_client_output* output_{nullptr}; + tdm_client_vblank* vblank_{nullptr}; + TizenEmbedderEngine* engine_{nullptr}; + intptr_t baton_{0}; + Ecore_Thread* vblank_thread_{nullptr}; }; #endif // EMBEDDER_TIZEN_VSYNC_WAITER_H_ diff --git a/shell/platform/tizen/touch_event_handler.cc b/shell/platform/tizen/touch_event_handler.cc index 44bf9311aac24..117cd9a209b84 100644 --- a/shell/platform/tizen/touch_event_handler.cc +++ b/shell/platform/tizen/touch_event_handler.cc @@ -4,8 +4,11 @@ #include "touch_event_handler.h" -#include "flutter/shell/platform/tizen/logger.h" #include "flutter/shell/platform/tizen/tizen_embedder_engine.h" +#include "flutter/shell/platform/tizen/tizen_log.h" + +static const int DIRECTION_VERTICAL = 0; +static const int DIRECTION_HORIZONTAL = 1; TouchEventHandler::TouchEventHandler(TizenEmbedderEngine *engine) : engine_(engine) { @@ -13,10 +16,10 @@ TouchEventHandler::TouchEventHandler(TizenEmbedderEngine *engine) 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)); - touch_event_handlers_.push_back(ecore_event_handler_add( - ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE, OnTouch, this)); } TouchEventHandler::~TouchEventHandler() { @@ -28,15 +31,19 @@ TouchEventHandler::~TouchEventHandler() { void TouchEventHandler::SendFlutterPointerEvent(FlutterPointerPhase phase, double x, double y, + double scroll_delta_x, + double scroll_delta_y, size_t timestamp) { if (!engine_->flutter_engine) { return; } // Correct errors caused by window rotation. - double width = engine_->tizen_surface->GetWidth(); - double height = engine_->tizen_surface->GetHeight(); + auto window_geometry = engine_->tizen_renderer->GetGeometry(); + double width = window_geometry.w; + double height = window_geometry.h; double new_x = x, new_y = y; + if (rotation == 90) { new_x = height - y; new_y = x; @@ -53,7 +60,12 @@ void TouchEventHandler::SendFlutterPointerEvent(FlutterPointerPhase phase, event.phase = phase; event.x = new_x; event.y = new_y; - event.timestamp = timestamp; + if (scroll_delta_x != 0 || scroll_delta_y != 0) { + event.signal_kind = kFlutterPointerSignalKindScroll; + } + event.scroll_delta_x = scroll_delta_x; + event.scroll_delta_y = scroll_delta_y; + event.timestamp = timestamp * 1000; FlutterEngineSendPointerEvent(engine_->flutter_engine, &event, 1); } @@ -63,25 +75,33 @@ Eina_Bool TouchEventHandler::OnTouch(void *data, int type, void *event) { if (type == ECORE_EVENT_MOUSE_BUTTON_DOWN) { self->pointer_state_ = true; auto *button_event = reinterpret_cast(event); - self->SendFlutterPointerEvent(kDown, button_event->x, button_event->y, + self->SendFlutterPointerEvent(kDown, button_event->x, button_event->y, 0, 0, button_event->timestamp); } else if (type == ECORE_EVENT_MOUSE_BUTTON_UP) { self->pointer_state_ = false; auto *button_event = reinterpret_cast(event); - self->SendFlutterPointerEvent(kUp, button_event->x, button_event->y, + self->SendFlutterPointerEvent(kUp, button_event->x, button_event->y, 0, 0, button_event->timestamp); } else if (type == ECORE_EVENT_MOUSE_MOVE) { if (self->pointer_state_) { auto *move_event = reinterpret_cast(event); - self->SendFlutterPointerEvent(kMove, move_event->x, move_event->y, + self->SendFlutterPointerEvent(kMove, move_event->x, move_event->y, 0, 0, move_event->timestamp); } - } else if (type == ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE) { - auto *focus_event = - reinterpret_cast(event); - LoggerD("Visibility changed: %u, %d", focus_event->win, - focus_event->fully_obscured); + } else if (type == ECORE_EVENT_MOUSE_WHEEL) { + auto *wheel_event = reinterpret_cast(event); + double scroll_delta_x = 0.0, scroll_delta_y = 0.0; + if (wheel_event->direction == DIRECTION_VERTICAL) { + scroll_delta_y += wheel_event->z; + } else if (wheel_event->direction == DIRECTION_HORIZONTAL) { + 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_PASS_ON; } diff --git a/shell/platform/tizen/touch_event_handler.h b/shell/platform/tizen/touch_event_handler.h index 0b0b678953dbe..daa1f014aed0b 100644 --- a/shell/platform/tizen/touch_event_handler.h +++ b/shell/platform/tizen/touch_event_handler.h @@ -5,10 +5,7 @@ #ifndef EMBEDDER_TOUCH_EVENT_HANDLER_H_ #define EMBEDDER_TOUCH_EVENT_HANDLER_H_ -#define EFL_BETA_API_SUPPORT #include -#include - #include #include "flutter/shell/platform/embedder/embedder.h" @@ -28,6 +25,7 @@ class TouchEventHandler { bool pointer_state_ = false; void SendFlutterPointerEvent(FlutterPointerPhase phase, double x, double y, + double scroll_delta_x, double scroll_delta_y, size_t timestamp); static Eina_Bool OnTouch(void* data, int type, void* event); diff --git a/tools/gn b/tools/gn index f10bd922218c9..17fd5c7eb67e6 100755 --- a/tools/gn +++ b/tools/gn @@ -170,6 +170,7 @@ def to_gn_args(args): gn_args['embedder_for_target'] = args.embedder_for_target gn_args['build_tizen_shell'] = args.build_tizen_shell + gn_args['tizen_sdk_4'] = args.tizen_sdk_4 gn_args['enable_coverage'] = args.coverage @@ -464,6 +465,7 @@ def parse_args(args): parser.add_argument('--embedder-for-target', dest='embedder_for_target', action='store_true', default=False) parser.add_argument('--build-tizen-shell', dest='build_tizen_shell', action='store_true', default=False) + parser.add_argument('--tizen-sdk-4', dest='tizen_sdk_4', action='store_true', default=False) parser.add_argument('--coverage', default=False, action='store_true')