[M108 Migration][MM] Handle User Permission popup.
[platform/framework/web/chromium-efl.git] / tizen_src / ewk / efl_integration / web_contents_delegate_efl.cc
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.
4
5 #include "web_contents_delegate_efl.h"
6
7 #include <tuple>
8
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/trace_event/ttrace.h"
11 #include "browser/input_picker/color_chooser_efl.h"
12 #include "browser/javascript_dialog_manager_efl.h"
13 #include "browser/policy_response_delegate_efl.h"
14 #include "browser_context_efl.h"
15 #include "common/render_messages_ewk.h"
16 #include "components/password_manager/core/common/password_manager_pref_names.h"
17 #include "components/prefs/pref_service.h"
18 #include "content/browser/manifest/manifest_manager_host.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/common/content_switches_internal.h"
21 #include "content/common/render_messages_efl.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/file_select_listener.h"
24 #include "content/public/browser/invalidate_type.h"
25 #include "content/public/browser/navigation_entry.h"
26 #include "content/public/browser/navigation_handle.h"
27 #include "content/public/browser/render_view_host.h"
28 #include "eweb_view.h"
29 #include "eweb_view_callbacks.h"
30 #include "net/base/load_states.h"
31 #include "net/cert/x509_certificate.h"
32 #include "net/http/http_response_headers.h"
33 #include "private/ewk_certificate_private.h"
34 #include "private/ewk_console_message_private.h"
35 #include "private/ewk_error_private.h"
36 #include "private/ewk_policy_decision_private.h"
37 #include "private/ewk_user_media_private.h"
38 #include "private/webview_delegate_ewk.h"
39 #include "third_party/blink/public/common/input/web_input_event.h"
40 #include "third_party/blink/public/common/manifest/manifest_util.h"
41 #include "url/gurl.h"
42 #include "web_contents_observer_efl.h"
43
44 #if BUILDFLAG(IS_TIZEN)
45 #include <app_control.h>
46 #include <app_manager.h>
47 #endif
48
49 #if defined(TIZEN_MULTIMEDIA)
50 #include "base/functional/callback.h"
51 #include "content/public/browser/media_capture_devices.h"
52 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
53 #endif
54
55 #if defined(TIZEN_AUTOFILL_SUPPORT)
56 #include "base/command_line.h"
57 #include "browser/autofill/autofill_client_efl.h"
58 #include "browser/password_manager/password_manager_client_efl.h"
59 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
60 #include "components/autofill/core/browser/autofill_client.h"
61 #include "components/autofill/core/browser/autofill_manager.h"
62 #include "components/autofill/core/common/autofill_switches.h"
63 #include "components/web_modal/web_contents_modal_dialog_manager.h"
64
65 using autofill::AutofillManager;
66 using autofill::AutofillClientEfl;
67 using autofill::ContentAutofillDriverFactory;
68 using password_manager::PasswordManagerClientEfl;
69 #endif
70
71 using std::u16string;
72 using namespace ui;
73
74 namespace content {
75
76 #if BUILDFLAG(IS_TIZEN) && defined(TIZEN_MULTIMEDIA)
77 static const blink::MediaStreamDevice* GetRequestedAudioDevice(
78     const std::string& device_id) {
79   const blink::MediaStreamDevices& audio_devices =
80       MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices();
81   if (audio_devices.empty())
82     return NULL;
83   if (device_id.length() == 0)
84     return &(*audio_devices.begin());
85
86   for (blink::MediaStreamDevices::const_iterator i = audio_devices.begin();
87        i != audio_devices.end(); i++) {
88     if (i->id.compare(device_id) == 0)
89       return &(*i);
90   }
91
92   NOTREACHED();
93   return nullptr;
94 }
95
96 /* LCOV_EXCL_START */
97 static const blink::MediaStreamDevice* GetRequestedVideoDevice(
98     const std::string& device_id) {
99   const blink::MediaStreamDevices& video_devices =
100       MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices();
101   if (video_devices.empty())
102     return nullptr;
103   if (device_id.length() == 0)
104     return &(*video_devices.begin());
105
106   for (blink::MediaStreamDevices::const_iterator i = video_devices.begin();
107        i != video_devices.end(); i++) {
108     if (i->id.compare(device_id) == 0)
109       return &(*i);
110   }
111
112   NOTREACHED();
113   return nullptr;
114 }
115 /* LCOV_EXCL_STOP */
116 #endif
117
118 WebContentsDelegateEfl::WebContentsDelegateEfl(EWebView* view)
119     : web_view_(view),
120       web_contents_(view->web_contents()),
121       contents_observer_(std::make_unique<WebContentsObserverEfl>(view, this)) {
122 #if defined(TIZEN_AUTOFILL_SUPPORT)
123   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
124           autofill::switches::kDisableAutofill)) {
125     AutofillClientEfl::CreateForWebContents(&web_contents_);
126     AutofillClientEfl* autofill_client =
127         AutofillClientEfl::FromWebContents(&web_contents_);
128     autofill_client->SetEWebView(view);
129     PasswordManagerClientEfl::CreateForWebContentsWithAutofillClient(
130         &web_contents_, autofill_client);
131     ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
132         &web_contents_, autofill_client,
133         base::BindRepeating(&autofill::BrowserDriverInitHook, autofill_client,
134                             EWebView::GetPlatformLocale()));
135   }
136 #endif
137 }
138
139 WebContentsDelegateEfl::~WebContentsDelegateEfl() {
140   // It's important to delete web_contents_ before dialog_manager_
141   // destructor of web contents uses dialog_manager_
142   if (dialog_manager_)
143     delete dialog_manager_;
144 }
145
146 WebContents* WebContentsDelegateEfl::OpenURLFromTab(
147     WebContents* source,
148     const OpenURLParams& params) {
149   const GURL& url = params.url;
150   WindowOpenDisposition disposition = params.disposition;
151
152   if (!source || (disposition != WindowOpenDisposition::CURRENT_TAB &&
153                   disposition != WindowOpenDisposition::NEW_FOREGROUND_TAB &&
154                   disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB &&
155                   disposition != WindowOpenDisposition::OFF_THE_RECORD)) {
156     NOTIMPLEMENTED();
157     return NULL;
158   }
159
160   if (disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
161       disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB ||
162       disposition == WindowOpenDisposition::OFF_THE_RECORD) {
163     Evas_Object* new_object = NULL;
164     web_view_->SmartCallback<EWebViewCallbacks::CreateNewWindow>().call(
165         &new_object);
166
167     if (!new_object)
168       return NULL;
169
170     if (disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB)
171       ActivateContents(source);
172
173     EWebView* wv =
174         WebViewDelegateEwk::GetInstance().GetWebViewFromEvasObject(new_object);
175     DCHECK(wv);
176     wv->SetURL(url);
177     return NULL;
178   }
179
180   ui::PageTransition transition(ui::PageTransitionFromInt(params.transition));
181   source->GetController().LoadURL(url, params.referrer, transition,
182                                   std::string());
183   return source;
184 }
185
186 void WebContentsDelegateEfl::NavigationStateChanged(
187     WebContents* source, InvalidateTypes changed_flags) {
188   // We always notfiy clients about title invalidation, even if its text
189   // didn't actually change. This is to maintain EWK API consistency.
190   if (changed_flags & INVALIDATE_TYPE_TITLE) {
191     web_view_->SmartCallback<EWebViewCallbacks::TitleChange>().call(
192         base::UTF16ToUTF8(source->GetTitle()).c_str());
193   }
194
195   // We only notify clients if visible url actually changed, because on some
196   // pages we would get notifications with flag INVALIDATE_TYPE_URL even when
197   // visible url did not change.
198   if ((changed_flags & INVALIDATE_TYPE_URL) &&
199        last_visible_url_ != source->GetVisibleURL()) {
200     last_visible_url_ = source->GetVisibleURL();
201     const char* url = last_visible_url_.spec().c_str();
202
203     web_view_->SmartCallback<EWebViewCallbacks::URLChanged>().call(url);
204     web_view_->SmartCallback<EWebViewCallbacks::URIChanged>().call(url);
205   }
206 }
207
208 void WebContentsDelegateEfl::AddNewContents(
209     WebContents* source,
210     std::unique_ptr<WebContents> new_contents,
211     const GURL& target_url,
212     WindowOpenDisposition disposition,
213     const blink::mojom::WindowFeatures& window_features,
214     bool user_gesture,
215     bool* was_blocked) {
216   // Initialize the delegate for the new contents here using source's delegate
217   // as it will be needed to create a new window with the pre-created
218   // new contents in case the opener is suppressed. Otherwise, the delegate
219   // had already been initialized in EWebView::InitializeContent()
220   if (!new_contents->GetDelegate())
221     new_contents->SetDelegate(this);
222
223   // EWebView takes the ownership of new WebContents in
224   // EWebView::InitializeContent(). So, we can release the ownership of new
225   // WebContents here.
226   std::ignore = new_contents.release();
227 }
228
229 bool WebContentsDelegateEfl::ShouldCreateWebContents(
230     WebContents* web_contents,
231     RenderFrameHost* opener,
232     SiteInstance* source_site_instance,
233     mojom::WindowContainerType window_container_type,
234     const GURL& opener_url,
235     const std::string& frame_name,
236     const GURL& target_url,
237     const std::string& partition_id,
238     SessionStorageNamespace* session_storage_namespace) {
239   // We implement the asynchronous version of the function, this
240   // one should never be invoked.
241   NOTREACHED();
242   return false;
243 }
244
245 void WebContentsDelegateEfl::CloseContents(WebContents* source) {
246   web_view_->SmartCallback<EWebViewCallbacks::WindowClosed>().call();
247 }
248
249 void WebContentsDelegateEfl::EnterFullscreenModeForTab(
250     RenderFrameHost* requesting_frame,
251     const blink::mojom::FullscreenOptions& options) {
252   is_fullscreen_ = true;
253   web_view_->SmartCallback<EWebViewCallbacks::EnterFullscreen>().call();
254 }
255
256 void WebContentsDelegateEfl::ExitFullscreenModeForTab(
257     WebContents* web_contents) {
258   is_fullscreen_ = false;
259   web_view_->SmartCallback<EWebViewCallbacks::ExitFullscreen>().call();
260 }
261
262 bool WebContentsDelegateEfl::IsFullscreenForTabOrPending(
263     const WebContents* web_contents) {
264   return is_fullscreen_;
265 }
266
267 #if defined(TIZEN_MULTIMEDIA)
268 /* LCOV_EXCL_START */
269 void WebContentsDelegateEfl::RequestMediaAccessAllow(
270     const MediaStreamRequest& request,
271     MediaResponseCallback callback) {
272   blink::mojom::StreamDevicesSet stream_devices_set;
273   stream_devices_set.stream_devices.emplace_back(
274       blink::mojom::StreamDevices::New());
275   blink::mojom::StreamDevices& stream_devices =
276       *stream_devices_set.stream_devices[0];
277
278   if (request.audio_type ==
279       blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE) {
280     const blink::MediaStreamDevice* audio_device =
281         GetRequestedAudioDevice(request.requested_audio_device_id);
282     if (audio_device) {
283       stream_devices.audio_device = *audio_device;
284     } else {
285       std::move(callback).Run(
286           blink::mojom::StreamDevicesSet(),
287           blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED,
288           std::unique_ptr<MediaStreamUI>());
289       return;
290     }
291   }
292
293   if (request.video_type ==
294       blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE) {
295     const blink::MediaStreamDevice* video_device =
296         GetRequestedVideoDevice(request.requested_video_device_id);
297     if (video_device) {
298       stream_devices.video_device = *video_device;
299     } else {
300       std::move(callback).Run(
301           blink::mojom::StreamDevicesSet(),
302           blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED,
303           std::unique_ptr<MediaStreamUI>());
304       return;
305     }
306   }
307
308   std::move(callback).Run(stream_devices_set,
309                           blink::mojom::MediaStreamRequestResult::OK,
310                           std::unique_ptr<MediaStreamUI>());
311 }
312 /* LCOV_EXCL_STOP */
313
314 void WebContentsDelegateEfl::RequestMediaAccessDeny(
315     const MediaStreamRequest& request,
316     MediaResponseCallback callback) {
317   std::move(callback).Run(blink::mojom::StreamDevicesSet(),
318                           blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED,
319                           std::unique_ptr<MediaStreamUI>());
320 }
321
322 bool WebContentsDelegateEfl::CheckMediaAccessPermission(
323     RenderFrameHost* render_frame_host,
324     const GURL& security_origin,
325     blink::mojom::MediaStreamType type) {
326   return true;
327 }
328
329 void WebContentsDelegateEfl::RequestMediaAccessPermission(
330     WebContents* web_contents,
331     const MediaStreamRequest& request,
332     MediaResponseCallback callback) {
333   std::unique_ptr<_Ewk_User_Media_Permission_Request> media_permission_request(
334       new _Ewk_User_Media_Permission_Request(this, request,
335                                              std::move(callback)));
336
337   Eina_Bool callback_result = EINA_FALSE;
338   if (!web_view_->InvokeViewUserMediaPermissionCallback(
339           media_permission_request.get(), &callback_result)) {
340     web_view_->SmartCallback<EWebViewCallbacks::UserMediaPermission>()
341         .call(  // LCOV_EXCL_LINE
342             media_permission_request.get());
343   }
344
345   // if policy is suspended, the API takes over the policy object lifetime
346   // and policy will be deleted after decision is made
347   if (media_permission_request->IsSuspended())
348     std::ignore = media_permission_request.release();
349   /* LCOV_EXCL_START */
350   else if (!media_permission_request->IsDecided())
351     media_permission_request->ProceedPermissionCallback(false);
352   /* LCOV_EXCL_STOP */
353 }
354 #endif
355
356 void WebContentsDelegateEfl::OnAuthRequired(const std::string& realm,
357                                             const GURL& url,
358                                             LoginDelegateEfl* login_delegate) {
359   web_view_->InvokeAuthCallback(login_delegate, url, realm);
360 }
361
362 void WebContentsDelegateEfl::RequestCertificateConfirm(
363     WebContents* /*web_contents*/,
364     int cert_error,
365     const net::SSLInfo& ssl_info,
366     const GURL& url,
367     bool is_main_frame_request,
368     bool /*strict_enforcement*/,
369     base::OnceCallback<void(CertificateRequestResultType)> callback) {
370   std::string pem_certificate;
371   if (!net::X509Certificate::GetPEMEncoded(ssl_info.cert->cert_buffer(),
372                                            &pem_certificate)) {
373     LOG(INFO) << "Certificate for URL: " << url.spec()
374               << " could not be opened";
375     std::move(callback).Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL);
376     return;
377   }
378   certificate_policy_decision_.reset(new _Ewk_Certificate_Policy_Decision(
379       url, pem_certificate, is_main_frame_request, cert_error,
380       std::move(callback)));
381
382   web_view_->SmartCallback<EWebViewCallbacks::RequestCertificateConfirm>().call(
383       certificate_policy_decision_.get());
384   LOG(INFO) << "Certificate policy decision called for URL: " << url.spec()
385             << " with cert_error: " << cert_error;
386
387   // if policy is suspended, the API takes over the policy object lifetime
388   // and policy will be deleted after decision is made
389   if (certificate_policy_decision_->IsSuspended()) {
390     std::ignore = certificate_policy_decision_.release();
391   } else if (!certificate_policy_decision_->IsDecided()) {
392     // When the embeder neither suspended certificate decision nor handled it
393     // inside the smart callback by calling
394     // ewk_certificate_policy_decision_allowed_set
395     // this means the embeder let chromium decide what to do.
396     if (!is_main_frame_request) {
397       // A sub-resource has a certificate error. The user doesn't really
398       // have a context for making the right decision, so block the
399       // request hard.
400       std::move(certificate_policy_decision_->Callback())
401           .Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
402     } else {
403       // By default chromium-efl allows page to be opened with certificate
404       // compromise.
405       certificate_policy_decision_->SetDecision(true);
406       LOG(WARNING) << "Certificate for " << url.spec() << " was compromised";
407     }
408   }
409 }
410
411 void WebContentsDelegateEfl::VisibleSecurityStateChanged(WebContents* source) {
412   std::unique_ptr<_Ewk_Certificate_Info> certificate_info;
413   std::string pem_certificate;
414   SSLStatus ssl_status = source->GetController().GetVisibleEntry()->GetSSL();
415   scoped_refptr<net::X509Certificate> cert = ssl_status.certificate;
416
417   if (!cert) {
418     LOG(ERROR) << "Unable to get certificate!";
419     certificate_info.reset(new _Ewk_Certificate_Info(nullptr, false));
420   } else {
421     if (!net::X509Certificate::GetPEMEncoded(cert->cert_buffer(),
422                                              &pem_certificate)) {
423       LOG(ERROR) << "Unable to get encoded PEM!";
424       return;
425     }
426     // Note: The implementation below is a copy of the one in
427     // ChromeAutofillClient::IsContextSecure, and should be kept in sync
428     // until crbug.com/505388 gets implemented.
429     bool is_context_secure =
430         ssl_status.certificate &&
431         !net::IsCertStatusError(ssl_status.cert_status) &&
432         !(ssl_status.content_status & content::SSLStatus::RAN_INSECURE_CONTENT);
433
434     certificate_info.reset(
435         new _Ewk_Certificate_Info(pem_certificate.c_str(), is_context_secure));
436   }
437   web_view_->SmartCallback<EWebViewCallbacks::SSLCertificateChanged>().call(
438       certificate_info.get());
439 }
440
441 void WebContentsDelegateEfl::ActivateContents(WebContents* contents) {
442 #if BUILDFLAG(IS_TIZEN)
443   app_control_h app_control = nullptr;
444   int ret = app_control_create(&app_control);
445   if (ret != APP_CONTROL_ERROR_NONE) {
446     LOG(ERROR) << "app_control_create is failed with err " << ret;
447     return;
448   }
449
450   std::unique_ptr<std::remove_pointer<app_control_h>::type,
451                   decltype(app_control_destroy)*>
452       auto_release{app_control, app_control_destroy};
453
454   char* app_id = nullptr;
455   ret = app_manager_get_app_id(getpid(), &app_id);
456   if (ret != APP_MANAGER_ERROR_NONE) {
457     LOG(ERROR) << "app_manager_get_app_id is failed with err " << ret;
458     return;
459   }
460
461   ret = app_control_set_app_id(app_control, app_id);
462   if (app_id)
463     free(app_id);
464   if (ret != APP_CONTROL_ERROR_NONE) {
465     LOG(ERROR) << "app_control_set_app_id is failed with err " << ret;
466     return;
467   }
468
469   ret = app_control_send_launch_request(app_control, nullptr, nullptr);
470   if (ret != APP_CONTROL_ERROR_NONE) {
471     LOG(ERROR) << "app_control_send_launch_request is failed with err " << ret;
472     return;
473   }
474 #endif
475 }
476
477 void WebContentsDelegateEfl::SetContentSecurityPolicy(
478     const std::string& policy,
479     Ewk_CSP_Header_Type header_type) {
480   contents_observer_->SetContentSecurityPolicy(policy, header_type);
481 }
482
483 #if defined(TIZEN_AUTOFILL_SUPPORT)
484 void WebContentsDelegateEfl::UpdateAutofillIfRequired() {
485   if (AutofillClientEfl* autofill_client =
486           AutofillClientEfl::FromWebContents(&web_contents_)) {
487     autofill_client->UpdateAutofillIfRequired();
488   }
489 }
490 #endif
491
492 void WebContentsDelegateEfl::OnDidChangeFocusedNodeBounds(
493     const gfx::RectF& focused_node_bounds) {
494 #if defined(TIZEN_AUTOFILL_SUPPORT)
495   if (AutofillClientEfl* autofill_client =
496           AutofillClientEfl::FromWebContents(&web_contents_)) {
497     autofill_client->DidChangeFocusedNodeBounds(focused_node_bounds);
498   }
499 #endif
500 }
501
502 void WebContentsDelegateEfl::FindReply(WebContents* web_contents,
503                                        int request_id,
504                                        int number_of_matches,
505                                        const gfx::Rect& selection_rect,
506                                        int active_match_ordinal,
507                                        bool final_update) {
508   if (final_update && request_id == web_view_->current_find_request_id()) {
509     unsigned int uint_number_of_matches =
510         static_cast<unsigned int>(number_of_matches);
511     web_view_->SmartCallback<EWebViewCallbacks::TextFound>().call(
512         &uint_number_of_matches);
513   }
514 }
515
516 void WebContentsDelegateEfl::DidRenderFrame() {
517   // Call FrameRendered callback when loading and first layout is finished.
518   if (!did_render_frame_ && did_first_visually_non_empty_paint_ &&
519       (web_view_->GetProgressValue() > 0.1)) {
520     did_first_visually_non_empty_paint_ = false;
521     did_render_frame_ = true;
522     TTRACE_WEB("WebContentsDelegateEfl::DidRenderFrame");
523     LOG(INFO) << "WebContentsDelegateEfl::DidRenderFrame";
524
525     // "frame,rendered" message is triggered as soon as rendering of a frame
526     // is completed.
527     web_view_->SmartCallback<EWebViewCallbacks::FrameRendered>().call(0);
528   }
529 }
530
531 JavaScriptDialogManager* WebContentsDelegateEfl::GetJavaScriptDialogManager(
532     WebContents* source) {
533   if (!dialog_manager_)
534     dialog_manager_ = new JavaScriptDialogManagerEfl();
535   return dialog_manager_;
536 }
537
538 void WebContentsDelegateEfl::OnUpdateSettings(const Ewk_Settings* settings) {
539 #if defined(TIZEN_AUTOFILL_SUPPORT)
540   PasswordManagerClientEfl* client =
541       PasswordManagerClientEfl::FromWebContents(&web_contents_);
542   if (client) {
543     PrefService* prefs = client->GetPrefs();
544     prefs->SetBoolean(password_manager::prefs::kCredentialsEnableService,
545                       settings->autofillPasswordForm());
546   }
547 #endif
548 }
549
550 void WebContentsDelegateEfl::DidFirstVisuallyNonEmptyPaint() {
551   did_first_visually_non_empty_paint_ = true;
552   web_view_->SmartCallback<EWebViewCallbacks::LoadNonEmptyLayoutFinished>()
553       .call();
554 }
555
556 void WebContentsDelegateEfl::DidStartLoading() {
557   did_render_frame_ = false;
558 }
559
560 bool WebContentsDelegateEfl::DidAddMessageToConsole(
561     WebContents* source,
562     blink::mojom::ConsoleMessageLevel level,
563     const std::u16string& message,
564     int32_t line_no,
565     const std::u16string& source_id) {
566   std::unique_ptr<_Ewk_Console_Message> console_message(
567       new _Ewk_Console_Message(static_cast<unsigned>(level),
568                                base::UTF16ToUTF8(message).c_str(), line_no,
569                                base::UTF16ToUTF8(source_id).c_str()));
570   web_view_->SmartCallback<EWebViewCallbacks::ConsoleMessage>().call(
571       console_message.get());
572   return true;
573 }
574
575 void WebContentsDelegateEfl::RunFileChooser(
576     RenderFrameHost* render_frame_host,
577     scoped_refptr<FileSelectListener> listener,
578     const blink::mojom::FileChooserParams& params) {
579   web_view_->ShowFileChooser(render_frame_host, params);
580 }
581
582 std::unique_ptr<ColorChooser> WebContentsDelegateEfl::OpenColorChooser(
583     WebContents* web_contents,
584     SkColor color,
585     const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions) {
586   web_view_->RequestColorPicker(SkColorGetR(color), SkColorGetG(color),
587                                 SkColorGetB(color), SkColorGetA(color));
588   return std::make_unique<ColorChooserEfl>(*web_contents);
589 }
590
591 #if !defined(EWK_BRINGUP)  // FIXME: m76 bringup
592 void WebContentsDelegateEfl::OpenDateTimeDialog(
593     ui::TextInputType dialog_type,
594     double dialog_value,
595     double min,
596     double max,
597     double step,
598     const std::vector<DateTimeSuggestion>& suggestions) {
599   web_view_->InputPickerShow(dialog_type, dialog_value);
600 }
601 #endif
602
603 bool WebContentsDelegateEfl::PreHandleGestureEvent(
604     WebContents* source,
605     const blink::WebGestureEvent& event) {
606   blink::WebInputEvent::Type event_type = event.GetType();
607   switch (event_type) {
608     case blink::WebInputEvent::Type::kGestureDoubleTap:
609       if (is_fullscreen_)
610         return true;
611       break;
612     case blink::WebInputEvent::Type::kGesturePinchBegin:
613     case blink::WebInputEvent::Type::kGesturePinchUpdate:
614     case blink::WebInputEvent::Type::kGesturePinchEnd:
615       if (!IsPinchToZoomEnabled() ||
616           IsFullscreenForTabOrPending(&web_contents()))
617         return true;
618       break;
619     default:
620       break;
621   }
622   return false;
623 }
624
625 void WebContentsDelegateEfl::BackgroundColorReceived(int callback_id,
626                                                      SkColor bg_color) {
627   web_view_->OnGetBackgroundColor(callback_id, bg_color);
628 }
629
630 void WebContentsDelegateEfl::RequestManifestInfo(
631     Ewk_View_Request_Manifest_Callback callback,
632     void* user_data) {
633   WebContentsImpl* wci = static_cast<WebContentsImpl*>(&web_contents_);
634   ManifestManagerHost* manifest_manager_host =
635       ManifestManagerHost::GetOrCreateForPage(wci->GetPrimaryPage());
636   if (!manifest_manager_host) {
637     web_view_->DidRespondRequestManifest(nullptr, callback, user_data);
638     return;
639   }
640
641   manifest_manager_host->GetManifest(
642       base::BindOnce(&WebContentsDelegateEfl::OnDidGetManifest,
643                      base::Unretained(this), callback, user_data));
644 }
645
646 void WebContentsDelegateEfl::OnDidGetManifest(
647     Ewk_View_Request_Manifest_Callback callback,
648     void* user_data,
649     const GURL& manifest_url,
650     blink::mojom::ManifestPtr manifest) {
651   if (blink::IsEmptyManifest(*manifest)) {
652     web_view_->DidRespondRequestManifest(nullptr, callback, user_data);
653   } else {
654     _Ewk_View_Request_Manifest ewk_manifest(std::move(manifest));
655     web_view_->DidRespondRequestManifest(&ewk_manifest, callback, user_data);
656   }
657 }
658
659 }  // namespace content