1 // Copyright 2014 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 "web_contents_delegate_efl.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/trace_event/ttrace.h"
9 #include "browser/input_picker/color_chooser_efl.h"
10 #include "browser/javascript_dialog_manager_efl.h"
11 #include "browser/policy_response_delegate_efl.h"
12 #include "browser_context_efl.h"
13 #include "common/render_messages_ewk.h"
14 #include "components/password_manager/core/common/password_manager_pref_names.h"
15 #include "components/prefs/pref_service.h"
16 #include "content/browser/manifest/manifest_manager_host.h"
17 #include "content/browser/web_contents/web_contents_impl.h"
18 #include "content/common/content_switches_internal.h"
19 #include "content/common/render_messages_efl.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/file_select_listener.h"
22 #include "content/public/browser/invalidate_type.h"
23 #include "content/public/browser/navigation_entry.h"
24 #include "content/public/browser/navigation_handle.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "eweb_view.h"
27 #include "eweb_view_callbacks.h"
28 #include "net/base/load_states.h"
29 #include "net/http/http_response_headers.h"
30 #include "private/ewk_certificate_private.h"
31 #include "private/ewk_console_message_private.h"
32 #include "private/ewk_custom_handlers_private.h"
33 #include "private/ewk_error_private.h"
34 #include "private/ewk_policy_decision_private.h"
35 #include "private/ewk_user_media_private.h"
36 #include "private/webview_delegate_ewk.h"
37 #include "third_party/blink/public/common/input/web_input_event.h"
38 #include "third_party/blink/public/common/manifest/manifest_util.h"
40 #include "web_contents_observer_efl.h"
42 #if BUILDFLAG(IS_TIZEN)
43 #include <app_control.h>
44 #include <app_manager.h>
47 #if defined(TIZEN_MULTIMEDIA_SUPPORT)
48 #include "content/public/browser/media_capture_devices.h"
49 #include "media/capture/video/tizen/video_capture_device_tizen.h"
52 #if defined(TIZEN_AUTOFILL_SUPPORT)
53 #include "base/command_line.h"
54 #include "browser/autofill/autofill_client_efl.h"
55 #include "browser/password_manager/password_manager_client_efl.h"
56 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
57 #include "components/autofill/core/browser/autofill_client.h"
58 #include "components/autofill/core/browser/autofill_manager.h"
59 #include "components/autofill/core/common/autofill_switches.h"
60 #include "components/web_modal/web_contents_modal_dialog_manager.h"
62 using autofill::AutofillManager;
63 using autofill::AutofillClientEfl;
64 using autofill::ContentAutofillDriverFactory;
65 using password_manager::PasswordManagerClientEfl;
73 #if BUILDFLAG(IS_TIZEN) && defined(TIZEN_MULTIMEDIA_SUPPORT)
74 static const MediaStreamDevice* GetRequestedVideoDevice(
75 const std::string& device_id) {
76 const MediaStreamDevices& video_devices =
77 MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices();
78 if (video_devices.empty())
80 if (device_id.length() == 0)
81 return &(*video_devices.begin());
82 return video_devices.FindById(device_id);
86 WebContentsDelegateEfl::WebContentsDelegateEfl(EWebView* view)
88 web_contents_(view->web_contents()),
89 contents_observer_(std::make_unique<WebContentsObserverEfl>(view, this)) {
90 #if defined(TIZEN_AUTOFILL_SUPPORT)
91 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
92 autofill::switches::kDisableAutofill)) {
93 AutofillClientEfl::CreateForWebContents(&web_contents_);
94 AutofillClientEfl* autofill_client =
95 AutofillClientEfl::FromWebContents(&web_contents_);
96 autofill_client->SetEWebView(view);
97 PasswordManagerClientEfl::CreateForWebContentsWithAutofillClient(
98 &web_contents_, autofill_client);
99 ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
100 &web_contents_, autofill_client,
101 base::BindRepeating(&autofill::BrowserDriverInitHook, autofill_client,
102 EWebView::GetPlatformLocale()));
107 WebContentsDelegateEfl::~WebContentsDelegateEfl() {
108 // It's important to delete web_contents_ before dialog_manager_
109 // destructor of web contents uses dialog_manager_
111 delete dialog_manager_;
114 WebContents* WebContentsDelegateEfl::OpenURLFromTab(
116 const OpenURLParams& params) {
117 const GURL& url = params.url;
118 WindowOpenDisposition disposition = params.disposition;
120 if (!source || (disposition != WindowOpenDisposition::CURRENT_TAB &&
121 disposition != WindowOpenDisposition::NEW_FOREGROUND_TAB &&
122 disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB &&
123 disposition != WindowOpenDisposition::OFF_THE_RECORD)) {
128 if (disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
129 disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB ||
130 disposition == WindowOpenDisposition::OFF_THE_RECORD) {
131 Evas_Object* new_object = NULL;
132 web_view_->SmartCallback<EWebViewCallbacks::CreateNewWindow>().call(
138 if (disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB)
139 ActivateContents(source);
142 WebViewDelegateEwk::GetInstance().GetWebViewFromEvasObject(new_object);
148 ui::PageTransition transition(ui::PageTransitionFromInt(params.transition));
149 source->GetController().LoadURL(url, params.referrer, transition,
154 void WebContentsDelegateEfl::NavigationStateChanged(
155 WebContents* source, InvalidateTypes changed_flags) {
156 // We always notfiy clients about title invalidation, even if its text
157 // didn't actually change. This is to maintain EWK API consistency.
158 if (changed_flags & INVALIDATE_TYPE_TITLE) {
159 web_view_->SmartCallback<EWebViewCallbacks::TitleChange>().call(
160 base::UTF16ToUTF8(source->GetTitle()).c_str());
163 // We only notify clients if visible url actually changed, because on some
164 // pages we would get notifications with flag INVALIDATE_TYPE_URL even when
165 // visible url did not change.
166 if ((changed_flags & INVALIDATE_TYPE_URL) &&
167 last_visible_url_ != source->GetVisibleURL()) {
168 last_visible_url_ = source->GetVisibleURL();
169 const char* url = last_visible_url_.spec().c_str();
171 web_view_->SmartCallback<EWebViewCallbacks::URLChanged>().call(url);
172 web_view_->SmartCallback<EWebViewCallbacks::URIChanged>().call(url);
176 void WebContentsDelegateEfl::LoadingStateChanged(WebContents* source,
177 bool to_different_document) {
178 if (source->IsLoading())
179 web_view_->SmartCallback<EWebViewCallbacks::LoadProgressStarted>().call();
181 web_view_->SmartCallback<EWebViewCallbacks::LoadProgressFinished>().call();
184 void WebContentsDelegateEfl::AddNewContents(
186 std::unique_ptr<WebContents> new_contents,
187 const GURL& target_url,
188 WindowOpenDisposition disposition,
189 const blink::mojom::WindowFeatures& window_features,
192 // Initialize the delegate for the new contents here using source's delegate
193 // as it will be needed to create a new window with the pre-created
194 // new contents in case the opener is suppressed. Otherwise, the delegate
195 // had already been initialized in EWebView::InitializeContent()
196 if (!new_contents->GetDelegate())
197 new_contents->SetDelegate(this);
199 // EWebView takes the ownership of new WebContents in
200 // EWebView::InitializeContent(). So, we can release the ownership of new
202 std::ignore = new_contents.release();
205 bool WebContentsDelegateEfl::ShouldCreateWebContents(
206 WebContents* web_contents,
207 RenderFrameHost* opener,
208 SiteInstance* source_site_instance,
209 mojom::WindowContainerType window_container_type,
210 const GURL& opener_url,
211 const std::string& frame_name,
212 const GURL& target_url,
213 const std::string& partition_id,
214 SessionStorageNamespace* session_storage_namespace) {
215 // We implement the asynchronous version of the function, this
216 // one should never be invoked.
221 void WebContentsDelegateEfl::CloseContents(WebContents* source) {
222 web_view_->SmartCallback<EWebViewCallbacks::WindowClosed>().call();
225 void WebContentsDelegateEfl::EnterFullscreenModeForTab(
226 RenderFrameHost* requesting_frame,
227 const blink::mojom::FullscreenOptions& options) {
228 is_fullscreen_ = true;
229 web_view_->SmartCallback<EWebViewCallbacks::EnterFullscreen>().call();
232 void WebContentsDelegateEfl::ExitFullscreenModeForTab(
233 WebContents* web_contents) {
234 is_fullscreen_ = false;
235 web_view_->SmartCallback<EWebViewCallbacks::ExitFullscreen>().call();
238 bool WebContentsDelegateEfl::IsFullscreenForTabOrPending(
239 const WebContents* web_contents) {
240 return is_fullscreen_;
243 void WebContentsDelegateEfl::RegisterProtocolHandler(
244 RenderFrameHost* host,
245 const std::string& protocol,
248 Ewk_Custom_Handlers_Data protocol_data(protocol.c_str(), url.host().c_str(),
250 web_view_->SmartCallback<EWebViewCallbacks::RegisterProtocolHandler>().call(
254 void WebContentsDelegateEfl::UnregisterProtocolHandler(
255 RenderFrameHost* host,
256 const std::string& protocol,
259 Ewk_Custom_Handlers_Data protocol_data(protocol.c_str(), url.host().c_str(),
261 web_view_->SmartCallback<EWebViewCallbacks::UnregisterProtocolHandler>().call(
265 #if defined(TIZEN_MULTIMEDIA_SUPPORT)
266 void WebContentsDelegateEfl::RequestMediaAccessAllow(
267 const MediaStreamRequest& request,
268 MediaResponseCallback callback) {
269 MediaStreamDevices devices;
271 if (request.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
273 MediaStreamDevice(request.audio_type, "default", "Default"));
276 if (request.video_type == MEDIA_DEVICE_VIDEO_CAPTURE) {
277 #if BUILDFLAG(IS_TIZEN)
278 const MediaStreamDevice* video_device =
279 GetRequestedVideoDevice(request.requested_video_device_id);
281 devices.push_back(*video_device);
283 std::move(callback).Run(MediaStreamDevices(), MEDIA_DEVICE_NOT_SUPPORTED,
284 std::unique_ptr<MediaStreamUI>());
288 MediaStreamDevice(request.video_type, "/dev/video0", "1"));
292 std::move(callback).Run(devices, MEDIA_DEVICE_OK,
293 std::unique_ptr<MediaStreamUI>());
296 void WebContentsDelegateEfl::RequestMediaAccessDeny(
297 const MediaStreamRequest& request,
298 MediaResponseCallback callback) {
299 LOG(ERROR) << __FUNCTION__ << " Decline request with empty list";
300 std::move(callback).Run(MediaStreamDevices(), MEDIA_DEVICE_NOT_SUPPORTED,
301 std::unique_ptr<MediaStreamUI>());
304 bool WebContentsDelegateEfl::CheckMediaAccessPermission(
305 WebContents* web_contents,
306 const GURL& security_origin,
307 MediaStreamType type) {
311 void WebContentsDelegateEfl::RequestMediaAccessPermission(
312 WebContents* web_contents,
313 const MediaStreamRequest& request,
314 MediaResponseCallback callback) {
315 std::unique_ptr<_Ewk_User_Media_Permission_Request> media_permission_request(
316 new _Ewk_User_Media_Permission_Request(this, request,
317 std::move(callback)));
319 Eina_Bool callback_result = EINA_FALSE;
320 if (!web_view_->InvokeViewUserMediaPermissionCallback(
321 media_permission_request.get(), &callback_result)) {
322 web_view_->SmartCallback<EWebViewCallbacks::UserMediaPermission>().call(
323 media_permission_request.get());
326 // if policy is suspended, the API takes over the policy object lifetime
327 // and policy will be deleted after decision is made
328 if (media_permission_request->IsSuspended())
329 ignore_result(media_permission_request.release());
330 else if (!media_permission_request->IsDecided()) {
331 callback.Run(MediaStreamDevices(), MEDIA_DEVICE_NOT_SUPPORTED,
332 std::unique_ptr<MediaStreamUI>());
337 void WebContentsDelegateEfl::OnAuthRequired(const std::string& realm,
339 LoginDelegateEfl* login_delegate) {
340 web_view_->InvokeAuthCallback(login_delegate, url, realm);
343 void WebContentsDelegateEfl::RequestCertificateConfirm(
344 WebContents* /*web_contents*/,
346 const net::SSLInfo& ssl_info,
348 bool /*overridable*/,
349 bool /*strict_enforcement*/,
350 base::OnceCallback<void(CertificateRequestResultType)> callback) {
351 #if !defined(EWK_BRINGUP) // FIXME: m67 bringup
352 // FIXME: EWK_BRINGUP definition should be removed.
354 std::string pem_certificate;
355 if (!net::X509Certificate::GetPEMEncoded(ssl_info.cert->os_cert_handle(),
357 *result = CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
360 certificate_policy_decision_.reset(new _Ewk_Certificate_Policy_Decision(
361 url, pem_certificate, cert_error, std::move(callback)));
362 #endif // !defined(EWK_BRINGUP)
363 web_view_->SmartCallback<EWebViewCallbacks::RequestCertificateConfirm>().call(
364 certificate_policy_decision_.get());
366 // if policy is suspended, the API takes over the policy object lifetime
367 // and policy will be deleted after decision is made
368 #if !defined(EWK_BRINGUP) // FIXME: m108 bringup
369 if (certificate_policy_decision_->isSuspended()) {
370 ignore_result(certificate_policy_decision_.release());
372 certificate_policy_decision_->setDecision(true);
377 void WebContentsDelegateEfl::ActivateContents(WebContents* contents) {
378 #if BUILDFLAG(IS_TIZEN)
379 app_control_h app_control = nullptr;
380 int ret = app_control_create(&app_control);
381 if (ret != APP_CONTROL_ERROR_NONE) {
382 LOG(ERROR) << "app_control_create is failed with err " << ret;
386 std::unique_ptr<std::remove_pointer<app_control_h>::type,
387 decltype(app_control_destroy)*>
388 auto_release{app_control, app_control_destroy};
390 char* app_id = nullptr;
391 ret = app_manager_get_app_id(getpid(), &app_id);
392 if (ret != APP_MANAGER_ERROR_NONE) {
393 LOG(ERROR) << "app_manager_get_app_id is failed with err " << ret;
397 ret = app_control_set_app_id(app_control, app_id);
400 if (ret != APP_CONTROL_ERROR_NONE) {
401 LOG(ERROR) << "app_control_set_app_id is failed with err " << ret;
405 ret = app_control_send_launch_request(app_control, nullptr, nullptr);
406 if (ret != APP_CONTROL_ERROR_NONE) {
407 LOG(ERROR) << "app_control_send_launch_request is failed with err " << ret;
413 void WebContentsDelegateEfl::SetContentSecurityPolicy(
414 const std::string& policy,
415 Ewk_CSP_Header_Type header_type) {
416 contents_observer_->SetContentSecurityPolicy(policy, header_type);
419 #if defined(TIZEN_AUTOFILL_SUPPORT)
420 void WebContentsDelegateEfl::UpdateAutofillIfRequired() {
421 if (AutofillClientEfl* autofill_client =
422 AutofillClientEfl::FromWebContents(&web_contents_)) {
423 autofill_client->UpdateAutofillIfRequired();
428 void WebContentsDelegateEfl::OnDidChangeFocusedNodeBounds(
429 const gfx::RectF& focused_node_bounds) {
430 #if defined(TIZEN_AUTOFILL_SUPPORT)
431 if (AutofillClientEfl* autofill_client =
432 AutofillClientEfl::FromWebContents(&web_contents_)) {
433 autofill_client->DidChangeFocusedNodeBounds(focused_node_bounds);
438 void WebContentsDelegateEfl::FindReply(WebContents* web_contents,
440 int number_of_matches,
441 const gfx::Rect& selection_rect,
442 int active_match_ordinal,
444 if (final_update && request_id == web_view_->current_find_request_id()) {
445 unsigned int uint_number_of_matches =
446 static_cast<unsigned int>(number_of_matches);
447 web_view_->SmartCallback<EWebViewCallbacks::TextFound>().call(
448 &uint_number_of_matches);
452 void WebContentsDelegateEfl::DidRenderFrame() {
453 // Call FrameRendered callback when loading and first layout is finished.
454 if (!did_render_frame_ && did_first_visually_non_empty_paint_ &&
455 (web_view_->GetProgressValue() > 0.1)) {
456 did_first_visually_non_empty_paint_ = false;
457 did_render_frame_ = true;
458 TTRACE_WEB("WebContentsDelegateEfl::DidRenderFrame");
459 LOG(INFO) << "WebContentsDelegateEfl::DidRenderFrame";
461 // "frame,rendered" message is triggered as soon as rendering of a frame
463 web_view_->SmartCallback<EWebViewCallbacks::FrameRendered>().call(0);
467 JavaScriptDialogManager* WebContentsDelegateEfl::GetJavaScriptDialogManager(
468 WebContents* source) {
469 if (!dialog_manager_)
470 dialog_manager_ = new JavaScriptDialogManagerEfl();
471 return dialog_manager_;
474 void WebContentsDelegateEfl::OnUpdateSettings(const Ewk_Settings* settings) {
475 #if defined(TIZEN_AUTOFILL_SUPPORT)
476 PasswordManagerClientEfl* client =
477 PasswordManagerClientEfl::FromWebContents(&web_contents_);
479 PrefService* prefs = client->GetPrefs();
480 prefs->SetBoolean(password_manager::prefs::kCredentialsEnableService,
481 settings->autofillPasswordForm());
486 void WebContentsDelegateEfl::DidFirstVisuallyNonEmptyPaint() {
487 did_first_visually_non_empty_paint_ = true;
488 web_view_->SmartCallback<EWebViewCallbacks::LoadNonEmptyLayoutFinished>()
492 void WebContentsDelegateEfl::DidStartLoading() {
493 did_render_frame_ = false;
496 bool WebContentsDelegateEfl::DidAddMessageToConsole(
498 blink::mojom::ConsoleMessageLevel level,
499 const std::u16string& message,
501 const std::u16string& source_id) {
502 std::unique_ptr<_Ewk_Console_Message> console_message(
503 new _Ewk_Console_Message(static_cast<unsigned>(level),
504 base::UTF16ToUTF8(message).c_str(), line_no,
505 base::UTF16ToUTF8(source_id).c_str()));
506 web_view_->SmartCallback<EWebViewCallbacks::ConsoleMessage>().call(
507 console_message.get());
511 void WebContentsDelegateEfl::RunFileChooser(
512 RenderFrameHost* render_frame_host,
513 scoped_refptr<FileSelectListener> listener,
514 const blink::mojom::FileChooserParams& params) {
515 web_view_->ShowFileChooser(render_frame_host, params);
518 std::unique_ptr<ColorChooser> WebContentsDelegateEfl::OpenColorChooser(
519 WebContents* web_contents,
521 const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions) {
522 web_view_->RequestColorPicker(SkColorGetR(color), SkColorGetG(color),
523 SkColorGetB(color), SkColorGetA(color));
524 return std::make_unique<ColorChooserEfl>(*web_contents);
527 #if !defined(EWK_BRINGUP) // FIXME: m76 bringup
528 void WebContentsDelegateEfl::OpenDateTimeDialog(
529 ui::TextInputType dialog_type,
534 const std::vector<DateTimeSuggestion>& suggestions) {
535 web_view_->InputPickerShow(dialog_type, dialog_value);
539 bool WebContentsDelegateEfl::PreHandleGestureEvent(
541 const blink::WebGestureEvent& event) {
542 blink::WebInputEvent::Type event_type = event.GetType();
543 switch (event_type) {
544 case blink::WebInputEvent::Type::kGestureDoubleTap:
548 case blink::WebInputEvent::Type::kGesturePinchBegin:
549 case blink::WebInputEvent::Type::kGesturePinchUpdate:
550 case blink::WebInputEvent::Type::kGesturePinchEnd:
551 if (!IsPinchToZoomEnabled() ||
552 IsFullscreenForTabOrPending(&web_contents()))
561 void WebContentsDelegateEfl::RequestManifestInfo(
562 Ewk_View_Request_Manifest_Callback callback,
564 WebContentsImpl* wci = static_cast<WebContentsImpl*>(&web_contents_);
565 ManifestManagerHost* manifest_manager_host =
566 ManifestManagerHost::GetOrCreateForPage(wci->GetPrimaryPage());
567 if (!manifest_manager_host) {
568 web_view_->DidRespondRequestManifest(nullptr, callback, user_data);
572 manifest_manager_host->GetManifest(
573 base::BindOnce(&WebContentsDelegateEfl::OnDidGetManifest,
574 base::Unretained(this), callback, user_data));
577 void WebContentsDelegateEfl::OnDidGetManifest(
578 Ewk_View_Request_Manifest_Callback callback,
580 const GURL& manifest_url,
581 blink::mojom::ManifestPtr manifest) {
582 if (blink::IsEmptyManifest(*manifest)) {
583 web_view_->DidRespondRequestManifest(nullptr, callback, user_data);
585 _Ewk_View_Request_Manifest ewk_manifest(std::move(manifest));
586 web_view_->DidRespondRequestManifest(&ewk_manifest, callback, user_data);
590 } // namespace content