Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / guest_view / web_view / web_view_guest.cc
index 2d6bb11..9d233f1 100644 (file)
@@ -8,28 +8,24 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
-#include "chrome/browser/extensions/api/webview/webview_api.h"
+#include "chrome/browser/extensions/api/web_view/web_view_internal_api.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
-#include "chrome/browser/extensions/extension_renderer_state.h"
 #include "chrome/browser/extensions/menu_manager.h"
-#include "chrome/browser/extensions/script_executor.h"
 #include "chrome/browser/favicon/favicon_tab_helper.h"
-#include "chrome/browser/geolocation/geolocation_permission_context.h"
-#include "chrome/browser/geolocation/geolocation_permission_context_factory.h"
-#include "chrome/browser/guest_view/guest_view_constants.h"
-#include "chrome/browser/guest_view/guest_view_manager.h"
 #include "chrome/browser/guest_view/web_view/web_view_constants.h"
+#include "chrome/browser/guest_view/web_view/web_view_permission_helper.h"
 #include "chrome/browser/guest_view/web_view/web_view_permission_types.h"
-#include "chrome/browser/renderer_context_menu/context_menu_delegate.h"
+#include "chrome/browser/guest_view/web_view/web_view_renderer_state.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
 #include "chrome/browser/ui/pdf/pdf_tab_helper.h"
+#include "chrome/browser/ui/zoom/zoom_controller.h"
 #include "chrome/common/chrome_version_info.h"
+#include "chrome/common/extensions/chrome_extension_messages.h"
 #include "chrome/common/render_messages.h"
+#include "components/renderer_context_menu/context_menu_delegate.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/host_zoom_map.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_details.h"
@@ -49,6 +45,9 @@
 #include "content/public/common/result_codes.h"
 #include "content/public/common/stop_find_action.h"
 #include "content/public/common/url_constants.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/guest_view/guest_view_constants.h"
+#include "extensions/browser/guest_view/guest_view_manager.h"
 #include "extensions/common/constants.h"
 #include "ipc/ipc_message_macros.h"
 #include "net/base/escape.h"
 #endif  // defined(ENABLE_FULL_PRINTING)
 #endif  // defined(ENABLE_PRINTING)
 
-#if defined(ENABLE_PLUGINS)
-#include "chrome/browser/guest_view/web_view/plugin_permission_helper.h"
-#endif
-
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #endif
 
 using base::UserMetricsAction;
 using content::RenderFrameHost;
+using content::ResourceType;
 using content::WebContents;
 
