Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / guestview / webview / webview_guest.cc
1 // Copyright 2013 The Chromium Authors. 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 "chrome/browser/guestview/webview/webview_guest.h"
6
7 #include "base/command_line.h"
8 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
11 #include "chrome/browser/extensions/extension_renderer_state.h"
12 #include "chrome/browser/extensions/extension_web_contents_observer.h"
13 #include "chrome/browser/extensions/script_executor.h"
14 #include "chrome/browser/favicon/favicon_tab_helper.h"
15 #include "chrome/browser/guestview/guestview_constants.h"
16 #include "chrome/browser/guestview/webview/webview_constants.h"
17 #include "chrome/browser/guestview/webview/webview_permission_types.h"
18 #include "chrome/common/chrome_version_info.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/native_web_keyboard_event.h"
21 #include "content/public/browser/navigation_entry.h"
22 #include "content/public/browser/notification_details.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/notification_source.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/browser/resource_request_details.h"
28 #include "content/public/browser/site_instance.h"
29 #include "content/public/browser/storage_partition.h"
30 #include "content/public/browser/user_metrics.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/page_zoom.h"
34 #include "content/public/common/result_codes.h"
35 #include "extensions/common/constants.h"
36 #include "net/base/net_errors.h"
37
38 #if defined(ENABLE_PLUGINS)
39 #include "chrome/browser/guestview/webview/plugin_permission_helper.h"
40 #endif
41
42 #if defined(OS_CHROMEOS)
43 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
44 #endif
45
46 using base::UserMetricsAction;
47 using content::WebContents;
48
49 namespace {
50
51 static std::string TerminationStatusToString(base::TerminationStatus status) {
52   switch (status) {
53     case base::TERMINATION_STATUS_NORMAL_TERMINATION:
54       return "normal";
55     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
56     case base::TERMINATION_STATUS_STILL_RUNNING:
57       return "abnormal";
58     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
59       return "killed";
60     case base::TERMINATION_STATUS_PROCESS_CRASHED:
61 #if defined(OS_ANDROID)
62     case base::TERMINATION_STATUS_OOM_PROTECTED:
63 #endif
64       return "crashed";
65     case base::TERMINATION_STATUS_MAX_ENUM:
66       break;
67   }
68   NOTREACHED() << "Unknown Termination Status.";
69   return "unknown";
70 }
71
72 static std::string PermissionTypeToString(BrowserPluginPermissionType type) {
73   switch (type) {
74     case BROWSER_PLUGIN_PERMISSION_TYPE_DOWNLOAD:
75       return webview::kPermissionTypeDownload;
76     case BROWSER_PLUGIN_PERMISSION_TYPE_GEOLOCATION:
77       return webview::kPermissionTypeGeolocation;
78     case BROWSER_PLUGIN_PERMISSION_TYPE_MEDIA:
79       return webview::kPermissionTypeMedia;
80     case BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW:
81       return webview::kPermissionTypeNewWindow;
82     case BROWSER_PLUGIN_PERMISSION_TYPE_POINTER_LOCK:
83       return webview::kPermissionTypePointerLock;
84     case BROWSER_PLUGIN_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
85       return webview::kPermissionTypeDialog;
86     case BROWSER_PLUGIN_PERMISSION_TYPE_UNKNOWN:
87       NOTREACHED();
88       break;
89     default: {
90       WebViewPermissionType webview = static_cast<WebViewPermissionType>(type);
91       switch (webview) {
92         case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN:
93           return webview::kPermissionTypeLoadPlugin;
94       }
95       NOTREACHED();
96     }
97   }
98   return std::string();
99 }
100
101 void RemoveWebViewEventListenersOnIOThread(
102     void* profile,
103     const std::string& extension_id,
104     int embedder_process_id,
105     int view_instance_id) {
106   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
107   ExtensionWebRequestEventRouter::GetInstance()->RemoveWebViewEventListeners(
108       profile,
109       extension_id,
110       embedder_process_id,
111       view_instance_id);
112 }
113
114 void AttachWebViewHelpers(WebContents* contents) {
115   FaviconTabHelper::CreateForWebContents(contents);
116   extensions::ExtensionWebContentsObserver::CreateForWebContents(contents);
117 #if defined(ENABLE_PLUGINS)
118   PluginPermissionHelper::CreateForWebContents(contents);
119 #endif
120 }
121
122 }  // namespace
123
124 WebViewGuest::WebViewGuest(WebContents* guest_web_contents,
125                            const std::string& extension_id)
126     : GuestView(guest_web_contents, extension_id),
127       WebContentsObserver(guest_web_contents),
128       script_executor_(new extensions::ScriptExecutor(guest_web_contents,
129                                                       &script_observers_)),
130       next_permission_request_id_(0),
131       is_overriding_user_agent_(false),
132       pending_reload_on_attachment_(false),
133       main_frame_id_(0),
134       chromevox_injected_(false) {
135   notification_registrar_.Add(
136       this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
137       content::Source<WebContents>(guest_web_contents));
138
139   notification_registrar_.Add(
140       this, content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
141       content::Source<WebContents>(guest_web_contents));
142
143 #if defined(OS_CHROMEOS)
144   notification_registrar_.Add(this,
145       chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK,
146       content::NotificationService::AllSources());
147 #endif
148
149   AttachWebViewHelpers(guest_web_contents);
150 }
151
152 // static
153 WebViewGuest* WebViewGuest::From(int embedder_process_id,
154                                  int guest_instance_id) {
155   GuestView* guest = GuestView::From(embedder_process_id, guest_instance_id);
156   if (!guest)
157     return NULL;
158   return guest->AsWebView();
159 }
160
161 // static
162 WebViewGuest* WebViewGuest::FromWebContents(WebContents* contents) {
163   GuestView* guest = GuestView::FromWebContents(contents);
164   return guest ? guest->AsWebView() : NULL;
165 }
166
167 // static
168 void WebViewGuest::RecordUserInitiatedUMA(const PermissionResponseInfo& info,
169                                           bool allow) {
170   if (allow) {
171     // Note that |allow| == true means the embedder explicitly allowed the
172     // request. For some requests they might still fail. An example of such
173     // scenario would be: an embedder allows geolocation request but doesn't
174     // have geolocation access on its own.
175     switch (info.permission_type) {
176       case BROWSER_PLUGIN_PERMISSION_TYPE_DOWNLOAD:
177         content::RecordAction(
178             UserMetricsAction("BrowserPlugin.PermissionAllow.Download"));
179         break;
180       case BROWSER_PLUGIN_PERMISSION_TYPE_GEOLOCATION:
181         content::RecordAction(
182             UserMetricsAction("BrowserPlugin.PermissionAllow.Geolocation"));
183         break;
184       case BROWSER_PLUGIN_PERMISSION_TYPE_MEDIA:
185         content::RecordAction(
186             UserMetricsAction("BrowserPlugin.PermissionAllow.Media"));
187         break;
188       case BROWSER_PLUGIN_PERMISSION_TYPE_POINTER_LOCK:
189         content::RecordAction(
190             UserMetricsAction("BrowserPlugin.PermissionAllow.PointerLock"));
191         break;
192       case BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW:
193         content::RecordAction(
194             UserMetricsAction("BrowserPlugin.PermissionAllow.NewWindow"));
195         break;
196       case BROWSER_PLUGIN_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
197         content::RecordAction(
198             UserMetricsAction("BrowserPlugin.PermissionAllow.JSDialog"));
199         break;
200       case BROWSER_PLUGIN_PERMISSION_TYPE_UNKNOWN:
201         break;
202       default: {
203         WebViewPermissionType webview_permission_type =
204             static_cast<WebViewPermissionType>(info.permission_type);
205         switch (webview_permission_type) {
206           case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN:
207             content::RecordAction(
208                 UserMetricsAction("WebView.Guest.PermissionAllow.PluginLoad"));
209             break;
210           default:
211             break;
212         }
213       }
214     }
215   } else {
216     switch (info.permission_type) {
217       case BROWSER_PLUGIN_PERMISSION_TYPE_DOWNLOAD:
218         content::RecordAction(
219             UserMetricsAction("BrowserPlugin.PermissionDeny.Download"));
220         break;
221       case BROWSER_PLUGIN_PERMISSION_TYPE_GEOLOCATION:
222         content::RecordAction(
223             UserMetricsAction("BrowserPlugin.PermissionDeny.Geolocation"));
224         break;
225       case BROWSER_PLUGIN_PERMISSION_TYPE_MEDIA:
226         content::RecordAction(
227             UserMetricsAction("BrowserPlugin.PermissionDeny.Media"));
228         break;
229       case BROWSER_PLUGIN_PERMISSION_TYPE_POINTER_LOCK:
230         content::RecordAction(
231             UserMetricsAction("BrowserPlugin.PermissionDeny.PointerLock"));
232         break;
233       case BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW:
234         content::RecordAction(
235             UserMetricsAction("BrowserPlugin.PermissionDeny.NewWindow"));
236         break;
237       case BROWSER_PLUGIN_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
238         content::RecordAction(
239             UserMetricsAction("BrowserPlugin.PermissionDeny.JSDialog"));
240         break;
241       case BROWSER_PLUGIN_PERMISSION_TYPE_UNKNOWN:
242         break;
243       default: {
244         WebViewPermissionType webview_permission_type =
245             static_cast<WebViewPermissionType>(info.permission_type);
246         switch (webview_permission_type) {
247           case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN:
248             content::RecordAction(
249                 UserMetricsAction("WebView.Guest.PermissionDeny.PluginLoad"));
250             break;
251           default:
252             break;
253         }
254       }
255     }
256   }
257 }
258
259 void WebViewGuest::Attach(WebContents* embedder_web_contents,
260                           const base::DictionaryValue& args) {
261   std::string user_agent_override;
262   if (args.GetString(webview::kParameterUserAgentOverride,
263                      &user_agent_override)) {
264     SetUserAgentOverride(user_agent_override);
265   } else {
266     SetUserAgentOverride("");
267   }
268
269   GuestView::Attach(embedder_web_contents, args);
270
271   AddWebViewToExtensionRendererState();
272 }
273
274 GuestView::Type WebViewGuest::GetViewType() const {
275   return GuestView::WEBVIEW;
276 }
277
278 WebViewGuest* WebViewGuest::AsWebView() {
279   return this;
280 }
281
282 AdViewGuest* WebViewGuest::AsAdView() {
283   return NULL;
284 }
285
286 void WebViewGuest::AddMessageToConsole(int32 level,
287                                        const base::string16& message,
288                                        int32 line_no,
289                                        const base::string16& source_id) {
290   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
291   // Log levels are from base/logging.h: LogSeverity.
292   args->SetInteger(webview::kLevel, level);
293   args->SetString(webview::kMessage, message);
294   args->SetInteger(webview::kLine, line_no);
295   args->SetString(webview::kSourceId, source_id);
296   DispatchEvent(
297       new GuestView::Event(webview::kEventConsoleMessage, args.Pass()));
298 }
299
300 void WebViewGuest::Close() {
301   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
302   DispatchEvent(new GuestView::Event(webview::kEventClose, args.Pass()));
303 }
304
305 void WebViewGuest::DidAttach() {
306   if (pending_reload_on_attachment_) {
307     pending_reload_on_attachment_ = false;
308     guest_web_contents()->GetController().Reload(false);
309   }
310 }
311
312 void WebViewGuest::EmbedderDestroyed() {
313   // TODO(fsamuel): WebRequest event listeners for <webview> should survive
314   // reparenting of a <webview> within a single embedder. Right now, we keep
315   // around the browser state for the listener for the lifetime of the embedder.
316   // Ideally, the lifetime of the listeners should match the lifetime of the
317   // <webview> DOM node. Once http://crbug.com/156219 is resolved we can move
318   // the call to RemoveWebViewEventListenersOnIOThread back to
319   // WebViewGuest::WebContentsDestroyed.
320   content::BrowserThread::PostTask(
321       content::BrowserThread::IO,
322       FROM_HERE,
323       base::Bind(
324           &RemoveWebViewEventListenersOnIOThread,
325           browser_context(), extension_id(),
326           embedder_render_process_id(),
327           view_instance_id()));
328 }
329
330 void WebViewGuest::GuestProcessGone(base::TerminationStatus status) {
331   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
332   args->SetInteger(webview::kProcessId,
333                    guest_web_contents()->GetRenderProcessHost()->GetID());
334   args->SetString(webview::kReason, TerminationStatusToString(status));
335   DispatchEvent(
336       new GuestView::Event(webview::kEventExit, args.Pass()));
337 }
338
339 bool WebViewGuest::HandleKeyboardEvent(
340     const content::NativeWebKeyboardEvent& event) {
341   if (event.type != blink::WebInputEvent::RawKeyDown)
342     return false;
343
344 #if defined(OS_MACOSX)
345   if (event.modifiers != blink::WebInputEvent::MetaKey)
346     return false;
347
348   if (event.windowsKeyCode == ui::VKEY_OEM_4) {
349     Go(-1);
350     return true;
351   }
352
353   if (event.windowsKeyCode == ui::VKEY_OEM_6) {
354     Go(1);
355     return true;
356   }
357 #else
358   if (event.windowsKeyCode == ui::VKEY_BROWSER_BACK) {
359     Go(-1);
360     return true;
361   }
362
363   if (event.windowsKeyCode == ui::VKEY_BROWSER_FORWARD) {
364     Go(1);
365     return true;
366   }
367 #endif
368   return false;
369 }
370
371 bool WebViewGuest::IsDragAndDropEnabled() {
372 #if defined(OS_CHROMEOS)
373   return true;
374 #else
375   chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
376   if (channel != chrome::VersionInfo::CHANNEL_STABLE &&
377       channel != chrome::VersionInfo::CHANNEL_BETA) {
378     // Drag and drop is enabled in canary and dev channel.
379     return true;
380   }
381
382   return CommandLine::ForCurrentProcess()->HasSwitch(
383       switches::kEnableBrowserPluginDragDrop);
384 #endif
385 }
386
387 bool WebViewGuest::IsOverridingUserAgent() const {
388   return is_overriding_user_agent_;
389 }
390
391 void WebViewGuest::LoadProgressed(double progress) {
392   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
393   args->SetString(guestview::kUrl, guest_web_contents()->GetURL().spec());
394   args->SetDouble(webview::kProgress, progress);
395   DispatchEvent(new GuestView::Event(webview::kEventLoadProgress, args.Pass()));
396 }
397
398 void WebViewGuest::LoadAbort(bool is_top_level,
399                              const GURL& url,
400                              const std::string& error_type) {
401   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
402   args->SetBoolean(guestview::kIsTopLevel, is_top_level);
403   args->SetString(guestview::kUrl, url.possibly_invalid_spec());
404   args->SetString(guestview::kReason, error_type);
405   DispatchEvent(new GuestView::Event(webview::kEventLoadAbort, args.Pass()));
406 }
407
408 // TODO(fsamuel): Find a reliable way to test the 'responsive' and
409 // 'unresponsive' events.
410 void WebViewGuest::RendererResponsive() {
411   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
412   args->SetInteger(webview::kProcessId,
413       guest_web_contents()->GetRenderProcessHost()->GetID());
414   DispatchEvent(new GuestView::Event(webview::kEventResponsive, args.Pass()));
415 }
416
417 void WebViewGuest::RendererUnresponsive() {
418   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
419   args->SetInteger(webview::kProcessId,
420       guest_web_contents()->GetRenderProcessHost()->GetID());
421   DispatchEvent(new GuestView::Event(webview::kEventUnresponsive, args.Pass()));
422 }
423
424 bool WebViewGuest::RequestPermission(
425     BrowserPluginPermissionType permission_type,
426     const base::DictionaryValue& request_info,
427     const PermissionResponseCallback& callback,
428     bool allowed_by_default) {
429   // If there are too many pending permission requests then reject this request.
430   if (pending_permission_requests_.size() >=
431       webview::kMaxOutstandingPermissionRequests) {
432     callback.Run(false, std::string());
433     return true;
434   }
435
436   int request_id = next_permission_request_id_++;
437   pending_permission_requests_[request_id] =
438       PermissionResponseInfo(callback, permission_type, allowed_by_default);
439   scoped_ptr<base::DictionaryValue> args(request_info.DeepCopy());
440   args->SetInteger(webview::kRequestId, request_id);
441   switch (permission_type) {
442     case BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW: {
443       DispatchEvent(new GuestView::Event(webview::kEventNewWindow,
444                                          args.Pass()));
445       break;
446     }
447     case BROWSER_PLUGIN_PERMISSION_TYPE_JAVASCRIPT_DIALOG: {
448       chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
449       if (channel > chrome::VersionInfo::CHANNEL_DEV) {
450         // 'dialog' API is not available in stable/beta.
451         callback.Run(false, std::string());
452         return true;
453       }
454       DispatchEvent(new GuestView::Event(webview::kEventDialog,
455                                          args.Pass()));
456       break;
457     }
458     default: {
459       args->SetString(webview::kPermission,
460                       PermissionTypeToString(permission_type));
461       DispatchEvent(new GuestView::Event(webview::kEventPermissionRequest,
462                                          args.Pass()));
463       break;
464     }
465   }
466   return true;
467 }
468
469 void WebViewGuest::Observe(int type,
470                            const content::NotificationSource& source,
471                            const content::NotificationDetails& details) {
472   switch (type) {
473     case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
474       DCHECK_EQ(content::Source<WebContents>(source).ptr(),
475                 guest_web_contents());
476       if (content::Source<WebContents>(source).ptr() == guest_web_contents())
477         LoadHandlerCalled();
478       break;
479     }
480     case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
481       DCHECK_EQ(content::Source<WebContents>(source).ptr(),
482                 guest_web_contents());
483       content::ResourceRedirectDetails* resource_redirect_details =
484           content::Details<content::ResourceRedirectDetails>(details).ptr();
485       bool is_top_level =
486           resource_redirect_details->resource_type == ResourceType::MAIN_FRAME;
487       LoadRedirect(resource_redirect_details->url,
488                    resource_redirect_details->new_url,
489                    is_top_level);
490       break;
491     }
492 #if defined(OS_CHROMEOS)
493     case chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK:
494       InjectChromeVoxIfNeeded(guest_web_contents()->GetRenderViewHost());
495       break;
496 #endif
497     default:
498       NOTREACHED() << "Unexpected notification sent.";
499       break;
500   }
501 }
502
503 void WebViewGuest::SetZoom(double zoom_factor) {
504   double zoom_level = content::ZoomFactorToZoomLevel(zoom_factor);
505   guest_web_contents()->SetZoomLevel(zoom_level);
506
507   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
508   args->SetDouble(webview::kOldZoomFactor, current_zoom_factor_);
509   args->SetDouble(webview::kNewZoomFactor, zoom_factor);
510   DispatchEvent(new GuestView::Event(webview::kEventZoomChange, args.Pass()));
511
512   current_zoom_factor_ = zoom_factor;
513 }
514
515 double WebViewGuest::GetZoom() {
516   return current_zoom_factor_;
517 }
518
519 void WebViewGuest::Go(int relative_index) {
520   guest_web_contents()->GetController().GoToOffset(relative_index);
521 }
522
523 void WebViewGuest::Reload() {
524   // TODO(fsamuel): Don't check for repost because we don't want to show
525   // Chromium's repost warning. We might want to implement a separate API
526   // for registering a callback if a repost is about to happen.
527   guest_web_contents()->GetController().Reload(false);
528 }
529
530 WebViewGuest::SetPermissionResult WebViewGuest::SetPermission(
531     int request_id,
532     PermissionResponseAction action,
533     const std::string& user_input) {
534   RequestMap::iterator request_itr =
535       pending_permission_requests_.find(request_id);
536
537   if (request_itr == pending_permission_requests_.end())
538     return SET_PERMISSION_INVALID;
539
540   const PermissionResponseInfo& info = request_itr->second;
541   bool allow = (action == ALLOW) ||
542       ((action == DEFAULT) && info.allowed_by_default);
543
544   info.callback.Run(allow, user_input);
545
546   // Only record user initiated (i.e. non-default) actions.
547   if (action != DEFAULT)
548     RecordUserInitiatedUMA(info, allow);
549
550   pending_permission_requests_.erase(request_itr);
551
552   return allow ? SET_PERMISSION_ALLOWED : SET_PERMISSION_DENIED;
553 }
554
555 void WebViewGuest::SetUserAgentOverride(
556     const std::string& user_agent_override) {
557   is_overriding_user_agent_ = !user_agent_override.empty();
558   if (is_overriding_user_agent_) {
559     content::RecordAction(UserMetricsAction("WebView.Guest.OverrideUA"));
560   }
561   guest_web_contents()->SetUserAgentOverride(user_agent_override);
562 }
563
564 void WebViewGuest::Stop() {
565   guest_web_contents()->Stop();
566 }
567
568 void WebViewGuest::Terminate() {
569   content::RecordAction(UserMetricsAction("WebView.Guest.Terminate"));
570   base::ProcessHandle process_handle =
571       guest_web_contents()->GetRenderProcessHost()->GetHandle();
572   if (process_handle)
573     base::KillProcess(process_handle, content::RESULT_CODE_KILLED, false);
574 }
575
576 bool WebViewGuest::ClearData(const base::Time remove_since,
577                              uint32 removal_mask,
578                              const base::Closure& callback) {
579   content::RecordAction(UserMetricsAction("WebView.Guest.ClearData"));
580   content::StoragePartition* partition =
581       content::BrowserContext::GetStoragePartition(
582           guest_web_contents()->GetBrowserContext(),
583           guest_web_contents()->GetSiteInstance());
584
585   if (!partition)
586     return false;
587
588   partition->ClearData(
589       removal_mask,
590       content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
591       GURL(),
592       content::StoragePartition::OriginMatcherFunction(),
593       remove_since,
594       base::Time::Now(),
595       callback);
596   return true;
597 }
598
599 WebViewGuest::~WebViewGuest() {
600 }
601
602 void WebViewGuest::DidCommitProvisionalLoadForFrame(
603     int64 frame_id,
604     const base::string16& frame_unique_name,
605     bool is_main_frame,
606     const GURL& url,
607     content::PageTransition transition_type,
608     content::RenderViewHost* render_view_host) {
609   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
610   args->SetString(guestview::kUrl, url.spec());
611   args->SetBoolean(guestview::kIsTopLevel, is_main_frame);
612   args->SetInteger(webview::kInternalCurrentEntryIndex,
613       guest_web_contents()->GetController().GetCurrentEntryIndex());
614   args->SetInteger(webview::kInternalEntryCount,
615       guest_web_contents()->GetController().GetEntryCount());
616   args->SetInteger(webview::kInternalProcessId,
617       guest_web_contents()->GetRenderProcessHost()->GetID());
618   DispatchEvent(new GuestView::Event(webview::kEventLoadCommit, args.Pass()));
619
620   // Update the current zoom factor for the new page.
621   current_zoom_factor_ = content::ZoomLevelToZoomFactor(
622       guest_web_contents()->GetZoomLevel());
623
624   if (is_main_frame) {
625     chromevox_injected_ = false;
626     main_frame_id_ = frame_id;
627   }
628 }
629
630 void WebViewGuest::DidFailProvisionalLoad(
631     int64 frame_id,
632     const base::string16& frame_unique_name,
633     bool is_main_frame,
634     const GURL& validated_url,
635     int error_code,
636     const base::string16& error_description,
637     content::RenderViewHost* render_view_host) {
638   // Translate the |error_code| into an error string.
639   std::string error_type;
640   base::RemoveChars(net::ErrorToString(error_code), "net::", &error_type);
641   LoadAbort(is_main_frame, validated_url, error_type);
642 }
643
644 void WebViewGuest::DidStartProvisionalLoadForFrame(
645     int64 frame_id,
646     int64 parent_frame_id,
647     bool is_main_frame,
648     const GURL& validated_url,
649     bool is_error_page,
650     bool is_iframe_srcdoc,
651     content::RenderViewHost* render_view_host) {
652   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
653   args->SetString(guestview::kUrl, validated_url.spec());
654   args->SetBoolean(guestview::kIsTopLevel, is_main_frame);
655   DispatchEvent(new GuestView::Event(webview::kEventLoadStart, args.Pass()));
656 }
657
658 void WebViewGuest::DocumentLoadedInFrame(
659     int64 frame_id,
660     content::RenderViewHost* render_view_host) {
661   if (frame_id == main_frame_id_)
662     InjectChromeVoxIfNeeded(render_view_host);
663 }
664
665 void WebViewGuest::DidStopLoading(content::RenderViewHost* render_view_host) {
666   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
667   DispatchEvent(new GuestView::Event(webview::kEventLoadStop, args.Pass()));
668 }
669
670 void WebViewGuest::WebContentsDestroyed(WebContents* web_contents) {
671   RemoveWebViewFromExtensionRendererState(web_contents);
672 }
673
674 void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) {
675   content::NavigationController& controller =
676       guest_web_contents()->GetController();
677   content::NavigationEntry* entry = controller.GetVisibleEntry();
678   if (!entry)
679     return;
680   entry->SetIsOverridingUserAgent(!user_agent.empty());
681   if (!attached()) {
682     // We cannot reload now because all resource loads are suspended until
683     // attachment.
684     pending_reload_on_attachment_ = true;
685     return;
686   }
687   guest_web_contents()->GetController().Reload(false);
688 }
689
690 void WebViewGuest::LoadHandlerCalled() {
691   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
692   DispatchEvent(new GuestView::Event(webview::kEventContentLoad, args.Pass()));
693 }
694
695 void WebViewGuest::LoadRedirect(const GURL& old_url,
696                                 const GURL& new_url,
697                                 bool is_top_level) {
698   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
699   args->SetBoolean(guestview::kIsTopLevel, is_top_level);
700   args->SetString(webview::kNewURL, new_url.spec());
701   args->SetString(webview::kOldURL, old_url.spec());
702   DispatchEvent(new GuestView::Event(webview::kEventLoadRedirect, args.Pass()));
703 }
704
705 void WebViewGuest::AddWebViewToExtensionRendererState() {
706   const GURL& site_url = guest_web_contents()->GetSiteInstance()->GetSiteURL();
707   std::string partition_domain;
708   std::string partition_id;
709   bool in_memory;
710   if (!GetGuestPartitionConfigForSite(
711           site_url, &partition_domain, &partition_id, &in_memory)) {
712     NOTREACHED();
713     return;
714   }
715   DCHECK(extension_id() == partition_domain);
716
717   ExtensionRendererState::WebViewInfo webview_info;
718   webview_info.embedder_process_id = embedder_render_process_id();
719   webview_info.instance_id = view_instance_id();
720   webview_info.partition_id =  partition_id;
721   webview_info.extension_id = extension_id();
722
723   content::BrowserThread::PostTask(
724       content::BrowserThread::IO, FROM_HERE,
725       base::Bind(
726           &ExtensionRendererState::AddWebView,
727           base::Unretained(ExtensionRendererState::GetInstance()),
728           guest_web_contents()->GetRenderProcessHost()->GetID(),
729           guest_web_contents()->GetRoutingID(),
730           webview_info));
731 }
732
733 // static
734 void WebViewGuest::RemoveWebViewFromExtensionRendererState(
735     WebContents* web_contents) {
736   content::BrowserThread::PostTask(
737       content::BrowserThread::IO, FROM_HERE,
738       base::Bind(
739           &ExtensionRendererState::RemoveWebView,
740           base::Unretained(ExtensionRendererState::GetInstance()),
741           web_contents->GetRenderProcessHost()->GetID(),
742           web_contents->GetRoutingID()));
743 }
744
745 GURL WebViewGuest::ResolveURL(const std::string& src) {
746   if (extension_id().empty()) {
747     NOTREACHED();
748     return GURL(src);
749   }
750
751   GURL default_url(base::StringPrintf("%s://%s/",
752                                       extensions::kExtensionScheme,
753                                       extension_id().c_str()));
754   return default_url.Resolve(src);
755 }
756
757 void WebViewGuest::SizeChanged(const gfx::Size& old_size,
758                                const gfx::Size& new_size) {
759   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
760   args->SetInteger(webview::kOldHeight, old_size.height());
761   args->SetInteger(webview::kOldWidth, old_size.width());
762   args->SetInteger(webview::kNewHeight, new_size.height());
763   args->SetInteger(webview::kNewWidth, new_size.width());
764   DispatchEvent(new GuestView::Event(webview::kEventSizeChanged, args.Pass()));
765 }
766
767 void WebViewGuest::InjectChromeVoxIfNeeded(
768     content::RenderViewHost* render_view_host) {
769 #if defined(OS_CHROMEOS)
770   if (!chromevox_injected_) {
771     chromeos::AccessibilityManager* manager =
772         chromeos::AccessibilityManager::Get();
773     if (manager && manager->IsSpokenFeedbackEnabled()) {
774       manager->InjectChromeVox(render_view_host);
775       chromevox_injected_ = true;
776     }
777   }
778 #endif
779 }
780
781 WebViewGuest::PermissionResponseInfo::PermissionResponseInfo()
782     : permission_type(BROWSER_PLUGIN_PERMISSION_TYPE_UNKNOWN),
783       allowed_by_default(false) {
784 }
785
786 WebViewGuest::PermissionResponseInfo::PermissionResponseInfo(
787     const PermissionResponseCallback& callback,
788     BrowserPluginPermissionType permission_type,
789     bool allowed_by_default)
790     : callback(callback),
791       permission_type(permission_type),
792       allowed_by_default(allowed_by_default) {
793 }
794
795 WebViewGuest::PermissionResponseInfo::~PermissionResponseInfo() {
796 }