[WRTjs] Refactor popup
[platform/framework/web/chromium-efl.git] / wrt / src / browser / wrt_native_window_off_screen.cc
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.
4
5 #include "wrt/src/browser/wrt_native_window_off_screen.h"
6
7 #include <Ecore_Wl2.h>
8 #include <Elementary.h>
9
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"
15
16 #if defined(TIZEN_VIDEO_HOLE)
17 #include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller.h"
18 #endif
19
20 #if BUILDFLAG(IS_TIZEN_TV)
21 #include "base/path_service.h"
22 #include "tizen_src/chromium_impl/content/common/paths_efl.h"
23 #else
24 #include <inputmethod.h>
25 #include <watch_app_efl.h>
26 #endif // BUILDFLAG(IS_TIZEN_TV)
27
28 namespace wrt {
29
30 namespace {
31
32 #if BUILDFLAG(IS_TIZEN_TV)
33 const char* kEdjeFile = "wrtjs_tizen.edj";
34 #else
35 const char* kConfigProfile = "mobile";
36 const char* kEdjePath = "/usr/share/edje/wrtjs/wrtjs_tizen.edj";
37
38 enum class Shape { STANDARD = 0, SQUARE = 1 };
39
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))
45     return Shape::SQUARE;
46   return Shape::STANDARD;
47 }
48 #endif  // BUILDFLAG(IS_TIZEN_TV)
49
50 }  // namespace
51
52 Evas_Object* WRTNativeWindowOffScreen::elm_window_ = nullptr;
53 Evas_Object* WRTNativeWindowOffScreen::layout_ = nullptr;
54 Evas_Object* WRTNativeWindowOffScreen::conformant_ = nullptr;
55
56 // static
57 Evas_Object* WRTNativeWindowOffScreen::CreateElmWindow() {
58   if (elm_window_)
59     return elm_window_;
60
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();
71   } else
72 #endif
73     elm_window_ = elm_win_util_standard_add("", "");
74
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);
78 #else
79   elm_win_indicator_mode_set(elm_window_, ELM_WIN_INDICATOR_SHOW);
80 #endif
81
82   int window_width, window_height;
83   elm_win_screen_size_get(elm_window_, nullptr, nullptr, &window_width,
84                           &window_height);
85   evas_object_resize(elm_window_, window_width, window_height);
86
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);
93   }
94 #endif
95
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,
101                                      EVAS_HINT_EXPAND);
102     elm_win_resize_object_add(elm_window_, conformant_);
103     evas_object_show(conformant_);
104     container = conformant_;
105   }
106
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(),
112                       "web-application");
113 #else
114   if (IsWearableProfile() && GetWindowShape() == Shape::SQUARE) {
115     LOG(ERROR) << "Device shape square";
116     elm_layout_file_set(layout_, kEdjePath, "web-applicationsview");
117   } else {
118     LOG(ERROR) << "Device shape standard";
119     elm_layout_file_set(layout_, kEdjePath, "web-application");
120   }
121 #endif
122
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_);
127
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);
132 #endif
133
134   return elm_window_;
135 }
136
137 Evas_Object* WRTNativeWindowOffScreen::GetWindowEvasObject() {
138   return CreateElmWindow();
139 }
140
141 Evas_Object* WRTNativeWindowOffScreen::GetTopWindow() {
142   return elm_window_;
143 }
144
145 Evas_Object* WRTNativeWindowOffScreen::GetConformant() {
146   return conformant_;
147 }
148
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();
154
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)));
158   return host;
159 }
160
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);
167 #endif
168
169     std::map<WRTNativeWindow*, std::unique_ptr<WRTWindowTreeHost>> host_map;
170     host_map_.swap(host_map);
171     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
172         FROM_HERE,
173         base::BindOnce([](std::map<WRTNativeWindow*,
174                                    std::unique_ptr<WRTWindowTreeHost>>
175                               host_map) { host_map.clear(); },
176                        std::move(host_map)));
177   } else {
178     auto it = host_map_.find(native_window);
179     if (it != host_map_.end()) {
180       auto* host = it->second.release();
181       host_map_.erase(it);
182       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
183           FROM_HERE,
184           base::BindOnce([](WRTWindowTreeHost* host) { delete host; }, host));
185     }
186   }
187 }
188
189 void WRTNativeWindowOffScreen::InitRotation() {
190   evas_object_smart_callback_add(
191       elm_window_, "wm,rotation,changed",
192       [](void*, Evas_Object*, void*) { WRTNativeWindow::RotationCallback(); },
193       nullptr);
194 }
195
196 content::RenderWidgetHostViewAura*
197 WRTNativeWindowOffScreen::GetRenderWidgetHostView(
198     WRTNativeWindow* native_window) {
199   return static_cast<content::RenderWidgetHostViewAura*>(
200       native_window->GetWebContents()->GetRenderWidgetHostView());
201 }
202
203 int WRTNativeWindowOffScreen::SetRotationState(bool is_auto, int degree) {
204   int rotation_degree = 0;
205   if (is_auto) {
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);
211     }
212 #if BUILDFLAG(IS_TIZEN_TV)
213     // TODO(dh81.song):
214     //   need to check elm_win_wm_rotation_manual_rotation_done_set is appliable
215     //   for all profile
216     elm_win_wm_rotation_manual_rotation_done_set(elm_window_, EINA_TRUE);
217 #endif
218     rotation_degree = elm_win_rotation_get(elm_window_);
219   } else {
220     if (degree != -1)
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);
224   }
225
226   return rotation_degree;
227 }
228
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_;
235 }
236
237 void WRTNativeWindowOffScreen::SetContentView(WRTNativeWindow* native_window,
238                                               views::View* view) {
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);
244 }
245
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) {
249     auto prev_view =
250         elm_object_part_content_unset(layout_, "elm.swallow.content");
251     if (prev_view)
252       evas_object_hide(prev_view);
253     elm_object_part_content_set(layout_, "elm.swallow.content", view);
254     evas_object_show(view);
255   }
256
257   if (!evas_object_visible_get(elm_window_)) {
258     evas_object_show(elm_window_);
259     elm_win_activate(elm_window_);
260   }
261   Focus(native_window, true);
262 }
263
264 void WRTNativeWindowOffScreen::Hide() {
265   evas_object_hide(elm_window_);
266 }
267
268 bool WRTNativeWindowOffScreen::IsFocused(WRTNativeWindow* native_window) {
269   return elm_object_focus_get(elm_window_);
270 }
271
272 void WRTNativeWindowOffScreen::Focus(WRTNativeWindow* native_window,
273                                      bool focus) {
274   elm_object_focus_set(elm_window_, focus);
275   if (focus)
276     native_window->GetWebContents()->Focus();
277
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);
282 }
283
284 #if BUILDFLAG(IS_TIZEN_TV)
285 void WRTNativeWindowOffScreen::SetConformantObject(bool no_resize) {
286   if (!conformant_) {
287     LOG(ERROR) << "conformant_ is empty.";
288     return;
289   }
290
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";
299   }
300 }
301
302 void WRTNativeWindowOffScreen::SetScreenOrientation(
303     WRTNativeWindow* native_window,
304     ScreenOrientation orientation) {
305   if (!conformant_) {
306     LOG(ERROR) << "conformant_ is empty.";
307     return;
308   }
309
310   if (orientation == ScreenOrientation::LANDSCAPE_PRIMARY) {
311     LOG(INFO) << "orientation is landscape";
312     if (native_window->ShouldHandleConformantChange())
313       SetConformantObject(false);
314     else
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);
324     }
325   }
326 }
327
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);
331 #endif
332 }
333
334 void WRTNativeWindowOffScreen::SetZoomLevel(double level, const char* style) {
335   zoom_level_ = level;
336   orientation_style_ = style ? style : "";
337   ecore_idler_add(
338       [](void* data) {
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;
344       },
345       this);
346 }
347
348 void WRTNativeWindowOffScreen::DidFinishNavigation() {
349   // focus native_view
350   evas_object_focus_set(efl_main_layout_, EINA_TRUE);
351 }
352 #endif  // BUILDFLAG(IS_TIZEN_TV)
353
354 }  // namespace wrt