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/prefs/pref_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "browser/favicon/favicon_service.h"
10 #include "browser/inputpicker/color_chooser_efl.h"
11 #include "browser/javascript_dialog_manager_efl.h"
12 #include "browser/policy_response_delegate_efl.h"
13 #include "common/render_messages_ewk.h"
14 #include "components/password_manager/core/common/password_manager_pref_names.h"
15 #include "content/browser/renderer_host/render_widget_host_view_efl.h"
16 #include "content/common/content_switches_internal.h"
17 #include "content/common/date_time_suggestion.h"
18 #include "content/common/render_messages_efl.h"
19 #include "content/common/view_messages.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/favicon_status.h"
22 #include "content/public/browser/invalidate_type.h"
23 #include "content/public/browser/navigation_entry.h"
24 #include "content/public/common/favicon_url.h"
25 #include "eweb_view.h"
26 #include "eweb_view_callbacks.h"
27 #include "net/base/load_states.h"
28 #include "net/http/http_response_headers.h"
29 #include "printing/pdf_metafile_skia.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 "public/web/WebInputEvent.h"
41 #include "content/public/browser/media_capture_devices.h"
42 #include "media/capture/video/tizen/video_capture_device_tizen.h"
45 #if defined(TIZEN_AUTOFILL_SUPPORT)
46 #include "browser/autofill/autofill_manager_delegate_efl.h"
47 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
48 #include "browser/password_manager/password_manager_client_efl.h"
49 #include "components/autofill/core/browser/autofill_client.h"
50 #include "components/autofill/core/browser/autofill_manager.h"
51 #include "components/web_modal/web_contents_modal_dialog_manager.h"
53 using autofill::AutofillManager;
54 using autofill::AutofillManagerDelegateEfl;
55 using autofill::ContentAutofillDriverFactory;
56 using password_manager::PasswordManagerClientEfl;
63 void WritePdfDataToFile(printing::PdfMetafileSkia* metafile, const base::FilePath& filename) {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
66 base::File file(filename, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
67 metafile->SaveTo(&file);
73 static const content::MediaStreamDevice*
74 GetRequestedVideoDevice(const std::string& device_id) {
75 const content::MediaStreamDevices& video_devices =
76 MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices();
77 if (video_devices.empty())
79 if (device_id.length() == 0)
80 return &(*video_devices.begin());
81 return video_devices.FindById(device_id);
85 WebContentsDelegateEfl::WebContentsDelegateEfl(EWebView* view)
86 : WebContentsObserver(&view->web_contents())
88 , is_fullscreen_(false)
89 , web_contents_(view->web_contents())
90 , document_created_(false)
91 , dialog_manager_(NULL)
92 , weak_ptr_factory_(this) {
93 #if defined(TIZEN_AUTOFILL_SUPPORT)
94 AutofillManagerDelegateEfl::CreateForWebContents(&web_contents_);
95 AutofillManagerDelegateEfl* autofill_manager =
96 AutofillManagerDelegateEfl::FromWebContents(&web_contents_);
97 autofill_manager->SetEWebView(view);
98 PasswordManagerClientEfl::CreateForWebContentsWithAutofillClient(&web_contents_,
100 ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(&web_contents_,
102 EWebView::GetPlatformLocale(),
103 AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
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 content::OpenURLParams& params) {
118 const GURL& url = params.url;
119 WindowOpenDisposition disposition = params.disposition;
121 if (!source || (disposition != CURRENT_TAB &&
122 disposition != NEW_FOREGROUND_TAB &&
123 disposition != NEW_BACKGROUND_TAB &&
124 disposition != OFF_THE_RECORD)) {
129 if (disposition == NEW_FOREGROUND_TAB ||
130 disposition == NEW_BACKGROUND_TAB ||
131 disposition == OFF_THE_RECORD) {
132 Evas_Object* new_object = NULL;
133 web_view_->SmartCallback<EWebViewCallbacks::CreateNewWindow>().call(&new_object);
138 EWebView* wv = WebViewDelegateEwk::GetInstance().
139 GetWebViewFromEvasObject(new_object);
145 ui::PageTransition transition(ui::PageTransitionFromInt(params.transition));
146 source->GetController().LoadURL(url, params.referrer, transition,
151 void WebContentsDelegateEfl::NavigationStateChanged(
152 WebContents* source, InvalidateTypes changed_flags) {
153 if (changed_flags & content::INVALIDATE_TYPE_URL) {
154 const char* url = source->GetVisibleURL().spec().c_str();
155 web_view_->SmartCallback<EWebViewCallbacks::URLChanged>().call(url);
156 web_view_->SmartCallback<EWebViewCallbacks::URIChanged>().call(url);
160 void WebContentsDelegateEfl::LoadingStateChanged(WebContents* source,
161 bool to_different_document) {
162 if (source->IsLoading())
163 web_view_->SmartCallback<EWebViewCallbacks::LoadProgressStarted>().call();
165 web_view_->SmartCallback<EWebViewCallbacks::LoadProgressFinished>().call();
168 void WebContentsDelegateEfl::LoadProgressChanged(WebContents* source, double progress) {
169 web_view_->SetProgressValue(progress);
170 web_view_->SmartCallback<EWebViewCallbacks::LoadProgress>().call(&progress);
173 bool WebContentsDelegateEfl::ShouldCreateWebContents(
174 WebContents* web_contents,
176 int main_frame_route_id,
177 WindowContainerType window_container_type,
178 const std::string& frame_name,
179 const GURL& target_url,
180 const std::string& partition_id,
181 SessionStorageNamespace* session_storage_namespace) {
182 // We implement the asynchronous version of the function, this
183 // one should never be invoked.
188 void WebContentsDelegateEfl::CloseContents(WebContents* source) {
189 web_view_->SmartCallback<EWebViewCallbacks::WindowClosed>().call();
192 void WebContentsDelegateEfl::EnterFullscreenModeForTab(content::WebContents* web_contents,
193 const GURL& origin) {
194 is_fullscreen_ = true;
195 web_view_->SmartCallback<EWebViewCallbacks::EnterFullscreen>().call();
198 void WebContentsDelegateEfl::ExitFullscreenModeForTab(content::WebContents* web_contents) {
199 is_fullscreen_ = false;
200 web_view_->SmartCallback<EWebViewCallbacks::ExitFullscreen>().call();
203 bool WebContentsDelegateEfl::IsFullscreenForTabOrPending(
204 const WebContents* web_contents) const {
205 return is_fullscreen_;
208 void WebContentsDelegateEfl::RegisterProtocolHandler(WebContents* web_contents,
209 const std::string& protocol, const GURL& url, bool user_gesture) {
210 Ewk_Custom_Handlers_Data protocol_data(protocol.c_str(),
211 url.host().c_str(), url.spec().c_str());
212 web_view_->SmartCallback<EWebViewCallbacks::RegisterProtocolHandler>().call(&protocol_data);
215 void WebContentsDelegateEfl::UnregisterProtocolHandler(WebContents* web_contents,
216 const std::string& protocol,
219 Ewk_Custom_Handlers_Data protocol_data(protocol.c_str(),
220 url.host().c_str(), url.spec().c_str());
221 web_view_->SmartCallback<EWebViewCallbacks::UnregisterProtocolHandler>()
222 .call(&protocol_data);
225 #if defined(TIZEN_MULTIMEDIA_SUPPORT)
226 void WebContentsDelegateEfl::RequestMediaAccessAllow(
227 const MediaStreamRequest& request,
228 const MediaResponseCallback& callback) {
230 MediaStreamDevices devices;
232 if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
233 devices.push_back(MediaStreamDevice(request.audio_type,
234 "default", "Default"));
237 if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
238 #if defined(OS_TIZEN)
239 const content::MediaStreamDevice* video_device =
240 GetRequestedVideoDevice(request.requested_video_device_id);
242 devices.push_back(*video_device);
245 callback.Run(MediaStreamDevices(), MEDIA_DEVICE_NOT_SUPPORTED,
246 scoped_ptr<MediaStreamUI>());
249 devices.push_back(MediaStreamDevice(request.video_type, "/dev/video0", "1"));
253 callback.Run(devices, MEDIA_DEVICE_OK,scoped_ptr<MediaStreamUI>());
256 void WebContentsDelegateEfl::RequestMediaAccessDeny(
257 const MediaStreamRequest& request,
258 const MediaResponseCallback& callback) {
259 LOG(ERROR) << __FUNCTION__ << " Decline request with empty list";
260 callback.Run(MediaStreamDevices(), MEDIA_DEVICE_NOT_SUPPORTED,
261 scoped_ptr<MediaStreamUI>());
264 bool WebContentsDelegateEfl::CheckMediaAccessPermission(
265 WebContents* web_contents,
266 const GURL& security_origin,
267 MediaStreamType type) {
271 void WebContentsDelegateEfl::RequestMediaAccessPermission(
272 WebContents* web_contents,
273 const MediaStreamRequest& request,
274 const MediaResponseCallback& callback) {
275 scoped_ptr<_Ewk_User_Media_Permission_Request> media_permission_request(
276 new _Ewk_User_Media_Permission_Request(this, request, callback));
278 Eina_Bool callback_result = EINA_FALSE;
279 if (!web_view_->InvokeViewUserMediaPermissionCallback(
280 media_permission_request.get(), &callback_result)) {
281 web_view_->SmartCallback<EWebViewCallbacks::UserMediaPermission>()
282 .call(media_permission_request.get());
285 if (media_permission_request->IsSuspended())
286 media_permission_request.release();
287 else if (!media_permission_request->IsDecided()) {
288 callback.Run(MediaStreamDevices(), MEDIA_DEVICE_NOT_SUPPORTED,
289 scoped_ptr<MediaStreamUI>());
294 void WebContentsDelegateEfl::OnAuthRequired(net::URLRequest* request,
295 const std::string& realm,
296 LoginDelegateEfl* login_delegate) {
297 web_view_->InvokeAuthCallback(login_delegate, request->url(), realm);
300 void WebContentsDelegateEfl::DidStartProvisionalLoadForFrame(RenderFrameHost* render_frame_host,
301 const GURL& validated_url,
303 bool is_iframe_srcdoc) {
304 web_view_->SmartCallback<EWebViewCallbacks::ProvisionalLoadStarted>().call();
307 void WebContentsDelegateEfl::DidCommitProvisionalLoadForFrame(RenderFrameHost* render_frame_host,
309 ui::PageTransition transition_type) {
310 web_view_->SmartCallback<EWebViewCallbacks::LoadCommitted>().call();
314 void WebContentsDelegateEfl::DidNavigateMainFrame(const LoadCommittedDetails& details,
315 const FrameNavigateParams& params) {
316 // The condition checks whether the main frame navigated to a different page,
317 // not scrolled to a fragment inside the current page.
318 if (details.is_navigation_to_different_page())
319 web_view_->SmartCallback<EWebViewCallbacks::LoadStarted>().call();
322 void WebContentsDelegateEfl::DocumentOnLoadCompletedInMainFrame() {
323 web_view_->SmartCallback<EWebViewCallbacks::LoadFinished>().call();
326 void WebContentsDelegateEfl::DidNavigateAnyFrame(RenderFrameHost* render_frame_host, const LoadCommittedDetails& details, const FrameNavigateParams& params) {
327 web_view_->SmartCallback<EWebViewCallbacks::ProvisionalLoadRedirect>().call();
328 static_cast<BrowserContextEfl*>(web_contents_.GetBrowserContext())->AddVisitedURLs(params.redirects);
331 void WebContentsDelegateEfl::DidFinishLoad(RenderFrameHost* render_frame_host,
332 const GURL& validated_url) {
333 if (render_frame_host->GetParent())
336 NavigationEntry *entry = web_contents().GetController().GetVisibleEntry();
340 FaviconStatus &favicon = entry->GetFavicon();
343 // check/update the url and favicon url in favicon database
345 fs.SetFaviconURLForPageURL(favicon.url, validated_url);
347 // download favicon if there is no such in database
348 if (!fs.ExistsForFaviconURL(favicon.url)) {
349 LOG(ERROR) << "[DidFinishLoad] :: no favicon in database for URL: "
350 << favicon.url.spec();
351 favicon_downloader_.reset(
352 new FaviconDownloader(&web_contents_,
355 &WebContentsDelegateEfl::DidDownloadFavicon,
356 weak_ptr_factory_.GetWeakPtr())));
357 favicon_downloader_->Start();
359 web_view_->SmartCallback<EWebViewCallbacks::IconReceived>().call();
363 web_contents_.Focus();
367 void WebContentsDelegateEfl::DidUpdateFaviconURL(const std::vector<FaviconURL>& candidates) {
368 // select and set proper favicon
369 for (unsigned int i = 0; i < candidates.size(); ++i) {
370 FaviconURL favicon = candidates[i];
371 if (favicon.icon_type == FaviconURL::FAVICON && !favicon.icon_url.is_empty()) {
372 NavigationEntry *entry = web_contents_.GetController().GetVisibleEntry();
375 entry->GetFavicon().url = favicon.icon_url;
376 entry->GetFavicon().valid = true;
383 void WebContentsDelegateEfl::DidDownloadFavicon(bool success, const GURL& icon_url, const SkBitmap& bitmap) {
384 favicon_downloader_.reset();
387 fs.SetBitmapForFaviconURL(bitmap, icon_url);
388 // emit "icon,received"
389 web_view_->SmartCallback<EWebViewCallbacks::IconReceived>().call();
393 void WebContentsDelegateEfl::RequestCertificateConfirm(WebContents* /*web_contents*/,
395 const net::SSLInfo& ssl_info,
397 ResourceType /*resource_type*/,
398 bool /*overridable*/,
399 bool /*strict_enforcement*/,
400 const base::Callback<void(bool)>& callback,
401 CertificateRequestResultType* result) {
403 std::string pem_certificate;
404 if (!net::X509Certificate::GetPEMEncoded(ssl_info.cert->os_cert_handle(), &pem_certificate)) {
405 *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
408 certificate_policy_decision_.reset(new _Ewk_Certificate_Policy_Decision(url,
412 web_view_->SmartCallback<EWebViewCallbacks::RequestCertificateConfirm>().call(
413 certificate_policy_decision_.get());
415 // if policy is suspended, the API takes over the policy object lifetime
416 // and policy will be deleted after decision is made
417 if (certificate_policy_decision_->isSuspended()) {
418 certificate_policy_decision_.release();
420 certificate_policy_decision_->setDecision(true);
424 void WebContentsDelegateEfl::SetContentSecurityPolicy(const std::string& policy, Ewk_CSP_Header_Type header_type) {
425 if (document_created_) {
426 RenderViewHost* rvh = web_contents_.GetRenderViewHost();
427 rvh->Send(new EwkViewMsg_SetCSP(rvh->GetRoutingID(), policy, header_type));
429 DCHECK(!pending_content_security_policy_.get());
430 pending_content_security_policy_.reset(new ContentSecurityPolicy(policy, header_type));
434 void WebContentsDelegateEfl::FindReply(WebContents* web_contents,
436 int number_of_matches,
437 const gfx::Rect& selection_rect,
438 int active_match_ordinal,
440 if (final_update && request_id == web_view_->current_find_request_id()) {
441 unsigned int uint_number_of_matches = static_cast<unsigned int>(number_of_matches);
442 web_view_->SmartCallback<EWebViewCallbacks::TextFound>().call(&uint_number_of_matches);
446 JavaScriptDialogManager* WebContentsDelegateEfl::GetJavaScriptDialogManager(
447 WebContents* source) {
448 if (!dialog_manager_)
449 dialog_manager_ = new JavaScriptDialogManagerEfl();
450 return dialog_manager_;
453 void WebContentsDelegateEfl::OnUpdateSettings(const Ewk_Settings *settings) {
454 #if defined(TIZEN_AUTOFILL_SUPPORT)
455 PasswordManagerClientEfl* client =
456 PasswordManagerClientEfl::FromWebContents(&web_contents_);
458 PrefService* prefs = client->GetPrefs();
459 prefs->SetBoolean(password_manager::prefs::kPasswordManagerSavingEnabled,
460 settings->autofillPasswordForm());
465 bool WebContentsDelegateEfl::OnMessageReceived(const IPC::Message& message) {
467 IPC_BEGIN_MESSAGE_MAP(WebContentsDelegateEfl, message)
468 IPC_MESSAGE_HANDLER_DELAY_REPLY(EwkHostMsg_GetContentSecurityPolicy, OnGetContentSecurityPolicy)
469 IPC_MESSAGE_HANDLER(EwkHostMsg_DidPrintPagesToPdf, OnPrintedMetafileReceived)
470 IPC_MESSAGE_HANDLER(EwkHostMsg_WrtMessage, OnWrtPluginMessage)
471 IPC_MESSAGE_HANDLER_DELAY_REPLY(EwkHostMsg_WrtSyncMessage, OnWrtPluginSyncMessage)
472 IPC_MESSAGE_UNHANDLED(handled = false)
473 IPC_END_MESSAGE_MAP()
478 void WebContentsDelegateEfl::OnWrtPluginMessage(const Ewk_Wrt_Message_Data& data) {
479 scoped_ptr<Ewk_Wrt_Message_Data> p(new Ewk_Wrt_Message_Data);
481 p->value = data.value;
483 p->reference_id = data.reference_id;
485 web_view_->SmartCallback<EWebViewCallbacks::WrtPluginsMessage>().call(p.get());
488 void WebContentsDelegateEfl::OnWrtPluginSyncMessage(const Ewk_Wrt_Message_Data& data,
489 IPC::Message* reply) {
490 Ewk_Wrt_Message_Data tmp = data;
491 web_view_->SmartCallback<EWebViewCallbacks::WrtPluginsMessage>().call(&tmp);
492 EwkHostMsg_WrtSyncMessage::WriteReplyParams(reply, tmp.value);
496 void WebContentsDelegateEfl::DidFirstVisuallyNonEmptyPaint() {
497 web_view_->SmartCallback<EWebViewCallbacks::LoadNonEmptyLayoutFinished>().call();
498 web_view_->SmartCallback<EWebViewCallbacks::FrameRendered>().call(0);
501 void WebContentsDelegateEfl::OnGetContentSecurityPolicy(IPC::Message* reply_msg) {
502 document_created_ = true;
503 if (!pending_content_security_policy_.get()) {
504 EwkHostMsg_GetContentSecurityPolicy::WriteReplyParams(reply_msg, std::string(), EWK_DEFAULT_POLICY);
506 EwkHostMsg_GetContentSecurityPolicy::WriteReplyParams(reply_msg,
507 pending_content_security_policy_->policy, pending_content_security_policy_->header_type);
508 pending_content_security_policy_.reset();
513 void WebContentsDelegateEfl::OnPrintedMetafileReceived(const DidPrintPagesParams& params) {
514 base::SharedMemory shared_buf(params.metafile_data_handle, true);
515 if (!shared_buf.Map(params.data_size)) {
516 NOTREACHED() << "couldn't map";
519 scoped_ptr<printing::PdfMetafileSkia> metafile(new printing::PdfMetafileSkia);
520 if (!metafile->InitFromData(shared_buf.memory(), params.data_size)) {
521 NOTREACHED() << "Invalid metafile header";
524 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
525 base::Bind(&WritePdfDataToFile, metafile.release(), params.filename));
528 void WebContentsDelegateEfl::NavigationEntryCommitted(const LoadCommittedDetails& load_details) {
529 web_view_->InvokeBackForwardListChangedCallback();
532 void WebContentsDelegateEfl::RenderViewCreated(RenderViewHost* render_view_host) {
533 web_view_->RenderViewCreated(render_view_host);
536 void WebContentsDelegateEfl::RenderProcessGone(base::TerminationStatus status) {
537 // See RenderWidgetHostViewEfl::RenderProcessGone.
538 if (status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION
539 || status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED
540 || status == base::TERMINATION_STATUS_PROCESS_CRASHED) {
541 web_view_->HandleRendererProcessCrash();
545 bool WebContentsDelegateEfl::AddMessageToConsole(WebContents* source,
547 const string16& message,
549 const string16& source_id) {
550 scoped_ptr<_Ewk_Console_Message> console_message(new _Ewk_Console_Message(level,
551 UTF16ToUTF8(message).c_str(),
553 source->GetVisibleURL().spec().c_str()));
554 web_view_->SmartCallback<EWebViewCallbacks::ConsoleMessage>().call(console_message.get());
558 void WebContentsDelegateEfl::RunFileChooser(WebContents* web_contents, const FileChooserParams& params) {
559 web_view_->ShowFileChooser(params);
562 content::ColorChooser* WebContentsDelegateEfl::OpenColorChooser(
563 WebContents* web_contents,
565 const std::vector<ColorSuggestion>& suggestions) {
566 ColorChooserEfl* color_chooser_efl = new ColorChooserEfl(*web_contents);
567 web_view_->RequestColorPicker(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color), SkColorGetA(color));
569 return color_chooser_efl;
572 void WebContentsDelegateEfl::OpenDateTimeDialog(
573 ui::TextInputType dialog_type,
578 const std::vector<DateTimeSuggestion>& suggestions) {
579 web_view_->InputPickerShow(dialog_type, dialog_value);
582 bool WebContentsDelegateEfl::PreHandleGestureEvent(
584 const blink::WebGestureEvent& event) {
585 switch (event.type) {
586 case blink::WebInputEvent::GestureDoubleTap:
590 case blink::WebInputEvent::GesturePinchBegin:
591 case blink::WebInputEvent::GesturePinchUpdate:
592 case blink::WebInputEvent::GesturePinchEnd:
593 if (!IsPinchToZoomEnabled() ||
594 IsFullscreenForTabOrPending(&web_contents()))
603 } //namespace content