1 #include "wrt/src/browser/wrt_web_contents.h"
3 #include "base/command_line.h"
4 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
5 #include "content/browser/web_contents/web_contents_impl.h"
6 #include "content/browser/web_contents/web_contents_view_aura.h"
7 #include "content/browser/web_contents/web_contents_view_aura_helper_efl.h"
8 #include "content/public/browser/navigation_handle.h"
9 #include "content/public/browser/render_frame_host.h"
10 #include "content/public/browser/render_view_host.h"
11 #include "content/public/browser/web_contents.h"
12 #include "content/public/common/content_switches.h"
13 #include "electron/shell/browser/web_contents_preferences.h"
14 #include "electron/shell/browser/window_list.h"
15 #include "electron/shell/common/electron_command_line.h"
16 #include "extensions/buildflags/buildflags.h"
17 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
18 #include "tizen_src/chromium_impl/content/browser/selection/selection_controller_efl.h"
19 #include "tizen_src/chromium_impl/efl/window_factory.h"
20 #include "tizen_src/chromium_impl/tizen/system_info.h"
21 #include "tizen_src/ewk/efl_integration/browser/sound_effect.h"
22 #include "tizen_src/ewk/efl_integration/public/EWebKit_internal.h"
23 #include "ui/display/screen.h"
24 #include "ui/gfx/geometry/dip_util.h"
25 #include "wrt/src/browser/native_web_runtime.h"
26 #include "wrt/src/browser/tv/wrt_select_picker_tv.h"
27 #include "wrt/src/browser/wrt_browser_context.h"
28 #include "wrt/src/browser/wrt_context_menu_controller.h"
29 #include "wrt/src/browser/wrt_native_window.h"
30 #include "wrt/src/browser/wrt_select_picker.h"
31 #include "wrt/src/browser/wrt_web_view_delegate.h"
32 #include "wrt/src/common/application_data.h"
33 #include "wrt/src/common/wrt_service_message_channel.h"
34 #include "wrt/src/service/wrt_service.h"
35 #include "wrt/src/service/wrt_service_launcher.h"
36 #include "wrt/src/service/wrt_service_manager.h"
38 #if BUILDFLAG(IS_TIZEN_TV)
39 #include "wrt/src/browser/tv/wrt_native_window_tv.h"
42 #if defined(TIZEN_ATK_SUPPORT)
43 #include "tizen_src/ewk/efl_integration/eweb_accessibility_util.h"
46 #if ENABLE_CHROME_EXTENSIONS
47 #include "wrt/src/browser/extensions/extension_util.h"
54 template <typename Callback>
55 void NotifyMessageOnUIThread(const std::string& type,
56 const std::vector<std::string>& params,
58 content::GetUIThreadTaskRunner({})->PostTask(
60 base::BindOnce([](const std::string& type,
61 const std::vector<std::string>& params,
63 auto& runtime = NativeWebRuntime::GetInstance();
64 bool result = runtime.NotifyMessage(type, params);
65 std::move(callback).Run(result);
66 }, type, params, std::move(callback)));
69 SelectPickerBase* CreateSelectPicker(
70 content::WebContents* web_contents,
72 std::vector<blink::mojom::MenuItemPtr> items,
73 bool is_multiple_selection,
74 const gfx::Rect& bounds,
75 double item_font_size) {
76 SelectPickerBase* picker;
77 Evas_Object* view_evas =
78 WRTNativeWindow::FromWebContents(web_contents)->view_evas();
79 #if BUILDFLAG(IS_TIZEN_TV)
80 picker = new WRTSelectPickerTv(web_contents, selected_index,
81 is_multiple_selection, view_evas);
82 picker->SetFontSizeAsItem(item_font_size);
84 picker = new WRTSelectPicker(web_contents, selected_index,
85 is_multiple_selection, view_evas);
87 // Create two separate Elm_Genlist_Item_Class classes, because EFL cannot swap
88 // item_style at runtime.
89 picker->InitializeItemClass();
90 picker->InitializeGroupClass();
91 picker->Init(std::move(items), bounds);
98 std::map<content::WebContents*, std::unique_ptr<WRTWebContents>>
102 void WRTWebContents::WebContentsCreated(content::WebContents* web_contents) {
104 std::unique_ptr<WRTWebContents>(new WRTWebContents(web_contents));
108 void WRTWebContents::WebContentsDeleted(content::WebContents* web_contents) {
109 map_.erase(web_contents);
113 bool WRTWebContents::IsObservedWebContents(
114 content::WebContents* web_contents) {
115 return (map_.find(web_contents) != map_.end());
119 WRTWebContents* WRTWebContents::FromWebContents(
120 content::WebContents* web_contents) {
121 auto it = map_.find(web_contents);
122 return (it != map_.end()) ? it->second.get() : nullptr;
126 WRTWebContents* WRTWebContents::FromNativeWindow(WRTNativeWindow* window) {
127 for (auto& it : map_) {
128 auto* relay = it.first->GetUserData(
129 electron::NativeWindowRelay::UserDataKey());
130 auto* relay_window = relay ?
131 static_cast<electron::NativeWindowRelay*>(relay)->GetNativeWindow() :
133 if (window == relay_window)
134 return it.second.get();
140 content::WebContents* WRTWebContents::GetWebContents() {
141 return map_.empty() ? nullptr : map_.begin()->first;
145 void WRTWebContents::BindBrowser(
146 mojo::PendingAssociatedReceiver<mojom::WRTBrowser> receiver,
147 content::RenderFrameHost* render_frame_host) {
149 content::WebContents::FromRenderFrameHost(render_frame_host);
150 auto* wrt_web_contents = FromWebContents(web_contents);
151 if (!wrt_web_contents)
153 wrt_web_contents->receivers_.Bind(render_frame_host, std::move(receiver));
156 content::WebContentsViewAura* WRTWebContents::GetWebContentsViewAura() const {
157 content::WebContentsImpl* wc =
158 static_cast<content::WebContentsImpl*>(web_contents());
159 return static_cast<content::WebContentsViewAura*>(wc->GetView());
162 content::WebContentsViewAuraHelperEfl*
163 WRTWebContents::GetWebContentsViewAuraHelper() {
164 auto* wcva = GetWebContentsViewAura();
165 return wcva ? wcva->wcva_helper() : nullptr;
168 #if BUILDFLAG(IS_TIZEN_TV)
169 content::RWHVAuraCommonHelperEfl* WRTWebContents::GetRWHVAEflHelper() {
170 return rwhva() ? rwhva()->aura_efl_helper() : nullptr;
174 WRTWebContents::WRTWebContents(content::WebContents* web_contents)
175 : receivers_(web_contents, this),
176 thread_("service_thread"),
177 show_ime_panel_(true),
178 ime_is_floating_(false),
179 use_keypad_without_user_action_(false) {
180 Observe(web_contents);
182 page_scale_factor_ = 1.0;
183 if (auto* aura_helper = GetWebContentsViewAuraHelper()) {
184 web_view_delegate_.reset(new WRTWebViewDelegate(this));
185 aura_helper->SetWebviewDelegate(web_view_delegate_.get());
188 static_cast<content::WebContentsImpl*>(web_contents)
189 ->set_ewk_view(efl::WindowFactory::GetHostWindow(web_contents));
192 WRTWebContents::~WRTWebContents() {
193 if (auto* aura_helper = GetWebContentsViewAuraHelper())
194 aura_helper->SetWebviewDelegate(nullptr);
195 web_view_delegate_.reset();
196 select_picker_.reset();
197 if (thread_.IsRunning())
201 mojom::WRTRenderer* WRTWebContents::GetRendererInterface() {
202 auto* frame = web_contents()->GetPrimaryMainFrame();
204 frame->GetRemoteAssociatedInterfaces()->GetInterface(&renderer_interface_);
205 return renderer_interface_.get();
211 void WRTWebContents::RenderFrameCreated(
212 content::RenderFrameHost* render_frame_host) {
213 SetExtraCommandLineSwitches(render_frame_host);
214 SetLongPollingTimeout();
217 void WRTWebContents::RenderViewReady() {
218 #if BUILDFLAG(IS_TIZEN_TV)
219 auto native_window_tv = static_cast<WRTNativeWindowTV*>(
220 WRTNativeWindow::FromWebContents(web_contents()));
221 if (native_window_tv && native_window_tv->NeedSetCursorPointer())
224 if (auto* aura_efl_helper = GetRWHVAEflHelper())
225 aura_efl_helper->SetCursorByClient(true);
229 void WRTWebContents::OnPageScaleFactorChanged(float page_scale_factor) {
230 page_scale_factor_ = page_scale_factor;
231 SetScaledContentSize();
234 void WRTWebContents::SetScaledContentSize() {
235 if (!rwhva() || !rwhva()->aura_efl_helper())
238 const float device_scale_factor =
239 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
240 gfx::SizeF scaled_contents_size = gfx::ConvertSizeToPixels(
241 contents_size_, device_scale_factor * page_scale_factor_);
242 rwhva()->aura_efl_helper()->SetScaledContentSize(scaled_contents_size);
245 void WRTWebContents::SetExtraCommandLineSwitches(
246 content::RenderFrameHost* render_frame_host) {
247 auto* command_line = base::CommandLine::ForCurrentProcess();
248 if (!command_line->HasSwitch(switches::kSingleProcess) || map_.size() > 1)
252 content::WebContents::FromRenderFrameHost(render_frame_host);
253 if (!IsObservedWebContents(web_contents))
256 auto* web_preferences = electron::WebContentsPreferences::From(web_contents);
257 if (web_preferences) {
258 base::CommandLine extra(base::CommandLine::NO_PROGRAM);
259 web_preferences->AppendCommandLineSwitches(&extra, false);
260 base::CommandLine::SwitchMap switches = extra.GetSwitches();
261 switches.erase(switches::kNoZygote);
262 for (const auto& sw : switches)
263 command_line->AppendSwitchNative(sw.first, sw.second);
264 electron::ElectronCommandLine::InitializeFromCommandLine();
268 void WRTWebContents::SetLongPollingTimeout() {
269 auto& setting_info = ApplicationData::GetInstance().setting_info();
270 auto polling_val(setting_info.long_polling());
271 auto* renderer = GetRendererInterface();
272 if (!polling_val || !renderer)
275 renderer->SetLongPollingTimeout(*polling_val);
278 void WRTWebContents::DidFinishNavigation(
279 content::NavigationHandle* navigation_handle) {
280 if (navigation_handle->ShouldUpdateHistory())
281 static_cast<WRTBrowserContext*>(web_contents()->GetBrowserContext())
282 ->AddVisitedURLs(navigation_handle->GetRedirectChain());
284 #if BUILDFLAG(IS_TIZEN_TV)
285 auto native_window_tv =
286 static_cast<WRTNativeWindowTV*>(
287 WRTNativeWindow::FromWebContents(web_contents()));
288 if (native_window_tv) {
289 native_window_tv->GetImeAndKeyPadConfig(show_ime_panel_, ime_is_floating_,
290 use_keypad_without_user_action_);
291 native_window_tv->DidFinishNavigation(
292 navigation_handle->GetURL().possibly_invalid_spec());
296 #if defined(TIZEN_ATK_SUPPORT)
297 static bool lazy_initialize_atk_ = true;
298 EWebAccessibilityUtil::GetInstance()->ToggleAtk(lazy_initialize_atk_);
302 void WRTWebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host,
303 const GURL& validated_url) {
304 #if ENABLE_CHROME_EXTENSIONS
305 if (web_contents()->GetPrimaryMainFrame() == render_frame_host)
306 extensions::util::SendExtensionActionInfo(this);
308 // Set focus to WebContents after load is finished. This makes sure
309 // JS focus events (eg. onfocus) are disaptched as expected.
310 web_contents()->Focus();
313 content::RenderWidgetHostViewAura* WRTWebContents::rwhva() const {
314 return static_cast<content::RenderWidgetHostViewAura*>(
315 web_contents()->GetRenderWidgetHostView());
318 Evas_Object* WRTWebContents::evas_object() {
319 return efl::WindowFactory::GetHostWindow(web_contents());
322 content::SelectionControllerEfl*
323 WRTWebContents::GetSelectionController() const {
324 #if defined(WRT_JS_BRINGUP)
328 return view ? view->GetSelectionController() : nullptr;
332 void WRTWebContents::UpdateContextMenuWithParams(
333 const content::ContextMenuParams& params) {
335 new WRTContextMenuController(*web_contents(), this));
336 if (!context_menu_->PopulateAndShowContextMenu(params)) {
337 context_menu_.reset();
338 if (GetSelectionController())
339 GetSelectionController()->HideHandles();
343 void WRTWebContents::ShowContextMenuInternal(
344 const content::ContextMenuParams& params) {
345 if (params.is_editable) {
346 auto* renderer = GetRendererInterface();
349 renderer->QueryInputType(
350 base::BindOnce([](content::WebContents* web_contents,
351 content::ContextMenuParams params,
352 bool is_password_input) -> void {
353 auto* wrt_web_contents =
354 WRTWebContents::FromWebContents(web_contents);
355 if (!wrt_web_contents)
358 if (is_password_input) {
359 params.form_control_type =
360 blink::mojom::FormControlType::kInputPassword;
362 wrt_web_contents->UpdateContextMenuWithParams(params);
363 }, web_contents(), params));
365 UpdateContextMenuWithParams(params);
369 void WRTWebContents::HandleLongPressGesture(
370 const content::ContextMenuParams& params) {
371 // This menu is created in renderer process and it does not know anything about
372 // view scaling factor and it has another calling sequence, so coordinates is
374 if (!(IsMobileProfile() || IsDesktopProfile())) {
375 LOG(ERROR) << "Touch events are not supported";
379 if (!rwhva() || !rwhva()->aura_efl_helper())
381 content::ContextMenuParams convertedParams = params;
382 gfx::Point convertedPoint = rwhva()->aura_efl_helper()->ConvertPointInViewPix(
383 gfx::Point(params.x, params.y));
384 convertedParams.x = convertedPoint.x();
385 convertedParams.y = convertedPoint.y();
388 evas_object_geometry_get(evas_object(), &x, &y, 0, 0);
389 convertedParams.x += x;
390 convertedParams.y += y;
392 bool show_context_menu_now = true;
393 if (GetSelectionController() && GetSelectionController()->GetLongPressed()) {
394 show_context_menu_now =
395 !GetSelectionController()->HandleLongPressEvent(convertedPoint,
398 if (show_context_menu_now)
399 ShowContextMenuInternal(convertedParams);
402 void WRTWebContents::ShowContextMenu(
403 const content::ContextMenuParams& params) {
404 if (params.source_type == ui::MENU_SOURCE_LONG_PRESS) {
405 HandleLongPressGesture(params);
409 if (!rwhva() || !rwhva()->aura_efl_helper())
411 // This menu is created in renderer process and it does not know anything about
412 // view scaling factor and it has another calling sequence, so coordinates is
414 content::ContextMenuParams convertedParams = params;
415 gfx::Point convertedPoint = rwhva()->aura_efl_helper()->ConvertPointInViewPix(
416 gfx::Point(params.x, params.y));
417 convertedParams.x = convertedPoint.x();
418 convertedParams.y = convertedPoint.y();
421 evas_object_geometry_get(evas_object(), &x, &y, 0, 0);
422 convertedParams.x += x;
423 convertedParams.y += y;
425 ShowContextMenuInternal(convertedParams);
428 void WRTWebContents::OnSelectionRectReceived(
429 const gfx::Rect& selection_rect) const {
431 context_menu_->OnSelectionRectReceived(selection_rect);
434 void WRTWebContents::ExecuteEditCommand(const char* command,
439 absl::optional<std::u16string> optional_value;
441 optional_value = absl::make_optional(base::ASCIIToUTF16(value));
443 static_cast<content::WebContentsImpl*>(web_contents())
444 ->ExecuteEditCommand(std::string(command), optional_value);
447 void WRTWebContents::HideContextMenu() {
449 context_menu_->HideContextMenu();
452 void WRTWebContents::ResetControllers() {
453 context_menu_.reset();
454 auto* selection_controller = GetSelectionController();
455 if (selection_controller)
456 selection_controller->ClearSelection();
459 void WRTWebContents::ShowPopupMenuImpl(
460 std::vector<blink::mojom::MenuItemPtr> items,
463 const gfx::Rect& bounds,
464 double item_font_size) {
465 if (!select_picker_) {
466 select_picker_.reset(CreateSelectPicker(web_contents(), selectedIndex,
467 std::move(items), multiple, bounds,
469 // Picker has been shown on top of webview and the page content gets
470 // partially overlapped. Decrease viewport while showing picker.
471 AdjustViewPortHeightToPopupMenu(true /* is_popup_menu_visible */);
472 is_popup_showing_ = true;
473 ScrollFocusedNodeIntoView();
475 select_picker_->UpdatePickerData(selectedIndex, std::move(items), multiple);
477 #if BUILDFLAG(IS_TIZEN_TV)
478 if (auto* aura_efl_helper = GetRWHVAEflHelper())
479 aura_efl_helper->SetPopupMenuVisible(true);
481 select_picker_->Show();
484 void WRTWebContents::HidePopupMenuImpl() {
485 is_popup_showing_ = false;
490 AdjustViewPortHeightToPopupMenu(false /* is_popup_menu_visible */);
491 #if BUILDFLAG(IS_TIZEN_TV)
492 if (auto* aura_efl_helper = GetRWHVAEflHelper()) {
493 aura_efl_helper->SetPopupMenuVisible(false);
494 aura_efl_helper->SetPopupMenuBounds(gfx::Rect(0, 0, 0, 0));
497 select_picker_.reset();
500 void WRTWebContents::AdjustViewPortHeightToPopupMenu(
501 bool is_popup_menu_visible) {
502 if (!rwhva() || !rwhva()->aura_efl_helper() || !IsMobileProfile() ||
503 NativeWebRuntime::GetInstance().IsTizenWebKitCompatibilityEnabled()) {
507 int picker_height = select_picker_->GetGeometryDIP().height();
508 gfx::Rect screen_rect =
509 display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
510 gfx::Rect view_rect = rwhva()->GetViewBounds();
512 screen_rect.height() - (view_rect.y() + view_rect.height());
514 rwhva()->aura_efl_helper()->SetCustomViewportSize(
515 is_popup_menu_visible
516 ? gfx::Size(view_rect.width(),
517 view_rect.height() - picker_height + bottom_height)
521 void WRTWebContents::ScrollFocusedNodeIntoView() {
522 auto* renderer = GetRendererInterface();
525 renderer->ScrollFocusedNodeIntoView();
528 void WRTWebContents::StartService(
529 const std::string& internal_id,
530 mojo::PendingRemote<mojom::WRTServiceMessageListener> remote,
531 StartServiceCallback callback) {
532 auto& app_data = ApplicationData::GetInstance();
533 auto service_id = ApplicationData::GetServiceID(internal_id);
534 if (app_data.IsGlobalServiceApp(service_id)) {
535 LOG(INFO) << "Starting global service...";
536 if (!thread_.IsRunning())
539 thread_.task_runner()->PostTask(
541 base::BindOnce([](const std::string& internal_id,
542 StartServiceCallback callback) {
544 auto wrt_service_launcher = WRTServiceLauncher::Get();
545 if (!wrt_service_launcher->LaunchWrtService()) {
546 std::move(callback).Run(false);
549 if (wrt_service_launcher->IsWrtServiceReady() &&
550 wrt_service_launcher->IsWrtServiceDbusReady() &&
551 WRTService::StartService(internal_id)) {
552 std::move(callback).Run(true);
554 std::move(callback).Run(false);
556 }, internal_id, std::move(callback)));
558 LOG(INFO) << "Starting ui service...";
559 auto service_manager = WRTServiceManager::Get();
560 service_manager->SetServiceModel(WRTService::UI_DEDICATED);
563 new WRTBrowserServiceMessageChannel(internal_id, std::move(remote));
565 LOG(ERROR) << "Fail to create message channel";
566 std::move(callback).Run(false);
570 auto service_path = app_data.GetStartServiceFile();
571 std::vector<std::string> params{ internal_id, service_path };
572 NotifyMessageOnUIThread("startService", params, std::move(callback));
576 void WRTWebContents::StopService(const std::string& internal_id,
577 StopServiceCallback callback) {
578 auto& app_data = ApplicationData::GetInstance();
579 if (app_data.IsGlobalServiceApp(ApplicationData::GetServiceID(internal_id))) {
580 if (!thread_.IsRunning())
583 thread_.task_runner()->PostTask(
585 base::BindOnce([](const std::string& internal_id,
586 StopServiceCallback callback) {
587 if (!WRTService::StopService(internal_id)) {
588 std::move(callback).Run(false);
590 std::move(callback).Run(true);
592 }, internal_id, std::move(callback)));
594 std::vector<std::string> params{ internal_id };
595 NotifyMessageOnUIThread("stopService", params, std::move(callback));
596 WRTBrowserServiceMessageChannel::RemoveMessageChannel(internal_id);
600 void WRTWebContents::PlayLinkEffect() {
601 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
602 sound_effect::playLinkEffect();
605 void WRTWebContents::DidChangeContentsSize(const gfx::Size& size) {
606 contents_size_ = size;
607 SetScaledContentSize();
610 void WRTWebContents::DidHandleGestureEventWithContext(
611 bool is_content_editable) {
612 if (!GetSelectionController())
615 GetSelectionController()->PostHandleTapGesture(is_content_editable);