| Index: chrome/browser/guest_view/web_view/web_view_guest.cc
 | 
| diff --git a/chrome/browser/guest_view/web_view/web_view_guest.cc b/chrome/browser/guest_view/web_view/web_view_guest.cc
 | 
| index efda0eb5915a1aea73c84e67eb986179a8137b98..db3f0dac2473d9fb1f3d7310603910c04cf6b339 100644
 | 
| --- a/chrome/browser/guest_view/web_view/web_view_guest.cc
 | 
| +++ b/chrome/browser/guest_view/web_view/web_view_guest.cc
 | 
| @@ -184,14 +184,39 @@ void AttachWebViewHelpers(WebContents* contents) {
 | 
|    PDFTabHelper::CreateForWebContents(contents);
 | 
|  }
 | 
|  
 | 
| +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;
 | 
| +  }
 | 
| +
 | 
| +  // 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;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  }  // namespace
 | 
|  
 | 
| -WebViewGuest::WebViewGuest(int guest_instance_id,
 | 
| -                           WebContents* guest_web_contents,
 | 
| -                           const std::string& embedder_extension_id)
 | 
| +WebViewGuest::WebViewGuest(int guest_instance_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),
 | 
| @@ -199,25 +224,6 @@ WebViewGuest::WebViewGuest(int guest_instance_id,
 | 
|        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));
 | 
| -
 | 
| -  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);
 | 
|  }
 | 
|  
 | 
|  // static
 | 
| @@ -256,37 +262,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) {
 | 
| @@ -385,6 +360,63 @@ scoped_ptr<base::ListValue> WebViewGuest::MenuModelToValue(
 | 
|    return items.Pass();
 | 
|  }
 | 
|  
 | 
| +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);
 | 
| +    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() {
 | 
|    std::string name;
 | 
|    if (extra_params()->GetString(webview::kName, &name)) {
 | 
| @@ -429,6 +461,31 @@ void WebViewGuest::DidAttachToEmbedder() {
 | 
|    }
 | 
|  }
 | 
|  
 | 
| +void WebViewGuest::DidInitialize() {
 | 
| +  script_executor_.reset(new extensions::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::DidStopLoading() {
 | 
|    scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
 | 
|    DispatchEvent(new GuestViewBase::Event(webview::kEventLoadStop, args.Pass()));
 | 
| @@ -573,26 +630,25 @@ void WebViewGuest::OnUpdateFrameName(bool is_top_level,
 | 
|    ReportFrameNameChange(name);
 | 
|  }
 | 
|  
 | 
| -WebViewGuest* WebViewGuest::CreateNewGuestWindow(
 | 
| +WebViewGuest* 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);
 | 
| +  base::DictionaryValue create_params;
 | 
| +  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());
 | 
| +      guest_manager->CreateGuest(
 | 
| +          WebViewGuest::Type,
 | 
| +          embedder_extension_id(),
 | 
| +          embedder_web_contents()->GetRenderProcessHost()->GetID(),
 | 
| +          create_params);
 | 
|    WebViewGuest* new_guest =
 | 
|        WebViewGuest::FromWebContents(new_guest_web_contents);
 | 
|    new_guest->SetOpener(this);
 | 
| @@ -1124,6 +1180,17 @@ void WebViewGuest::RemoveWebViewFromExtensionRendererState(
 | 
|            web_contents->GetRoutingID()));
 | 
|  }
 | 
|  
 | 
| +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::SizeChanged(const gfx::Size& old_size,
 | 
|                                 const gfx::Size& new_size) {
 | 
|    scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
 | 
| @@ -1477,7 +1544,7 @@ content::WebContents* WebViewGuest::OpenURLFromTab(
 | 
|      return source;
 | 
|    }
 | 
|  
 | 
| -  return CreateNewGuestWindow(params)->guest_web_contents();
 | 
| +  return CreateNewGuestWebViewWindow(params)->guest_web_contents();
 | 
|  }
 | 
|  
 | 
|  void WebViewGuest::WebContentsCreated(WebContents* source_contents,
 | 
| @@ -1536,7 +1603,8 @@ void WebViewGuest::RequestNewWindowPermission(
 | 
|    request_info.Set(webview::kName,
 | 
|                     base::Value::CreateStringValue(new_window_info.name));
 | 
|    request_info.Set(webview::kWindowID,
 | 
| -                   base::Value::CreateIntegerValue(guest->guest_instance_id()));
 | 
| +                   base::Value::CreateIntegerValue(
 | 
| +                      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,
 | 
| @@ -1549,7 +1617,7 @@ void WebViewGuest::RequestNewWindowPermission(
 | 
|                      request_info,
 | 
|                      base::Bind(&WebViewGuest::OnWebViewNewWindowResponse,
 | 
|                                 base::Unretained(this),
 | 
| -                               guest->guest_instance_id()),
 | 
| +                               guest->GetGuestInstanceID()),
 | 
|                                 false /* allowed_by_default */);
 | 
|  }
 | 
|  
 | 
| 
 |