1 // Copyright 2023 Samsung Electronics. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "wrt/src/browser/wrt_native_window_off_screen.h"
8 #include <Elementary.h>
10 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
11 #include "content/browser/web_contents/web_contents_impl.h"
12 #include "tizen_src/chromium_impl/tizen/system_info.h"
13 #include "wrt/src/browser/wrt_window_tree_host.h"
14 #include "wrt/src/common/application_data.h"
16 #if defined(TIZEN_VIDEO_HOLE)
17 #include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller.h"
20 #if BUILDFLAG(IS_TIZEN_TV)
21 #include "base/path_service.h"
22 #include "tizen_src/chromium_impl/content/common/paths_efl.h"
24 #include <inputmethod.h>
25 #include <watch_app_efl.h>
26 #endif // BUILDFLAG(IS_TIZEN_TV)
32 #if BUILDFLAG(IS_TIZEN_TV)
33 const char* kEdjeFile = "wrtjs_tizen.edj";
35 const char* kConfigProfile = "mobile";
36 const char* kEdjePath = "/usr/share/edje/wrtjs/wrtjs_tizen.edj";
38 enum class Shape { STANDARD = 0, SQUARE = 1 };
40 Shape GetWindowShape() {
41 auto& app_data = ApplicationData::GetInstance();
42 // As profile tag is not present app will be treated as square app
43 std::string type = app_data.profile_tag_info().GetProfileType();
44 if (type.empty() || !type.compare(kConfigProfile))
46 return Shape::STANDARD;
48 #endif // BUILDFLAG(IS_TIZEN_TV)
52 Evas_Object* WRTNativeWindowOffScreen::elm_window_ = nullptr;
53 Evas_Object* WRTNativeWindowOffScreen::layout_ = nullptr;
54 Evas_Object* WRTNativeWindowOffScreen::conformant_ = nullptr;
57 Evas_Object* WRTNativeWindowOffScreen::CreateElmWindow() {
61 #if !BUILDFLAG(IS_TIZEN_TV)
62 auto app_type = ApplicationData::GetInstance().app_type();
63 if (app_type == ApplicationData::WATCH) {
64 elm_config_accel_preference_set("opengl");
65 watch_app_get_elm_win(&elm_window_);
66 elm_win_alpha_set(elm_window_, EINA_TRUE);
67 evas_object_render_op_set(elm_window_, EVAS_RENDER_COPY);
68 } else if (app_type == ApplicationData::IME) {
69 elm_config_accel_preference_set("opengl");
70 elm_window_ = ime_get_main_window();
73 elm_window_ = elm_win_util_standard_add("", "");
75 elm_win_autodel_set(elm_window_, EINA_TRUE);
76 #if defined(OS_TIZEN_DA_PRODUCT) || BUILDFLAG(IS_TIZEN_TV)
77 elm_win_indicator_mode_set(elm_window_, ELM_WIN_INDICATOR_HIDE);
79 elm_win_indicator_mode_set(elm_window_, ELM_WIN_INDICATOR_SHOW);
82 int window_width, window_height;
83 elm_win_screen_size_get(elm_window_, nullptr, nullptr, &window_width,
85 evas_object_resize(elm_window_, window_width, window_height);
87 auto need_conformant = true;
88 #if !BUILDFLAG(IS_TIZEN_TV)
89 if (app_type == ApplicationData::IME) {
90 need_conformant = false;
91 ime_set_size(window_width, window_height * 2 / 5, window_height,
92 window_width * 3 / 5);
96 Evas_Object* container = elm_window_;
97 if (need_conformant) {
98 elm_win_conformant_set(elm_window_, EINA_TRUE);
99 conformant_ = elm_conformant_add(elm_window_);
100 evas_object_size_hint_weight_set(conformant_, EVAS_HINT_EXPAND,
102 elm_win_resize_object_add(elm_window_, conformant_);
103 evas_object_show(conformant_);
104 container = conformant_;
107 layout_ = elm_layout_add(container);
108 #if BUILDFLAG(IS_TIZEN_TV)
109 base::FilePath edje_dir;
110 base::PathService::Get(PathsEfl::EDJE_RESOURCE_DIR, &edje_dir);
111 elm_layout_file_set(layout_, (edje_dir.value() + "/" + kEdjeFile).c_str(),
114 if (IsWearableProfile() && GetWindowShape() == Shape::SQUARE) {
115 LOG(ERROR) << "Device shape square";
116 elm_layout_file_set(layout_, kEdjePath, "web-applicationsview");
118 LOG(ERROR) << "Device shape standard";
119 elm_layout_file_set(layout_, kEdjePath, "web-application");
123 elm_object_content_set(container, layout_);
124 evas_object_size_hint_align_set(layout_, EVAS_HINT_FILL, EVAS_HINT_FILL);
125 evas_object_size_hint_weight_set(layout_, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
126 evas_object_show(layout_);
128 #if defined(TIZEN_VIDEO_HOLE)
129 // Hand a window handle to enable video hole in OffscreenRendering mode.
130 media::VideoPlaneController::SetSharedVideoWindowHandle(
131 elm_window_, media::VideoPlaneController::RenderingMode::OFFSCREEN);
137 Evas_Object* WRTNativeWindowOffScreen::GetWindowEvasObject() {
138 return CreateElmWindow();
141 Evas_Object* WRTNativeWindowOffScreen::GetTopWindow() {
145 Evas_Object* WRTNativeWindowOffScreen::GetConformant() {
149 WRTWindowTreeHost* WRTNativeWindowOffScreen::GetWindowTreeHost(
150 WRTNativeWindow* native_window) {
151 auto it = host_map_.find(native_window);
152 if (it != host_map_.end())
153 return it->second.get();
155 std::unique_ptr<WRTWindowTreeHost> entry(WRTWindowTreeHost::Create());
156 auto* host = entry.get();
157 host_map_.insert(std::make_pair(native_window, std::move(entry)));
161 void WRTNativeWindowOffScreen::OnNativeWindowDestroyed(
162 WRTNativeWindow* native_window) {
163 if (native_window->is_main_native_window()) {
164 #if defined(TIZEN_VIDEO_HOLE)
165 media::VideoPlaneController::SetSharedVideoWindowHandle(
166 nullptr, media::VideoPlaneController::RenderingMode::OFFSCREEN);
169 std::map<WRTNativeWindow*, std::unique_ptr<WRTWindowTreeHost>> host_map;
170 host_map_.swap(host_map);
171 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
173 base::BindOnce([](std::map<WRTNativeWindow*,
174 std::unique_ptr<WRTWindowTreeHost>>
175 host_map) { host_map.clear(); },
176 std::move(host_map)));
178 auto it = host_map_.find(native_window);
179 if (it != host_map_.end()) {
180 auto* host = it->second.release();
182 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
184 base::BindOnce([](WRTWindowTreeHost* host) { delete host; }, host));
189 void WRTNativeWindowOffScreen::InitRotation() {
190 evas_object_smart_callback_add(
191 elm_window_, "wm,rotation,changed",
192 [](void*, Evas_Object*, void*) { WRTNativeWindow::RotationCallback(); },
196 content::RenderWidgetHostViewAura*
197 WRTNativeWindowOffScreen::GetRenderWidgetHostView(
198 WRTNativeWindow* native_window) {
199 return static_cast<content::RenderWidgetHostViewAura*>(
200 native_window->GetWebContents()->GetRenderWidgetHostView());
203 int WRTNativeWindowOffScreen::SetRotationState(bool is_auto, int degree) {
204 int rotation_degree = 0;
206 LOG(INFO) << "Rotation : Auto";
207 elm_win_wm_rotation_preferred_rotation_set(elm_window_, -1);
208 if (elm_win_wm_rotation_supported_get(elm_window_)) {
209 const int rotation[4] = {0, 90, 180, 270};
210 elm_win_wm_rotation_available_rotations_set(elm_window_, rotation, 4);
212 #if BUILDFLAG(IS_TIZEN_TV)
214 // need to check elm_win_wm_rotation_manual_rotation_done_set is appliable
216 elm_win_wm_rotation_manual_rotation_done_set(elm_window_, EINA_TRUE);
218 rotation_degree = elm_win_rotation_get(elm_window_);
221 rotation_degree = degree % 360;
222 LOG(INFO) << "Rotation : Lock to " << rotation_degree;
223 elm_win_wm_rotation_preferred_rotation_set(elm_window_, rotation_degree);
226 return rotation_degree;
229 Evas_Object* WRTNativeWindowOffScreen::GetEflMainLayout(
230 WRTNativeWindow* native_window) {
231 auto web_contents_impl =
232 static_cast<content::WebContentsImpl*>(native_window->GetWebContents());
233 efl_main_layout_ = web_contents_impl->GetEflMainLayout();
234 return efl_main_layout_;
237 void WRTNativeWindowOffScreen::SetContentView(WRTNativeWindow* native_window,
239 auto web_contents = native_window->GetWebContents();
240 auto content_view = web_contents->GetNativeView();
241 GetWindowTreeHost(native_window)->window()->AddChild(content_view);
242 content_view->Show();
243 std::ignore = GetEflMainLayout(native_window);
246 void WRTNativeWindowOffScreen::Show(WRTNativeWindow* native_window) {
247 auto* view = GetEflMainLayout(native_window);
248 if (elm_object_part_content_get(layout_, "elm.swallow.content") != view) {
250 elm_object_part_content_unset(layout_, "elm.swallow.content");
252 evas_object_hide(prev_view);
253 elm_object_part_content_set(layout_, "elm.swallow.content", view);
254 evas_object_show(view);
257 if (!evas_object_visible_get(elm_window_)) {
258 evas_object_show(elm_window_);
259 elm_win_activate(elm_window_);
261 Focus(native_window, true);
264 void WRTNativeWindowOffScreen::Hide() {
265 evas_object_hide(elm_window_);
268 bool WRTNativeWindowOffScreen::IsFocused(WRTNativeWindow* native_window) {
269 return elm_object_focus_get(elm_window_);
272 void WRTNativeWindowOffScreen::Focus(WRTNativeWindow* native_window,
274 elm_object_focus_set(elm_window_, focus);
276 native_window->GetWebContents()->Focus();
278 auto* rwhv = GetRenderWidgetHostView(native_window);
279 auto* aura_offscreen_helper = rwhv ? rwhv->offscreen_helper() : nullptr;
280 if (aura_offscreen_helper)
281 aura_offscreen_helper->Focus(true);
284 #if BUILDFLAG(IS_TIZEN_TV)
285 void WRTNativeWindowOffScreen::SetConformantObject(bool no_resize) {
287 LOG(ERROR) << "conformant_ is empty.";
291 const char* style = elm_object_style_get(conformant_);
292 std::string current_style = style ? style : "default";
293 if (no_resize && current_style != "conformant_noresize") {
294 elm_object_style_set(conformant_, "conformant_noresize");
295 LOG(INFO) << "SetConformantObject as conformant_noresize";
296 } else if (current_style != "web-application") {
297 elm_object_style_set(conformant_, "web-application");
298 LOG(INFO) << "SetConformantObject as web-application";
302 void WRTNativeWindowOffScreen::SetScreenOrientation(
303 WRTNativeWindow* native_window,
304 ScreenOrientation orientation) {
306 LOG(ERROR) << "conformant_ is empty.";
310 if (orientation == ScreenOrientation::LANDSCAPE_PRIMARY) {
311 LOG(INFO) << "orientation is landscape";
312 if (native_window->ShouldHandleConformantChange())
313 SetConformantObject(false);
315 LOG(INFO) << "use.conformant will be same as previous";
316 } else if (orientation == ScreenOrientation::PORTRAIT_PRIMARY) {
317 LOG(INFO) << "orientation is portrait";
318 const char* kScreenOrientation =
319 "http://samsung.com/tv/metadata/screen/orientation";
320 auto& app_data = ApplicationData::GetInstance();
321 if (app_data.GetMetadata(kScreenOrientation) == "landscape" ||
322 app_data.GetMetadata(kScreenOrientation) == "landscape_scale") {
323 SetConformantObject(true);
328 void WRTNativeWindowOffScreen::SetWindowBorderAlpha() {
329 #if TIZEN_VERSION_AT_LEAST(7, 0, 0) && defined(TIZEN_VD_ENTERPRISE_FEATURE)
330 elm_config_window_border_alpha_set(EINA_TRUE);
334 void WRTNativeWindowOffScreen::SetZoomLevel(double level, const char* style) {
336 orientation_style_ = style ? style : "";
339 auto self = static_cast<WRTNativeWindowOffScreen*>(data);
340 auto top_window = self->GetTopWindow();
341 elm_object_scale_set(top_window, self->zoom_level_);
342 elm_object_style_set(top_window, self->orientation_style_.c_str());
343 return ECORE_CALLBACK_CANCEL;
348 void WRTNativeWindowOffScreen::DidFinishNavigation() {
350 evas_object_focus_set(efl_main_layout_, EINA_TRUE);
352 #endif // BUILDFLAG(IS_TIZEN_TV)