+namespace extensions {
+
 namespace {
 
 std::string WindowOpenDispositionToString(
@@ -112,9 +110,6 @@ static std::string TerminationStatusToString(base::TerminationStatus status) {
     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
       return "killed";
     case base::TERMINATION_STATUS_PROCESS_CRASHED:
-#if defined(OS_ANDROID)
-    case base::TERMINATION_STATUS_OOM_PROTECTED:
-#endif
       return "crashed";
     case base::TERMINATION_STATUS_MAX_ENUM:
       break;
@@ -123,30 +118,6 @@ static std::string TerminationStatusToString(base::TerminationStatus status) {
   return "unknown";
 }
 
-static std::string PermissionTypeToString(WebViewPermissionType type) {
-  switch (type) {
-    case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD:
-      return webview::kPermissionTypeDownload;
-    case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM:
-      return webview::kPermissionTypeFileSystem;
-    case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION:
-      return webview::kPermissionTypeGeolocation;
-    case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
-      return webview::kPermissionTypeDialog;
-    case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN:
-      return webview::kPermissionTypeLoadPlugin;
-    case WEB_VIEW_PERMISSION_TYPE_MEDIA:
-      return webview::kPermissionTypeMedia;
-    case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW:
-      return webview::kPermissionTypeNewWindow;
-    case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK:
-      return webview::kPermissionTypePointerLock;
-    default:
-      NOTREACHED();
-      return std::string();
-  }
-}
-
 std::string GetStoragePartitionIdFromSiteURL(const GURL& site_url) {
   const std::string& partition_id = site_url.query();
   bool persist_storage = site_url.path().find("persist") != std::string::npos;
@@ -166,58 +137,41 @@ void RemoveWebViewEventListenersOnIOThread(
       view_instance_id);
 }
 
-void AttachWebViewHelpers(WebContents* contents) {
-  FaviconTabHelper::CreateForWebContents(contents);
-  extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
-      contents);
-#if defined(ENABLE_PLUGINS)
-  PluginPermissionHelper::CreateForWebContents(contents);
-#endif
-#if defined(ENABLE_PRINTING)
-#if defined(ENABLE_FULL_PRINTING)
-  printing::PrintViewManager::CreateForWebContents(contents);
-  printing::PrintPreviewMessageHandler::CreateForWebContents(contents);
-#else
-  printing::PrintViewManagerBasic::CreateForWebContents(contents);
-#endif  // defined(ENABLE_FULL_PRINTING)
-#endif  // defined(ENABLE_PRINTING)
-  PDFTabHelper::CreateForWebContents(contents);
-}
-
-}  // namespace
+void ParsePartitionParam(const base::DictionaryValue& create_params,
+                         std::string* storage_partition_id,
+                         bool* persist_storage) {
+  std::string partition_str;
+  if (!create_params.GetString(webview::kStoragePartitionId, &partition_str)) {
+    return;
+  }
 
-WebViewGuest::WebViewGuest(int guest_instance_id,
-                           WebContents* guest_web_contents,
-                           const std::string& embedder_extension_id)
-   :  GuestView<WebViewGuest>(guest_instance_id),
-      script_executor_(new extensions::ScriptExecutor(guest_web_contents,
-                                                      &script_observers_)),
-      pending_context_menu_request_id_(0),
-      next_permission_request_id_(0),
-      is_overriding_user_agent_(false),
-      main_frame_id_(0),
-      chromevox_injected_(false),
-      find_helper_(this),
-      javascript_dialog_helper_(this) {
-  Init(guest_web_contents, embedder_extension_id);
-  notification_registrar_.Add(
-      this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-      content::Source<WebContents>(guest_web_contents));
+  // Since the "persist:" prefix is in ASCII, StartsWith will work fine on
+  // UTF-8 encoded |partition_id|. If the prefix is a match, we can safely
+  // remove the prefix without splicing in the middle of a multi-byte codepoint.
+  // We can use the rest of the string as UTF-8 encoded one.
+  if (StartsWithASCII(partition_str, "persist:", true)) {
+    size_t index = partition_str.find(":");
+    CHECK(index != std::string::npos);
+    // It is safe to do index + 1, since we tested for the full prefix above.
+    *storage_partition_id = partition_str.substr(index + 1);
 
-  notification_registrar_.Add(
-      this, content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
-      content::Source<WebContents>(guest_web_contents));
+    if (storage_partition_id->empty()) {
+      // TODO(lazyboy): Better way to deal with this error.
+      return;
+    }
+    *persist_storage = true;
+  } else {
+    *storage_partition_id = partition_str;
+    *persist_storage = false;
+  }
+}
 
-#if defined(OS_CHROMEOS)
-  chromeos::AccessibilityManager* accessibility_manager =
-      chromeos::AccessibilityManager::Get();
-  CHECK(accessibility_manager);
-  accessibility_subscription_ = accessibility_manager->RegisterCallback(
-      base::Bind(&WebViewGuest::OnAccessibilityStatusChanged,
-                 base::Unretained(this)));
-#endif
+}  // namespace
 
-  AttachWebViewHelpers(guest_web_contents);
+// static
+GuestViewBase* WebViewGuest::Create(content::BrowserContext* browser_context,
+                                    int guest_instance_id) {
+  return new WebViewGuest(browser_context, guest_instance_id);
 }
 
 // static
@@ -256,120 +210,6 @@ int WebViewGuest::GetViewInstanceId(WebContents* contents) {
 }
 
 // static
-void WebViewGuest::ParsePartitionParam(
-    const base::DictionaryValue* extra_params,
-    std::string* storage_partition_id,
-    bool* persist_storage) {
-  std::string partition_str;
-  if (!extra_params->GetString(webview::kStoragePartitionId, &partition_str)) {
-    return;
-  }
-
-  // Since the "persist:" prefix is in ASCII, StartsWith will work fine on
-  // UTF-8 encoded |partition_id|. If the prefix is a match, we can safely
-  // remove the prefix without splicing in the middle of a multi-byte codepoint.
-  // We can use the rest of the string as UTF-8 encoded one.
-  if (StartsWithASCII(partition_str, "persist:", true)) {
-    size_t index = partition_str.find(":");
-    CHECK(index != std::string::npos);
-    // It is safe to do index + 1, since we tested for the full prefix above.
-    *storage_partition_id = partition_str.substr(index + 1);
-
-    if (storage_partition_id->empty()) {
-      // TODO(lazyboy): Better way to deal with this error.
-      return;
-    }
-    *persist_storage = true;
-  } else {
-    *storage_partition_id = partition_str;
-    *persist_storage = false;
-  }
-}
-
-// static
-void WebViewGuest::RecordUserInitiatedUMA(const PermissionResponseInfo& info,
-                                          bool allow) {
-  if (allow) {
-    // Note that |allow| == true means the embedder explicitly allowed the
-    // request. For some requests they might still fail. An example of such
-    // scenario would be: an embedder allows geolocation request but doesn't
-    // have geolocation access on its own.
-    switch (info.permission_type) {
-      case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionAllow.Download"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionAllow.FileSystem"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionAllow.Geolocation"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionAllow.JSDialog"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN:
-        content::RecordAction(
-            UserMetricsAction("WebView.Guest.PermissionAllow.PluginLoad"));
-      case WEB_VIEW_PERMISSION_TYPE_MEDIA:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionAllow.Media"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW:
-        content::RecordAction(
-            UserMetricsAction("BrowserPlugin.PermissionAllow.NewWindow"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionAllow.PointerLock"));
-        break;
-      default:
-        break;
-    }
-  } else {
-    switch (info.permission_type) {
-      case WEB_VIEW_PERMISSION_TYPE_DOWNLOAD:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionDeny.Download"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_FILESYSTEM:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionDeny.FileSystem"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_GEOLOCATION:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionDeny.Geolocation"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionDeny.JSDialog"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_LOAD_PLUGIN:
-        content::RecordAction(
-            UserMetricsAction("WebView.Guest.PermissionDeny.PluginLoad"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_MEDIA:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionDeny.Media"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW:
-        content::RecordAction(
-            UserMetricsAction("BrowserPlugin.PermissionDeny.NewWindow"));
-        break;
-      case WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK:
-        content::RecordAction(
-            UserMetricsAction("WebView.PermissionDeny.PointerLock"));
-        break;
-      default:
-        break;
-    }
-  }
-}
-
-// static
 scoped_ptr<base::ListValue> WebViewGuest::MenuModelToValue(
     const ui::SimpleMenuModel& menu_model) {
   scoped_ptr<base::ListValue> items(new base::ListValue());
@@ -385,7 +225,71 @@ scoped_ptr<base::ListValue> WebViewGuest::MenuModelToValue(
   return items.Pass();
 }
 
+const char* WebViewGuest::GetAPINamespace() {
+  return webview::kAPINamespace;
+}
+
+void WebViewGuest::CreateWebContents(
+    const std::string& embedder_extension_id,
+    int embedder_render_process_id,
+    const base::DictionaryValue& create_params,
+    const WebContentsCreatedCallback& callback) {
+  content::RenderProcessHost* embedder_render_process_host =
+      content::RenderProcessHost::FromID(embedder_render_process_id);
+  std::string storage_partition_id;
+  bool persist_storage = false;
+  std::string storage_partition_string;
+  ParsePartitionParam(create_params, &storage_partition_id, &persist_storage);
+  // Validate that the partition id coming from the renderer is valid UTF-8,
+  // since we depend on this in other parts of the code, such as FilePath
+  // creation. If the validation fails, treat it as a bad message and kill the
+  // renderer process.
+  if (!base::IsStringUTF8(storage_partition_id)) {
+    content::RecordAction(
+        base::UserMetricsAction("BadMessageTerminate_BPGM"));
+    base::KillProcess(
+        embedder_render_process_host->GetHandle(),
+        content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
+    callback.Run(NULL);
+    return;
+  }
+  std::string url_encoded_partition = net::EscapeQueryParamValue(
+      storage_partition_id, false);
+  // The SiteInstance of a given webview tag is based on the fact that it's
+  // a guest process in addition to which platform application the tag
+  // belongs to and what storage partition is in use, rather than the URL
+  // that the tag is being navigated to.
+  GURL guest_site(base::StringPrintf("%s://%s/%s?%s",
+                                     content::kGuestScheme,
+                                     embedder_extension_id.c_str(),
+                                     persist_storage ? "persist" : "",
+                                     url_encoded_partition.c_str()));
+
+  // If we already have a webview tag in the same app using the same storage
+  // partition, we should use the same SiteInstance so the existing tag and
+  // the new tag can script each other.
+  GuestViewManager* guest_view_manager =
+      GuestViewManager::FromBrowserContext(
+          embedder_render_process_host->GetBrowserContext());
+  content::SiteInstance* guest_site_instance =
+      guest_view_manager->GetGuestSiteInstance(guest_site);
+  if (!guest_site_instance) {
+    // Create the SiteInstance in a new BrowsingInstance, which will ensure
+    // that webview tags are also not allowed to send messages across
+    // different partitions.
+    guest_site_instance = content::SiteInstance::CreateForURL(
+        embedder_render_process_host->GetBrowserContext(), guest_site);
+  }
+  WebContents::CreateParams params(
+      embedder_render_process_host->GetBrowserContext(),
+      guest_site_instance);
+  params.guest_delegate = this;
+  callback.Run(WebContents::Create(params));
+}
+
 void WebViewGuest::DidAttachToEmbedder() {
+  SetUpAutoSize();
+
   std::string name;
   if (extra_params()->GetString(webview::kName, &name)) {
     // If the guest window's name is empty, then the WebView tag's name is
@@ -427,11 +331,69 @@ void WebViewGuest::DidAttachToEmbedder() {
     // lifetime of the new guest is no longer managed by the opener guest.
     GetOpener()->pending_new_windows_.erase(this);
   }
+
+  ZoomController* zoom_controller = ZoomController::FromWebContents(
+      embedder_web_contents());
+  if (!zoom_controller)
+    return;
+  // Listen to the embedder's zoom changes.
+  zoom_controller->AddObserver(this);
+  // Set the guest's initial zoom level to be equal to the embedder's.
+  ZoomController::FromWebContents(guest_web_contents())->
+      SetZoomLevel(zoom_controller->GetZoomLevel());
+}
+
+void WebViewGuest::DidInitialize() {
+  script_executor_.reset(
+      new ScriptExecutor(guest_web_contents(), &script_observers_));
+
+  notification_registrar_.Add(
+      this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+      content::Source<WebContents>(guest_web_contents()));
+
+  notification_registrar_.Add(
+      this, content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
+      content::Source<WebContents>(guest_web_contents()));
+
+#if defined(OS_CHROMEOS)
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  CHECK(accessibility_manager);
+  accessibility_subscription_ = accessibility_manager->RegisterCallback(
+      base::Bind(&WebViewGuest::OnAccessibilityStatusChanged,
+                 base::Unretained(this)));
+#endif
+
+  AttachWebViewHelpers(guest_web_contents());
+}
+
+void WebViewGuest::AttachWebViewHelpers(WebContents* contents) {
+  // Create a zoom controller for the guest contents give it access to
+  // GetZoomLevel() and and SetZoomLevel() in WebViewGuest.
+  // TODO(wjmaclean) This currently uses the same HostZoomMap as the browser
+  // context, but we eventually want to isolate the guest contents from zoom
+  // changes outside the guest (e.g. in the main browser), so we should
+  // create a separate HostZoomMap for the guest.
+  ZoomController::CreateForWebContents(contents);
+
+  FaviconTabHelper::CreateForWebContents(contents);
+  ChromeExtensionWebContentsObserver::CreateForWebContents(contents);
+#if defined(ENABLE_PRINTING)
+#if defined(ENABLE_FULL_PRINTING)
+  printing::PrintViewManager::CreateForWebContents(contents);
+  printing::PrintPreviewMessageHandler::CreateForWebContents(contents);
+#else
+  printing::PrintViewManagerBasic::CreateForWebContents(contents);
+#endif  // defined(ENABLE_FULL_PRINTING)
+#endif  // defined(ENABLE_PRINTING)
+  PDFTabHelper::CreateForWebContents(contents);
+  web_view_permission_helper_.reset(new WebViewPermissionHelper(this));
 }
 
 void WebViewGuest::DidStopLoading() {
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
-  DispatchEvent(new GuestViewBase::Event(webview::kEventLoadStop, args.Pass()));
+  DispatchEventToEmbedder(
+      new GuestViewBase::Event(webview::kEventLoadStop, args.Pass()));
 }
 
 void WebViewGuest::EmbedderDestroyed() {
@@ -454,12 +416,33 @@ void WebViewGuest::EmbedderDestroyed() {
 
 void WebViewGuest::GuestDestroyed() {
   // Clean up custom context menu items for this guest.
-  extensions::MenuManager* menu_manager = extensions::MenuManager::Get(
+  MenuManager* menu_manager = MenuManager::Get(
       Profile::FromBrowserContext(browser_context()));
-  menu_manager->RemoveAllContextItems(extensions::MenuItem::ExtensionKey(
+  menu_manager->RemoveAllContextItems(MenuItem::ExtensionKey(
       embedder_extension_id(), view_instance_id()));
 
-  RemoveWebViewFromExtensionRendererState(web_contents());
+  RemoveWebViewStateFromIOThread(web_contents());
+}
+
+void WebViewGuest::GuestReady() {
+  // The guest RenderView should always live in an isolated guest process.
+  CHECK(guest_web_contents()->GetRenderProcessHost()->IsIsolatedGuest());
+  Send(new ChromeViewMsg_SetName(guest_web_contents()->GetRoutingID(), name_));
+}
+
+void WebViewGuest::GuestSizeChangedDueToAutoSize(const gfx::Size& old_size,
+                                                 const gfx::Size& new_size) {
+  scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
+  args->SetInteger(webview::kOldHeight, old_size.height());
+  args->SetInteger(webview::kOldWidth, old_size.width());
+  args->SetInteger(webview::kNewHeight, new_size.height());
+  args->SetInteger(webview::kNewWidth, new_size.width());
+  DispatchEventToEmbedder(
+      new GuestViewBase::Event(webview::kEventSizeChanged, args.Pass()));
+}
+
+bool WebViewGuest::IsAutoSizeSupported() const {
+  return true;
 }
 
 bool WebViewGuest::IsDragAndDropEnabled() const {
@@ -483,14 +466,15 @@ bool WebViewGuest::AddMessageToConsole(WebContents* source,
   args->SetString(webview::kMessage, message);
   args->SetInteger(webview::kLine, line_no);
   args->SetString(webview::kSourceId, source_id);
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventConsoleMessage, args.Pass()));
   return true;
 }
 
 void WebViewGuest::CloseContents(WebContents* source) {
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
-  DispatchEvent(new GuestViewBase::Event(webview::kEventClose, args.Pass()));
+  DispatchEventToEmbedder(
+      new GuestViewBase::Event(webview::kEventClose, args.Pass()));
 }
 
 void WebViewGuest::FindReply(WebContents* source,
@@ -518,8 +502,8 @@ bool WebViewGuest::HandleContextMenu(
       MenuModelToValue(pending_menu_->menu_model());
   args->Set(webview::kContextMenuItems, items.release());
   args->SetInteger(webview::kRequestId, request_id);
-  DispatchEvent(new GuestViewBase::Event(webview::kEventContextMenu,
-                                         args.Pass()));
+  DispatchEventToEmbedder(
+      new GuestViewBase::Event(webview::kEventContextMenu, args.Pass()));
   return true;
 }
 
@@ -547,7 +531,7 @@ void WebViewGuest::LoadProgressChanged(content::WebContents* source,
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
   args->SetString(guestview::kUrl, guest_web_contents()->GetURL().spec());
   args->SetDouble(webview::kProgress, progress);
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventLoadProgress, args.Pass()));
 }
 
@@ -558,7 +542,7 @@ void WebViewGuest::LoadAbort(bool is_top_level,
   args->SetBoolean(guestview::kIsTopLevel, is_top_level);
   args->SetString(guestview::kUrl, url.possibly_invalid_spec());
   args->SetString(guestview::kReason, error_type);
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventLoadAbort, args.Pass()));
 }
 
@@ -573,28 +557,32 @@ void WebViewGuest::OnUpdateFrameName(bool is_top_level,
   ReportFrameNameChange(name);
 }
 
-WebViewGuest* WebViewGuest::CreateNewGuestWindow(
+void WebViewGuest::CreateNewGuestWebViewWindow(
     const content::OpenURLParams& params) {
   GuestViewManager* guest_manager =
       GuestViewManager::FromBrowserContext(browser_context());
-  // Allocate a new instance ID for the new guest.
-  int instance_id = guest_manager->GetNextInstanceID();
-
   // Set the attach params to use the same partition as the opener.
   // We pull the partition information from the site's URL, which is of the
   // form guest://site/{persist}?{partition_name}.
   const GURL& site_url = guest_web_contents()->GetSiteInstance()->GetSiteURL();
-  scoped_ptr<base::DictionaryValue> create_params(extra_params()->DeepCopy());
   const std::string storage_partition_id =
       GetStoragePartitionIdFromSiteURL(site_url);
-  create_params->SetString(webview::kStoragePartitionId, storage_partition_id);
-
-  WebContents* new_guest_web_contents =
-      guest_manager->CreateGuest(guest_web_contents()->GetSiteInstance(),
-                                 instance_id,
-                                 create_params.Pass());
-  WebViewGuest* new_guest =
-      WebViewGuest::FromWebContents(new_guest_web_contents);
+  base::DictionaryValue create_params;
+  create_params.SetString(webview::kStoragePartitionId, storage_partition_id);
+
+  guest_manager->CreateGuest(WebViewGuest::Type,
+                             embedder_extension_id(),
+                             embedder_web_contents(),
+                             create_params,
+                             base::Bind(&WebViewGuest::NewGuestWebViewCallback,
+                                        base::Unretained(this),
+                                        params));
+}
+
+void WebViewGuest::NewGuestWebViewCallback(
+    const content::OpenURLParams& params,
+    content::WebContents* guest_web_contents) {
+  WebViewGuest* new_guest = WebViewGuest::FromWebContents(guest_web_contents);
   new_guest->SetOpener(this);
 
   // Take ownership of |new_guest|.
@@ -605,8 +593,6 @@ WebViewGuest* WebViewGuest::CreateNewGuestWindow(
   RequestNewWindowPermission(params.disposition, gfx::Rect(),
                              params.user_gesture,
                              new_guest->guest_web_contents());
-
-  return new_guest;
 }
 
 // TODO(fsamuel): Find a reliable way to test the 'responsive' and
@@ -615,7 +601,7 @@ void WebViewGuest::RendererResponsive(content::WebContents* source) {
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
   args->SetInteger(webview::kProcessId,
       guest_web_contents()->GetRenderProcessHost()->GetID());
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventResponsive, args.Pass()));
 }
 
@@ -623,7 +609,7 @@ void WebViewGuest::RendererUnresponsive(content::WebContents* source) {
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
   args->SetInteger(webview::kProcessId,
       guest_web_contents()->GetRenderProcessHost()->GetID());
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventUnresponsive, args.Pass()));
 }
 
@@ -643,8 +629,8 @@ void WebViewGuest::Observe(int type,
                 guest_web_contents());
       content::ResourceRedirectDetails* resource_redirect_details =
           content::Details<content::ResourceRedirectDetails>(details).ptr();
-      bool is_top_level =
-          resource_redirect_details->resource_type == ResourceType::MAIN_FRAME;
+      bool is_top_level = resource_redirect_details->resource_type ==
+                          content::RESOURCE_TYPE_MAIN_FRAME;
       LoadRedirect(resource_redirect_details->url,
                    resource_redirect_details->new_url,
                    is_top_level);
@@ -663,7 +649,7 @@ double WebViewGuest::GetZoom() {
 void WebViewGuest::Find(
     const base::string16& search_text,
     const blink::WebFindOptions& options,
-    scoped_refptr<extensions::WebviewFindFunction> find_function) {
+    scoped_refptr<WebViewInternalFindFunction> find_function) {
   find_helper_.Find(guest_web_contents(), search_text, options, find_function);
 }
 
@@ -683,154 +669,6 @@ void WebViewGuest::Reload() {
   guest_web_contents()->GetController().Reload(false);
 }
 
-void WebViewGuest::RequestFileSystemPermission(
-    const GURL& url,
-    bool allowed_by_default,
-    const base::Callback<void(bool)>& callback) {
-  base::DictionaryValue request_info;
-  request_info.Set(guestview::kUrl, base::Value::CreateStringValue(url.spec()));
-  RequestPermission(
-      WEB_VIEW_PERMISSION_TYPE_FILESYSTEM,
-      request_info,
-      base::Bind(&WebViewGuest::OnWebViewFileSystemPermissionResponse,
-                 base::Unretained(this),
-                 callback),
-      allowed_by_default);
-}
-
-void WebViewGuest::OnWebViewFileSystemPermissionResponse(
-    const base::Callback<void(bool)>& callback,
-    bool allow,
-    const std::string& user_input) {
-  callback.Run(allow && attached());
-}
-
-void WebViewGuest::RequestGeolocationPermission(
-    int bridge_id,
-    const GURL& requesting_frame,
-    bool user_gesture,
-    const base::Callback<void(bool)>& callback) {
-  base::DictionaryValue request_info;
-  request_info.Set(guestview::kUrl,
-                   base::Value::CreateStringValue(requesting_frame.spec()));
-  request_info.Set(guestview::kUserGesture,
-                   base::Value::CreateBooleanValue(user_gesture));
-
-  // It is safe to hold an unretained pointer to WebViewGuest because this
-  // callback is called from WebViewGuest::SetPermission.
-  const PermissionResponseCallback permission_callback =
-      base::Bind(&WebViewGuest::OnWebViewGeolocationPermissionResponse,
-                 base::Unretained(this),
-                 bridge_id,
-                 user_gesture,
-                 callback);
-  int request_id = RequestPermission(
-      WEB_VIEW_PERMISSION_TYPE_GEOLOCATION,
-      request_info,
-      permission_callback,
-      false /* allowed_by_default */);
-  bridge_id_to_request_id_map_[bridge_id] = request_id;
-}
-
-void WebViewGuest::OnWebViewGeolocationPermissionResponse(
-    int bridge_id,
-    bool user_gesture,
-    const base::Callback<void(bool)>& callback,
-    bool allow,
-    const std::string& user_input) {
-  // The <webview> embedder has allowed the permission. We now need to make sure
-  // that the embedder has geolocation permission.
-  RemoveBridgeID(bridge_id);
-
-  if (!allow || !attached()) {
-    callback.Run(false);
-    return;
-  }
-
-  Profile* profile = Profile::FromBrowserContext(browser_context());
-  GeolocationPermissionContextFactory::GetForProfile(profile)->
-      RequestGeolocationPermission(
-          embedder_web_contents(),
-          // The geolocation permission request here is not initiated
-          // through WebGeolocationPermissionRequest. We are only interested
-          // in the fact whether the embedder/app has geolocation
-          // permission. Therefore we use an invalid |bridge_id|.
-          -1,
-          embedder_web_contents()->GetLastCommittedURL(),
-          user_gesture,
-          callback,
-          NULL);
-}
-
-void WebViewGuest::CancelGeolocationPermissionRequest(int bridge_id) {
-  int request_id = RemoveBridgeID(bridge_id);
-  RequestMap::iterator request_itr =
-      pending_permission_requests_.find(request_id);
-
-  if (request_itr == pending_permission_requests_.end())
-    return;
-
-  pending_permission_requests_.erase(request_itr);
-}
-
-void WebViewGuest::OnWebViewMediaPermissionResponse(
-    const content::MediaStreamRequest& request,
-    const content::MediaResponseCallback& callback,
-    bool allow,
-    const std::string& user_input) {
-  if (!allow || !attached()) {
-    // Deny the request.
-    callback.Run(content::MediaStreamDevices(),
-                 content::MEDIA_DEVICE_INVALID_STATE,
-                 scoped_ptr<content::MediaStreamUI>());
-    return;
-  }
-  if (!embedder_web_contents()->GetDelegate())
-    return;
-
-  embedder_web_contents()->GetDelegate()->
-      RequestMediaAccessPermission(embedder_web_contents(), request, callback);
-}
-
-void WebViewGuest::OnWebViewDownloadPermissionResponse(
-    const base::Callback<void(bool)>& callback,
-    bool allow,
-    const std::string& user_input) {
-  callback.Run(allow && attached());
-}
-
-void WebViewGuest::OnWebViewPointerLockPermissionResponse(
-    const base::Callback<void(bool)>& callback,
-    bool allow,
-    const std::string& user_input) {
-  callback.Run(allow && attached());
-}
-
-WebViewGuest::SetPermissionResult WebViewGuest::SetPermission(
-    int request_id,
-    PermissionResponseAction action,
-    const std::string& user_input) {
-  RequestMap::iterator request_itr =
-      pending_permission_requests_.find(request_id);
-
-  if (request_itr == pending_permission_requests_.end())
-    return SET_PERMISSION_INVALID;
-
-  const PermissionResponseInfo& info = request_itr->second;
-  bool allow = (action == ALLOW) ||
-      ((action == DEFAULT) && info.allowed_by_default);
-
-  info.callback.Run(allow, user_input);
-
-  // Only record user initiated (i.e. non-default) actions.
-  if (action != DEFAULT)
-    RecordUserInitiatedUMA(info, allow);
-
-  pending_permission_requests_.erase(request_itr);
-
-  return allow ? SET_PERMISSION_ALLOWED : SET_PERMISSION_DENIED;
-}
-
 void WebViewGuest::SetUserAgentOverride(
     const std::string& user_agent_override) {
   if (!attached())
@@ -877,147 +715,73 @@ bool WebViewGuest::ClearData(const base::Time remove_since,
   return true;
 }
 
-// static
-void WebViewGuest::FileSystemAccessedAsync(int render_process_id,
-                                           int render_frame_id,
-                                           int request_id,
-                                           const GURL& url,
-                                           bool blocked_by_policy) {
-  WebViewGuest* guest =
-      WebViewGuest::FromFrameID(render_process_id, render_frame_id);
-  DCHECK(guest);
-  guest->RequestFileSystemPermission(
-      url,
-      !blocked_by_policy,
-      base::Bind(&WebViewGuest::FileSystemAccessedAsyncResponse,
-                 render_process_id,
-                 render_frame_id,
-                 request_id,
-                 url));
-}
-
-// static
-void WebViewGuest::FileSystemAccessedAsyncResponse(int render_process_id,
-                                                   int render_frame_id,
-                                                   int request_id,
-                                                   const GURL& url,
-                                                   bool allowed) {
-  TabSpecificContentSettings::FileSystemAccessed(
-      render_process_id, render_frame_id, url, !allowed);
-  content::RenderFrameHost* render_frame_host =
-      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
-  if (!render_frame_host)
-    return;
-  render_frame_host->Send(
-      new ChromeViewMsg_RequestFileSystemAccessAsyncResponse(
-          render_frame_id, request_id, allowed));
-}
-
-// static
-void WebViewGuest::FileSystemAccessedSync(int render_process_id,
-                                          int render_frame_id,
-                                          const GURL& url,
-                                          bool blocked_by_policy,
-                                          IPC::Message* reply_msg) {
-  WebViewGuest* guest =
-      WebViewGuest::FromFrameID(render_process_id, render_frame_id);
-  DCHECK(guest);
-  guest->RequestFileSystemPermission(
-      url,
-      !blocked_by_policy,
-      base::Bind(&WebViewGuest::FileSystemAccessedSyncResponse,
-                 render_process_id,
-                 render_frame_id,
-                 url,
-                 reply_msg));
-}
-
-// static
-void WebViewGuest::FileSystemAccessedSyncResponse(int render_process_id,
-                                                  int render_frame_id,
-                                                  const GURL& url,
-                                                  IPC::Message* reply_msg,
-                                                  bool allowed) {
-  TabSpecificContentSettings::FileSystemAccessed(
-      render_process_id, render_frame_id, url, !allowed);
-  ChromeViewHostMsg_RequestFileSystemAccessSync::WriteReplyParams(reply_msg,
-                                                                  allowed);
-  content::RenderFrameHost* render_frame_host =
-      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
-  if (!render_frame_id)
-    return;
-  render_frame_host->Send(reply_msg);
+WebViewGuest::WebViewGuest(content::BrowserContext* browser_context,
+                           int guest_instance_id)
+    : GuestView<WebViewGuest>(browser_context, guest_instance_id),
+      pending_context_menu_request_id_(0),
+      is_overriding_user_agent_(false),
+      chromevox_injected_(false),
+      current_zoom_factor_(1.0),
+      find_helper_(this),
+      javascript_dialog_helper_(this) {
 }
 
 WebViewGuest::~WebViewGuest() {
 }
 
 void WebViewGuest::DidCommitProvisionalLoadForFrame(
-    int64 frame_id,
-    const base::string16& frame_unique_name,
-    bool is_main_frame,
+    content::RenderFrameHost* render_frame_host,
     const GURL& url,
-    content::PageTransition transition_type,
-    content::RenderViewHost* render_view_host) {
+    content::PageTransition transition_type) {
   find_helper_.CancelAllFindSessions();
 
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
   args->SetString(guestview::kUrl, url.spec());
-  args->SetBoolean(guestview::kIsTopLevel, is_main_frame);
+  args->SetBoolean(guestview::kIsTopLevel, !render_frame_host->GetParent());
   args->SetInteger(webview::kInternalCurrentEntryIndex,
       guest_web_contents()->GetController().GetCurrentEntryIndex());
   args->SetInteger(webview::kInternalEntryCount,
       guest_web_contents()->GetController().GetEntryCount());
   args->SetInteger(webview::kInternalProcessId,
       guest_web_contents()->GetRenderProcessHost()->GetID());
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventLoadCommit, args.Pass()));
 
   // Update the current zoom factor for the new page.
-  current_zoom_factor_ = content::ZoomLevelToZoomFactor(
-      content::HostZoomMap::GetZoomLevel(guest_web_contents()));
+  ZoomController* zoom_controller =
+      ZoomController::FromWebContents(guest_web_contents());
+  DCHECK(zoom_controller);
+  current_zoom_factor_ = zoom_controller->GetZoomLevel();
 
-  if (is_main_frame) {
+  if (!render_frame_host->GetParent())
     chromevox_injected_ = false;
-    main_frame_id_ = frame_id;
-  }
 }
 
 void WebViewGuest::DidFailProvisionalLoad(
-    int64 frame_id,
-    const base::string16& frame_unique_name,
-    bool is_main_frame,
+    content::RenderFrameHost* render_frame_host,
     const GURL& validated_url,
     int error_code,
-    const base::string16& error_description,
-    content::RenderViewHost* render_view_host) {
-  // Translate the |error_code| into an error string.
-  std::string error_type(net::ErrorToString(error_code));
-  DCHECK(StartsWithASCII(error_type, "net::", true));
-  error_type.erase(0, 5);
-  LoadAbort(is_main_frame, validated_url, error_type);
+    const base::string16& error_description) {
+  LoadAbort(!render_frame_host->GetParent(), validated_url,
+            net::ErrorToShortString(error_code));
 }
 
 void WebViewGuest::DidStartProvisionalLoadForFrame(
-    int64 frame_id,
-    int64 parent_frame_id,
-    bool is_main_frame,
+    content::RenderFrameHost* render_frame_host,
     const GURL& validated_url,
     bool is_error_page,
-    bool is_iframe_srcdoc,
-    content::RenderViewHost* render_view_host) {
+    bool is_iframe_srcdoc) {
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
   args->SetString(guestview::kUrl, validated_url.spec());
-  args->SetBoolean(guestview::kIsTopLevel, is_main_frame);
-  DispatchEvent(
+  args->SetBoolean(guestview::kIsTopLevel, !render_frame_host->GetParent());
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventLoadStart, args.Pass()));
 }
 
 void WebViewGuest::DocumentLoadedInFrame(
-    int64 frame_id,
-    content::RenderViewHost* render_view_host) {
-  if (frame_id == main_frame_id_)
-    InjectChromeVoxIfNeeded(render_view_host);
+    content::RenderFrameHost* render_frame_host) {
+  if (!render_frame_host->GetParent())
+    InjectChromeVoxIfNeeded(render_frame_host->GetRenderViewHost());
 }
 
 bool WebViewGuest::OnMessageReceived(const IPC::Message& message,
@@ -1038,7 +802,8 @@ void WebViewGuest::RenderProcessGone(base::TerminationStatus status) {
   args->SetInteger(webview::kProcessId,
                    guest_web_contents()->GetRenderProcessHost()->GetID());
   args->SetString(webview::kReason, TerminationStatusToString(status));
-  DispatchEvent(new GuestViewBase::Event(webview::kEventExit, args.Pass()));
+  DispatchEventToEmbedder(
+      new GuestViewBase::Event(webview::kEventExit, args.Pass()));
 }
 
 void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) {
@@ -1053,23 +818,17 @@ void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) {
   guest_web_contents()->GetController().Reload(false);
 }
 
-void WebViewGuest::RenderViewReady() {
-  // The guest RenderView should always live in an isolated guest process.
-  CHECK(guest_web_contents()->GetRenderProcessHost()->IsIsolatedGuest());
-  Send(new ChromeViewMsg_SetName(guest_web_contents()->GetRoutingID(), name_));
-}
-
 void WebViewGuest::ReportFrameNameChange(const std::string& name) {
   name_ = name;
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
   args->SetString(webview::kName, name);
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventFrameNameChanged, args.Pass()));
 }
 
 void WebViewGuest::LoadHandlerCalled() {
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventContentLoad, args.Pass()));
 }
 
@@ -1080,11 +839,11 @@ void WebViewGuest::LoadRedirect(const GURL& old_url,
   args->SetBoolean(guestview::kIsTopLevel, is_top_level);
   args->SetString(webview::kNewURL, new_url.spec());
   args->SetString(webview::kOldURL, old_url.spec());
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventLoadRedirect, args.Pass()));
 }
 
-void WebViewGuest::AddWebViewToExtensionRendererState() {
+void WebViewGuest::PushWebViewStateToIOThread() {
   const GURL& site_url = guest_web_contents()->GetSiteInstance()->GetSiteURL();
   std::string partition_domain;
   std::string partition_id;
@@ -1096,7 +855,7 @@ void WebViewGuest::AddWebViewToExtensionRendererState() {
   }
   DCHECK(embedder_extension_id() == partition_domain);
 
-  ExtensionRendererState::WebViewInfo web_view_info;
+  WebViewRendererState::WebViewInfo web_view_info;
   web_view_info.embedder_process_id = embedder_render_process_id();
   web_view_info.instance_id = view_instance_id();
   web_view_info.partition_id = partition_id;
@@ -1105,51 +864,43 @@ void WebViewGuest::AddWebViewToExtensionRendererState() {
   content::BrowserThread::PostTask(
       content::BrowserThread::IO,
       FROM_HERE,
-      base::Bind(&ExtensionRendererState::AddWebView,
-                 base::Unretained(ExtensionRendererState::GetInstance()),
+      base::Bind(&WebViewRendererState::AddGuest,
+                 base::Unretained(WebViewRendererState::GetInstance()),
                  guest_web_contents()->GetRenderProcessHost()->GetID(),
                  guest_web_contents()->GetRoutingID(),
                  web_view_info));
 }
 
 // static
-void WebViewGuest::RemoveWebViewFromExtensionRendererState(
+void WebViewGuest::RemoveWebViewStateFromIOThread(
     WebContents* web_contents) {
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
       base::Bind(
-          &ExtensionRendererState::RemoveWebView,
-          base::Unretained(ExtensionRendererState::GetInstance()),
+          &WebViewRendererState::RemoveGuest,
+          base::Unretained(WebViewRendererState::GetInstance()),
           web_contents->GetRenderProcessHost()->GetID(),
           web_contents->GetRoutingID()));
 }
 
-void WebViewGuest::SizeChanged(const gfx::Size& old_size,
-                               const gfx::Size& new_size) {
-  scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
-  args->SetInteger(webview::kOldHeight, old_size.height());
-  args->SetInteger(webview::kOldWidth, old_size.width());
-  args->SetInteger(webview::kNewHeight, new_size.height());
-  args->SetInteger(webview::kNewWidth, new_size.width());
-  DispatchEvent(
-      new GuestViewBase::Event(webview::kEventSizeChanged, args.Pass()));
+content::WebContents* WebViewGuest::CreateNewGuestWindow(
+    const content::WebContents::CreateParams& create_params) {
+  GuestViewManager* guest_manager =
+      GuestViewManager::FromBrowserContext(browser_context());
+  return guest_manager->CreateGuestWithWebContentsParams(
+      WebViewGuest::Type,
+      embedder_extension_id(),
+      embedder_web_contents()->GetRenderProcessHost()->GetID(),
+      create_params);
 }
 
 void WebViewGuest::RequestMediaAccessPermission(
     content::WebContents* source,
     const content::MediaStreamRequest& request,
     const content::MediaResponseCallback& callback) {
-  base::DictionaryValue request_info;
-  request_info.Set(
-      guestview::kUrl,
-      base::Value::CreateStringValue(request.security_origin.spec()));
-  RequestPermission(WEB_VIEW_PERMISSION_TYPE_MEDIA,
-                    request_info,
-                    base::Bind(&WebViewGuest::OnWebViewMediaPermissionResponse,
-                               base::Unretained(this),
-                               request,
-                               callback),
-                    false /* allowed_by_default */);
+  web_view_permission_helper_->RequestMediaAccessPermission(source,
+                                                            request,
+                                                            callback);
 }
 
 void WebViewGuest::CanDownload(
@@ -1157,46 +908,27 @@ void WebViewGuest::CanDownload(
     const GURL& url,
     const std::string& request_method,
     const base::Callback<void(bool)>& callback) {
-  base::DictionaryValue request_info;
-  request_info.Set(
-      guestview::kUrl,
-      base::Value::CreateStringValue(url.spec()));
-  RequestPermission(
-      WEB_VIEW_PERMISSION_TYPE_DOWNLOAD,
-      request_info,
-      base::Bind(&WebViewGuest::OnWebViewDownloadPermissionResponse,
-                 base::Unretained(this),
-                 callback),
-      false /* allowed_by_default */);
+  web_view_permission_helper_->CanDownload(render_view_host,
+                                           url,
+                                           request_method,
+                                           callback);
 }
 
 void WebViewGuest::RequestPointerLockPermission(
     bool user_gesture,
     bool last_unlocked_by_target,
     const base::Callback<void(bool)>& callback) {
-  base::DictionaryValue request_info;
-  request_info.Set(guestview::kUserGesture,
-                   base::Value::CreateBooleanValue(user_gesture));
-  request_info.Set(webview::kLastUnlockedBySelf,
-                   base::Value::CreateBooleanValue(last_unlocked_by_target));
-  request_info.Set(guestview::kUrl,
-                   base::Value::CreateStringValue(
-                       guest_web_contents()->GetLastCommittedURL().spec()));
-
-  RequestPermission(
-      WEB_VIEW_PERMISSION_TYPE_POINTER_LOCK,
-      request_info,
-      base::Bind(&WebViewGuest::OnWebViewPointerLockPermissionResponse,
-                 base::Unretained(this),
-                 callback),
-      false /* allowed_by_default */);
+  web_view_permission_helper_->RequestPointerLockPermission(
+      user_gesture,
+      last_unlocked_by_target,
+      callback);
 }
 
 void WebViewGuest::WillAttachToEmbedder() {
   // We must install the mapping from guests to WebViews prior to resuming
   // suspended resource loads so that the WebRequest API will catch resource
   // requests.
-  AddWebViewToExtensionRendererState();
+  PushWebViewStateToIOThread();
 }
 
 content::JavaScriptDialogManager*
@@ -1234,10 +966,8 @@ void WebViewGuest::NavigateGuest(const std::string& src) {
        !url.SchemeIs(url::kAboutScheme)) ||
       url.SchemeIs(url::kJavaScriptScheme);
   if (scheme_is_blocked || !url.is_valid()) {
-    std::string error_type(net::ErrorToString(net::ERR_ABORTED));
-    DCHECK(StartsWithASCII(error_type, "net::", true));
-    error_type.erase(0, 5);
-    LoadAbort(true /* is_top_level */, url, error_type);
+    LoadAbort(true /* is_top_level */, url,
+              net::ErrorToShortString(net::ERR_ABORTED));
     return;
   }
 
@@ -1283,65 +1013,6 @@ void WebViewGuest::InjectChromeVoxIfNeeded(
 #endif
 }
 
-int WebViewGuest::RemoveBridgeID(int bridge_id) {
-  std::map<int, int>::iterator bridge_itr =
-      bridge_id_to_request_id_map_.find(bridge_id);
-  if (bridge_itr == bridge_id_to_request_id_map_.end())
-    return webview::kInvalidPermissionRequestID;
-
-  int request_id = bridge_itr->second;
-  bridge_id_to_request_id_map_.erase(bridge_itr);
-  return request_id;
-}
-
-int WebViewGuest::RequestPermission(
-    WebViewPermissionType permission_type,
-    const base::DictionaryValue& request_info,
-    const PermissionResponseCallback& callback,
-    bool allowed_by_default) {
-  // If there are too many pending permission requests then reject this request.
-  if (pending_permission_requests_.size() >=
-      webview::kMaxOutstandingPermissionRequests) {
-    // Let the stack unwind before we deny the permission request so that
-    // objects held by the permission request are not destroyed immediately
-    // after creation. This is to allow those same objects to be accessed again
-    // in the same scope without fear of use after freeing.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&PermissionResponseCallback::Run,
-                  base::Owned(new PermissionResponseCallback(callback)),
-                  allowed_by_default,
-                  std::string()));
-    return webview::kInvalidPermissionRequestID;
-  }
-
-  int request_id = next_permission_request_id_++;
-  pending_permission_requests_[request_id] =
-      PermissionResponseInfo(callback, permission_type, allowed_by_default);
-  scoped_ptr<base::DictionaryValue> args(request_info.DeepCopy());
-  args->SetInteger(webview::kRequestId, request_id);
-  switch (permission_type) {
-    case WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW: {
-      DispatchEvent(
-          new GuestViewBase::Event(webview::kEventNewWindow, args.Pass()));
-      break;
-    }
-    case WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG: {
-      DispatchEvent(
-          new GuestViewBase::Event(webview::kEventDialog, args.Pass()));
-      break;
-    }
-    default: {
-      args->SetString(webview::kPermission,
-                      PermissionTypeToString(permission_type));
-      DispatchEvent(new GuestViewBase::Event(webview::kEventPermissionRequest,
-                                             args.Pass()));
-      break;
-    }
-  }
-  return request_id;
-}
-
 bool WebViewGuest::HandleKeyboardShortcuts(
     const content::NativeWebKeyboardEvent& event) {
   if (event.type != blink::WebInputEvent::RawKeyDown)
@@ -1382,21 +1053,26 @@ bool WebViewGuest::HandleKeyboardShortcuts(
   return false;
 }
 
-WebViewGuest::PermissionResponseInfo::PermissionResponseInfo()
-    : permission_type(WEB_VIEW_PERMISSION_TYPE_UNKNOWN),
-      allowed_by_default(false) {
-}
+void WebViewGuest::SetUpAutoSize() {
+  // Read the autosize parameters passed in from the embedder.
+  bool auto_size_enabled = false;
+  extra_params()->GetBoolean(webview::kAttributeAutoSize, &auto_size_enabled);
 
-WebViewGuest::PermissionResponseInfo::PermissionResponseInfo(
-    const PermissionResponseCallback& callback,
-    WebViewPermissionType permission_type,
-    bool allowed_by_default)
-    : callback(callback),
-      permission_type(permission_type),
-      allowed_by_default(allowed_by_default) {
-}
+  int max_height = 0;
+  int max_width = 0;
+  extra_params()->GetInteger(webview::kAttributeMaxHeight, &max_height);
+  extra_params()->GetInteger(webview::kAttributeMaxWidth, &max_width);
+
+  int min_height = 0;
+  int min_width = 0;
+  extra_params()->GetInteger(webview::kAttributeMinHeight, &min_height);
+  extra_params()->GetInteger(webview::kAttributeMinWidth, &min_width);
 
-WebViewGuest::PermissionResponseInfo::~PermissionResponseInfo() {
+  // Call SetAutoSize to apply all the appropriate validation and clipping of
+  // values.
+  SetAutoSize(auto_size_enabled,
+              gfx::Size(min_width, min_height),
+              gfx::Size(max_width, max_height));
 }
 
 void WebViewGuest::ShowContextMenu(int request_id,
@@ -1425,13 +1101,16 @@ void WebViewGuest::SetName(const std::string& name) {
 }
 
 void WebViewGuest::SetZoom(double zoom_factor) {
+  ZoomController* zoom_controller =
+      ZoomController::FromWebContents(guest_web_contents());
+  DCHECK(zoom_controller);
   double zoom_level = content::ZoomFactorToZoomLevel(zoom_factor);
-  content::HostZoomMap::SetZoomLevel(guest_web_contents(), zoom_level);
+  zoom_controller->SetZoomLevel(zoom_level);
 
   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
   args->SetDouble(webview::kOldZoomFactor, current_zoom_factor_);
   args->SetDouble(webview::kNewZoomFactor, zoom_factor);
-  DispatchEvent(
+  DispatchEventToEmbedder(
       new GuestViewBase::Event(webview::kEventZoomChange, args.Pass()));
 
   current_zoom_factor_ = zoom_factor;
@@ -1477,7 +1156,8 @@ content::WebContents* WebViewGuest::OpenURLFromTab(
     return source;
   }
 
-  return CreateNewGuestWindow(params)->guest_web_contents();
+  CreateNewGuestWebViewWindow(params);
+  return NULL;
 }
 
 void WebViewGuest::WebContentsCreated(WebContents* source_contents,
@@ -1527,30 +1207,27 @@ void WebViewGuest::RequestNewWindowPermission(
   std::string storage_partition_id = GetStoragePartitionIdFromSiteURL(site_url);
 
   base::DictionaryValue request_info;
-  request_info.Set(webview::kInitialHeight,
-                   base::Value::CreateIntegerValue(initial_bounds.height()));
-  request_info.Set(webview::kInitialWidth,
-                   base::Value::CreateIntegerValue(initial_bounds.width()));
+  request_info.SetInteger(webview::kInitialHeight, initial_bounds.height());
+  request_info.SetInteger(webview::kInitialWidth, initial_bounds.width());
   request_info.Set(webview::kTargetURL,
-                   base::Value::CreateStringValue(new_window_info.url.spec()));
-  request_info.Set(webview::kName,
-                   base::Value::CreateStringValue(new_window_info.name));
-  request_info.Set(webview::kWindowID,
-                   base::Value::CreateIntegerValue(guest->guest_instance_id()));
+                   new base::StringValue(new_window_info.url.spec()));
+  request_info.Set(webview::kName, new base::StringValue(new_window_info.name));
+  request_info.SetInteger(webview::kWindowID, guest->GetGuestInstanceID());
   // We pass in partition info so that window-s created through newwindow
   // API can use it to set their partition attribute.
   request_info.Set(webview::kStoragePartitionId,
-                   base::Value::CreateStringValue(storage_partition_id));
-  request_info.Set(webview::kWindowOpenDisposition,
-                   base::Value::CreateStringValue(
-                       WindowOpenDispositionToString(disposition)));
+                   new base::StringValue(storage_partition_id));
+  request_info.Set(
+      webview::kWindowOpenDisposition,
+      new base::StringValue(WindowOpenDispositionToString(disposition)));
 
-  RequestPermission(WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW,
-                    request_info,
-                    base::Bind(&WebViewGuest::OnWebViewNewWindowResponse,
-                               base::Unretained(this),
-                               guest->guest_instance_id()),
-                               false /* allowed_by_default */);
+  web_view_permission_helper_->
+      RequestPermission(WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW,
+                        request_info,
+                        base::Bind(&WebViewGuest::OnWebViewNewWindowResponse,
+                                   base::Unretained(this),
+                                   guest->GetGuestInstanceID()),
+                                   false /* allowed_by_default */);
 }
 
 void WebViewGuest::DestroyUnattachedWindows() {
@@ -1575,7 +1252,7 @@ GURL WebViewGuest::ResolveURL(const std::string& src) {
   }
 
   GURL default_url(base::StringPrintf("%s://%s/",
-                                      extensions::kExtensionScheme,
+                                      kExtensionScheme,
                                       embedder_extension_id().c_str()));
   return default_url.Resolve(src);
 }
@@ -1592,3 +1269,11 @@ void WebViewGuest::OnWebViewNewWindowResponse(
   if (!allow)
     guest->Destroy();
 }
+
+void WebViewGuest::OnZoomChanged(
+    const ZoomController::ZoomChangedEventData& data) {
+  ZoomController::FromWebContents(guest_web_contents())->
+      SetZoomLevel(data.new_zoom_level);
+}
+
+}  // namespace extensions