Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/browser_plugin/browser_plugin_embedder.h" | 5 #include "content/browser/browser_plugin/browser_plugin_embedder.h" |
| 6 | 6 |
| 7 #include "base/stl_util.h" | 7 #include "base/stl_util.h" |
| 8 #include "content/browser/browser_plugin/browser_plugin_guest.h" | 8 #include "content/browser/browser_plugin/browser_plugin_guest.h" |
| 9 #include "content/browser/browser_plugin/browser_plugin_host_factory.h" | 9 #include "content/browser/browser_plugin/browser_plugin_host_factory.h" |
| 10 #include "content/browser/renderer_host/render_view_host_impl.h" | 10 #include "content/browser/renderer_host/render_view_host_impl.h" |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 BrowserPluginEmbedder* BrowserPluginEmbedder::Create( | 47 BrowserPluginEmbedder* BrowserPluginEmbedder::Create( |
| 48 WebContentsImpl* web_contents, | 48 WebContentsImpl* web_contents, |
| 49 content::RenderViewHost* render_view_host) { | 49 content::RenderViewHost* render_view_host) { |
| 50 if (factory_) { | 50 if (factory_) { |
| 51 return factory_->CreateBrowserPluginEmbedder(web_contents, | 51 return factory_->CreateBrowserPluginEmbedder(web_contents, |
| 52 render_view_host); | 52 render_view_host); |
| 53 } | 53 } |
| 54 return new BrowserPluginEmbedder(web_contents, render_view_host); | 54 return new BrowserPluginEmbedder(web_contents, render_view_host); |
| 55 } | 55 } |
| 56 | 56 |
| 57 void BrowserPluginEmbedder::CreateGuest( | |
| 58 int instance_id, | |
| 59 int routing_id, | |
| 60 BrowserPluginGuest* guest_opener, | |
| 61 const BrowserPluginHostMsg_CreateGuest_Params& params) { | |
| 62 WebContentsImpl* guest_web_contents = NULL; | |
| 63 BrowserPluginGuest* guest = GetGuestByInstanceID(instance_id); | |
| 64 CHECK(!guest); | |
| 65 | |
| 66 // Validate that the partition id coming from the renderer is valid UTF-8, | |
| 67 // since we depend on this in other parts of the code, such as FilePath | |
| 68 // creation. If the validation fails, treat it as a bad message and kill the | |
| 69 // renderer process. | |
| 70 if (!IsStringUTF8(params.storage_partition_id)) { | |
| 71 content::RecordAction(UserMetricsAction("BadMessageTerminate_BPE")); | |
| 72 base::KillProcess(render_view_host_->GetProcess()->GetHandle(), | |
| 73 content::RESULT_CODE_KILLED_BAD_MESSAGE, false); | |
| 74 return; | |
| 75 } | |
| 76 | |
| 77 const std::string& host = | |
| 78 render_view_host_->GetSiteInstance()->GetSiteURL().host(); | |
| 79 std::string url_encoded_partition = net::EscapeQueryParamValue( | |
| 80 params.storage_partition_id, false); | |
| 81 | |
| 82 SiteInstance* guest_site_instance = NULL; | |
| 83 if (guest_opener) { | |
| 84 guest_site_instance = guest_opener->GetWebContents()->GetSiteInstance(); | |
|
Charlie Reis
2013/01/04 18:53:19
Yep, this looks right. This will ensure the new g
Fady Samuel
2013/01/08 17:00:49
OK
| |
| 85 } else { | |
| 86 // The SiteInstance of a given webview tag is based on the fact that it's a | |
| 87 // guest process in addition to which platform application the tag belongs | |
| 88 // to and what storage partition is in use, rather than the URL that the tag | |
| 89 // is being navigated to. | |
| 90 GURL guest_site( | |
| 91 base::StringPrintf("%s://%s/%s?%s", chrome::kGuestScheme, | |
| 92 host.c_str(), params.persist_storage ? "persist" : "", | |
| 93 url_encoded_partition.c_str())); | |
| 94 | |
| 95 // If we already have a webview tag in the same app using the same storage | |
| 96 // partition, we should use the same SiteInstance so the existing tag and | |
| 97 // the new tag can script each other. | |
| 98 for (ContainerInstanceMap::const_iterator it = | |
| 99 guest_web_contents_by_instance_id_.begin(); | |
| 100 it != guest_web_contents_by_instance_id_.end(); ++it) { | |
| 101 if (it->second->GetSiteInstance()->GetSiteURL() == guest_site) { | |
| 102 guest_site_instance = it->second->GetSiteInstance(); | |
| 103 break; | |
| 104 } | |
| 105 } | |
| 106 if (!guest_site_instance) { | |
| 107 // Create the SiteInstance in a new BrowsingInstance, which will ensure | |
| 108 // that webview tags are also not allowed to send messages across | |
| 109 // different partitions. | |
| 110 guest_site_instance = SiteInstance::CreateForURL( | |
| 111 web_contents()->GetBrowserContext(), guest_site); | |
| 112 } | |
| 113 } | |
| 114 WebContentsImpl* base_web_contents = static_cast<WebContentsImpl*>( | |
|
Charlie Reis
2013/01/04 18:53:19
What does base mean? Might be clearer to call thi
Fady Samuel
2013/01/08 17:00:49
Done.
| |
| 115 guest_opener ? guest_opener->GetWebContents() : NULL); | |
| 116 guest_web_contents = WebContentsImpl::CreateGuest( | |
| 117 web_contents()->GetBrowserContext(), | |
|
sadrul
2013/01/07 15:09:54
Should you be using the browser-context of opener_
Fady Samuel
2013/01/08 17:00:49
This is the embedder's BrowserContext. All guests
Charlie Reis
2013/01/08 21:13:52
The BrowserContext is the part of Profile that liv
| |
| 118 guest_site_instance, | |
| 119 routing_id, | |
| 120 base_web_contents, | |
| 121 instance_id, | |
| 122 params); | |
| 123 | |
| 124 guest = guest_web_contents->GetBrowserPluginGuest(); | |
| 125 guest->set_embedder_web_contents( | |
| 126 static_cast<WebContentsImpl*>(web_contents())); | |
| 127 | |
| 128 RendererPreferences* guest_renderer_prefs = | |
| 129 guest_web_contents->GetMutableRendererPrefs(); | |
| 130 // Copy renderer preferences (and nothing else) from the embedder's | |
| 131 // TabContents to the guest. | |
| 132 // | |
| 133 // For GTK and Aura this is necessary to get proper renderer configuration | |
| 134 // values for caret blinking interval, colors related to selection and | |
| 135 // focus. | |
| 136 *guest_renderer_prefs = *web_contents()->GetMutableRendererPrefs(); | |
| 137 | |
| 138 guest_renderer_prefs->throttle_input_events = false; | |
| 139 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated | |
| 140 // navigations still continue to function inside the app. | |
| 141 guest_renderer_prefs->browser_handles_all_top_level_requests = false; | |
| 142 AddGuest(instance_id, guest_web_contents); | |
| 143 guest_web_contents->SetDelegate(guest); | |
| 144 | |
| 145 // Create a swapped out RenderView for the guest in the embedder render | |
| 146 // process, so that the embedder can access the guest's window object. | |
| 147 int guest_routing_id = | |
| 148 static_cast<WebContentsImpl*>(guest->GetWebContents())-> | |
| 149 CreateSwappedOutRenderView(web_contents()->GetSiteInstance()); | |
| 150 render_view_host_->Send(new BrowserPluginMsg_GuestContentWindowReady( | |
| 151 render_view_host_->GetRoutingID(), instance_id, guest_routing_id)); | |
| 152 | |
| 153 // If this guest was created by another guest, then don't initialize it yet as | |
| 154 // it has not yet necessarily been attached to a BrowserPlugin. | |
|
Charlie Reis
2013/01/04 18:53:19
The comment makes it sound like we should be check
Fady Samuel
2013/01/08 17:00:49
This is a bad comment. Thanks for catching this! A
| |
| 155 guest->Initialize(params, guest_web_contents->GetRenderViewHost()); | |
| 156 } | |
| 157 | |
| 158 BrowserPluginGuest* BrowserPluginEmbedder::GetGuestByInstanceID( | |
| 159 int instance_id) const { | |
| 160 ContainerInstanceMap::const_iterator it = | |
| 161 guest_web_contents_by_instance_id_.find(instance_id); | |
| 162 if (it != guest_web_contents_by_instance_id_.end()) | |
| 163 return static_cast<WebContentsImpl*>(it->second)->GetBrowserPluginGuest(); | |
| 164 return NULL; | |
| 165 } | |
| 166 | |
| 167 void BrowserPluginEmbedder::DestroyGuestByInstanceID(int instance_id) { | |
| 168 BrowserPluginGuest* guest = GetGuestByInstanceID(instance_id); | |
| 169 if (guest) { | |
| 170 WebContents* guest_web_contents = guest->GetWebContents(); | |
| 171 | |
| 172 // Destroy the guest's web_contents. | |
| 173 delete guest_web_contents; | |
| 174 guest_web_contents_by_instance_id_.erase(instance_id); | |
| 175 } | |
| 176 } | |
| 177 | |
| 57 void BrowserPluginEmbedder::GetRenderViewHostAtPosition( | 178 void BrowserPluginEmbedder::GetRenderViewHostAtPosition( |
| 58 int x, int y, const WebContents::GetRenderViewHostCallback& callback) { | 179 int x, int y, const WebContents::GetRenderViewHostCallback& callback) { |
| 59 // Store the callback so we can call it later when we have the response. | 180 // Store the callback so we can call it later when we have the response. |
| 60 pending_get_render_view_callbacks_.insert( | 181 pending_get_render_view_callbacks_.insert( |
| 61 std::make_pair(next_get_render_view_request_id_, callback)); | 182 std::make_pair(next_get_render_view_request_id_, callback)); |
| 62 render_view_host_->Send( | 183 render_view_host_->Send( |
| 63 new BrowserPluginMsg_PluginAtPositionRequest( | 184 new BrowserPluginMsg_PluginAtPositionRequest( |
| 64 render_view_host_->GetRoutingID(), | 185 render_view_host_->GetRoutingID(), |
| 65 next_get_render_view_request_id_, | 186 next_get_render_view_request_id_, |
| 66 gfx::Point(x, y))); | 187 gfx::Point(x, y))); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 case NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED: { | 231 case NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED: { |
| 111 bool visible = *Details<bool>(details).ptr(); | 232 bool visible = *Details<bool>(details).ptr(); |
| 112 WebContentsVisibilityChanged(visible); | 233 WebContentsVisibilityChanged(visible); |
| 113 break; | 234 break; |
| 114 } | 235 } |
| 115 default: | 236 default: |
| 116 NOTREACHED() << "Unexpected notification type: " << type; | 237 NOTREACHED() << "Unexpected notification type: " << type; |
| 117 } | 238 } |
| 118 } | 239 } |
| 119 | 240 |
| 120 BrowserPluginGuest* BrowserPluginEmbedder::GetGuestByInstanceID( | |
| 121 int instance_id) const { | |
| 122 ContainerInstanceMap::const_iterator it = | |
| 123 guest_web_contents_by_instance_id_.find(instance_id); | |
| 124 if (it != guest_web_contents_by_instance_id_.end()) | |
| 125 return static_cast<WebContentsImpl*>(it->second)->GetBrowserPluginGuest(); | |
| 126 return NULL; | |
| 127 } | |
| 128 | |
| 129 void BrowserPluginEmbedder::AddGuest(int instance_id, | 241 void BrowserPluginEmbedder::AddGuest(int instance_id, |
| 130 WebContents* guest_web_contents) { | 242 WebContents* guest_web_contents) { |
| 131 DCHECK(guest_web_contents_by_instance_id_.find(instance_id) == | 243 DCHECK(guest_web_contents_by_instance_id_.find(instance_id) == |
| 132 guest_web_contents_by_instance_id_.end()); | 244 guest_web_contents_by_instance_id_.end()); |
| 133 guest_web_contents_by_instance_id_[instance_id] = guest_web_contents; | 245 guest_web_contents_by_instance_id_[instance_id] = guest_web_contents; |
| 134 } | 246 } |
| 135 | 247 |
| 136 void BrowserPluginEmbedder::DestroyGuestByInstanceID(int instance_id) { | |
| 137 BrowserPluginGuest* guest = GetGuestByInstanceID(instance_id); | |
| 138 if (guest) { | |
| 139 WebContents* guest_web_contents = guest->GetWebContents(); | |
| 140 | |
| 141 // Destroy the guest's web_contents. | |
| 142 delete guest_web_contents; | |
| 143 guest_web_contents_by_instance_id_.erase(instance_id); | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 void BrowserPluginEmbedder::CleanUp() { | 248 void BrowserPluginEmbedder::CleanUp() { |
| 148 // Destroy guests that are managed by the current embedder. | 249 // Destroy guests that are managed by the current embedder. |
| 149 STLDeleteContainerPairSecondPointers( | 250 STLDeleteContainerPairSecondPointers( |
| 150 guest_web_contents_by_instance_id_.begin(), | 251 guest_web_contents_by_instance_id_.begin(), |
| 151 guest_web_contents_by_instance_id_.end()); | 252 guest_web_contents_by_instance_id_.end()); |
| 152 guest_web_contents_by_instance_id_.clear(); | 253 guest_web_contents_by_instance_id_.clear(); |
| 153 | 254 |
| 154 // CleanUp gets called when BrowserPluginEmbedder's WebContents goes away | 255 // CleanUp gets called when BrowserPluginEmbedder's WebContents goes away |
| 155 // or the associated RenderViewHost is destroyed or swapped out. Therefore we | 256 // or the associated RenderViewHost is destroyed or swapped out. Therefore we |
| 156 // don't need to care about the pending callbacks anymore. | 257 // don't need to care about the pending callbacks anymore. |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 187 return true; | 288 return true; |
| 188 default: | 289 default: |
| 189 break; | 290 break; |
| 190 } | 291 } |
| 191 return false; | 292 return false; |
| 192 } | 293 } |
| 193 | 294 |
| 194 void BrowserPluginEmbedder::OnCreateGuest( | 295 void BrowserPluginEmbedder::OnCreateGuest( |
| 195 int instance_id, | 296 int instance_id, |
| 196 const BrowserPluginHostMsg_CreateGuest_Params& params) { | 297 const BrowserPluginHostMsg_CreateGuest_Params& params) { |
| 197 WebContentsImpl* guest_web_contents = NULL; | 298 CreateGuest(instance_id, MSG_ROUTING_NONE, NULL, params); |
| 198 BrowserPluginGuest* guest = GetGuestByInstanceID(instance_id); | |
| 199 CHECK(!guest); | |
| 200 | |
| 201 // Validate that the partition id coming from the renderer is valid UTF-8, | |
| 202 // since we depend on this in other parts of the code, such as FilePath | |
| 203 // creation. If the validation fails, treat it as a bad message and kill the | |
| 204 // renderer process. | |
| 205 if (!IsStringUTF8(params.storage_partition_id)) { | |
| 206 content::RecordAction(UserMetricsAction("BadMessageTerminate_BPE")); | |
| 207 base::KillProcess(render_view_host_->GetProcess()->GetHandle(), | |
| 208 content::RESULT_CODE_KILLED_BAD_MESSAGE, false); | |
| 209 return; | |
| 210 } | |
| 211 | |
| 212 const std::string& host = | |
| 213 render_view_host_->GetSiteInstance()->GetSiteURL().host(); | |
| 214 std::string url_encoded_partition = net::EscapeQueryParamValue( | |
| 215 params.storage_partition_id, false); | |
| 216 | |
| 217 // The SiteInstance of a given webview tag is based on the fact that it's a | |
| 218 // guest process in addition to which platform application the tag belongs to | |
| 219 // and what storage partition is in use, rather than the URL that the tag is | |
| 220 // being navigated to. | |
| 221 GURL guest_site( | |
| 222 base::StringPrintf("%s://%s/%s?%s", chrome::kGuestScheme, | |
| 223 host.c_str(), params.persist_storage ? "persist" : "", | |
| 224 url_encoded_partition.c_str())); | |
| 225 | |
| 226 // If we already have a webview tag in the same app using the same storage | |
| 227 // partition, we should use the same SiteInstance so the existing tag and | |
| 228 // the new tag can script each other. | |
| 229 SiteInstance* guest_site_instance = NULL; | |
| 230 for (ContainerInstanceMap::const_iterator it = | |
| 231 guest_web_contents_by_instance_id_.begin(); | |
| 232 it != guest_web_contents_by_instance_id_.end(); ++it) { | |
| 233 if (it->second->GetSiteInstance()->GetSiteURL() == guest_site) { | |
| 234 guest_site_instance = it->second->GetSiteInstance(); | |
| 235 break; | |
| 236 } | |
| 237 } | |
| 238 if (!guest_site_instance) { | |
| 239 // Create the SiteInstance in a new BrowsingInstance, which will ensure that | |
| 240 // webview tags are also not allowed to send messages across different | |
| 241 // partitions. | |
| 242 guest_site_instance = SiteInstance::CreateForURL( | |
| 243 web_contents()->GetBrowserContext(), guest_site); | |
| 244 } | |
| 245 | |
| 246 guest_web_contents = WebContentsImpl::CreateGuest( | |
| 247 web_contents()->GetBrowserContext(), | |
| 248 guest_site_instance, | |
| 249 instance_id, | |
| 250 params); | |
| 251 | |
| 252 guest = guest_web_contents->GetBrowserPluginGuest(); | |
| 253 guest->set_embedder_web_contents( | |
| 254 static_cast<WebContentsImpl*>(web_contents())); | |
| 255 | |
| 256 RendererPreferences* guest_renderer_prefs = | |
| 257 guest_web_contents->GetMutableRendererPrefs(); | |
| 258 // Copy renderer preferences (and nothing else) from the embedder's | |
| 259 // TabContents to the guest. | |
| 260 // | |
| 261 // For GTK and Aura this is necessary to get proper renderer configuration | |
| 262 // values for caret blinking interval, colors related to selection and | |
| 263 // focus. | |
| 264 *guest_renderer_prefs = *web_contents()->GetMutableRendererPrefs(); | |
| 265 | |
| 266 guest_renderer_prefs->throttle_input_events = false; | |
| 267 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated | |
| 268 // navigations still continue to function inside the app. | |
| 269 guest_renderer_prefs->browser_handles_all_top_level_requests = false; | |
| 270 AddGuest(instance_id, guest_web_contents); | |
| 271 guest_web_contents->SetDelegate(guest); | |
| 272 | |
| 273 // Create a swapped out RenderView for the guest in the embedder render | |
| 274 // process, so that the embedder can access the guest's window object. | |
| 275 int guest_routing_id = | |
| 276 static_cast<WebContentsImpl*>(guest->GetWebContents())-> | |
| 277 CreateSwappedOutRenderView(web_contents()->GetSiteInstance()); | |
| 278 render_view_host_->Send(new BrowserPluginMsg_GuestContentWindowReady( | |
| 279 render_view_host_->GetRoutingID(), instance_id, guest_routing_id)); | |
| 280 | |
| 281 guest->Initialize(params, guest_web_contents->GetRenderViewHost()); | |
| 282 } | 299 } |
| 283 | 300 |
| 284 void BrowserPluginEmbedder::OnNavigateGuest( | 301 void BrowserPluginEmbedder::OnNavigateGuest( |
| 285 int instance_id, | 302 int instance_id, |
| 286 const std::string& src) { | 303 const std::string& src) { |
| 287 BrowserPluginGuest* guest = GetGuestByInstanceID(instance_id); | 304 BrowserPluginGuest* guest = GetGuestByInstanceID(instance_id); |
| 288 CHECK(guest); | 305 CHECK(guest); |
| 289 GURL url(src); | 306 GURL url(src); |
| 290 WebContentsImpl* guest_web_contents = | 307 WebContentsImpl* guest_web_contents = |
| 291 static_cast<WebContentsImpl*>(guest->GetWebContents()); | 308 static_cast<WebContentsImpl*>(guest->GetWebContents()); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 335 uint32 sync_point) { | 352 uint32 sync_point) { |
| 336 AcceleratedSurfaceMsg_BufferPresented_Params ack_params; | 353 AcceleratedSurfaceMsg_BufferPresented_Params ack_params; |
| 337 ack_params.mailbox_name = mailbox_name; | 354 ack_params.mailbox_name = mailbox_name; |
| 338 ack_params.sync_point = sync_point; | 355 ack_params.sync_point = sync_point; |
| 339 RenderWidgetHostImpl::AcknowledgeBufferPresent(route_id, | 356 RenderWidgetHostImpl::AcknowledgeBufferPresent(route_id, |
| 340 gpu_host_id, | 357 gpu_host_id, |
| 341 ack_params); | 358 ack_params); |
| 342 } | 359 } |
| 343 | 360 |
| 344 } // namespace content | 361 } // namespace content |
| OLD | NEW |