OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/browser_plugin/browser_plugin_host.h" | |
6 | |
7 #include "content/browser/renderer_host/render_view_host_impl.h" | |
8 #include "content/browser/web_contents/web_contents_impl.h" | |
9 #include "content/common/browser_plugin_messages.h" | |
10 #include "content/public/browser/notification_details.h" | |
11 #include "content/public/browser/notification_source.h" | |
12 #include "content/public/browser/notification_types.h" | |
13 #include "content/public/browser/render_process_host.h" | |
14 #include "content/public/browser/render_widget_host_view.h" | |
15 #include "content/public/browser/site_instance.h" | |
16 #include "content/public/browser/web_contents_view.h" | |
17 #include "ppapi/proxy/ppapi_messages.h" | |
18 | |
19 namespace content { | |
20 | |
21 BrowserPluginHost::BrowserPluginHost( | |
22 WebContentsImpl* web_contents) | |
23 : WebContentsObserver(web_contents), | |
24 embedder_(NULL), | |
25 instance_id_(0), | |
26 pending_render_view_host_(NULL) { | |
27 // Listen to visibility changes so that an embedder hides its guests | |
28 // as well. | |
29 registrar_.Add(this, | |
30 NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, | |
31 Source<RenderViewHost>( | |
32 web_contents->GetRenderViewHost())); | |
Charlie Reis
2012/05/18 20:35:24
Just want to sanity check that we know this is the
Fady Samuel
2012/05/21 14:30:17
Using the new NOTIFICATION_WEB_CONTENTS_VISIBLITY_
| |
33 } | |
34 | |
35 BrowserPluginHost::~BrowserPluginHost() { | |
36 } | |
37 | |
38 BrowserPluginHost* BrowserPluginHost::GetGuestByContainerID(int container_id) { | |
39 ContainerInstanceMap::const_iterator it = | |
40 guests_by_container_id_.find(container_id); | |
41 if (it != guests_by_container_id_.end()) | |
42 return it->second; | |
43 return NULL; | |
44 } | |
45 | |
46 void BrowserPluginHost::RegisterContainerInstance( | |
47 int container_id, | |
48 BrowserPluginHost* observer) { | |
49 DCHECK(guests_by_container_id_.find(container_id) == | |
50 guests_by_container_id_.end()); | |
51 guests_by_container_id_[container_id] = observer; | |
52 } | |
53 | |
54 void BrowserPluginHost::OnCrossProcessNavigation(RenderViewHost* dest_rvh) { | |
55 if (web_contents()->GetRenderViewHost() != dest_rvh) { | |
56 pending_render_view_host_ = dest_rvh; | |
57 } | |
58 } | |
59 | |
60 | |
61 bool BrowserPluginHost::OnMessageReceived(const IPC::Message& message) { | |
62 bool handled = true; | |
63 IPC_BEGIN_MESSAGE_MAP(BrowserPluginHost, message) | |
64 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ConnectToChannel, | |
65 OnConnectToChannel) | |
66 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_NavigateFromGuest, | |
67 OnNavigateFromGuest) | |
68 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_MapInstance, | |
69 OnMapInstance) | |
70 IPC_MESSAGE_UNHANDLED(handled = false) | |
71 IPC_END_MESSAGE_MAP() | |
72 return handled; | |
73 } | |
74 | |
75 void BrowserPluginHost::NavigateGuestFromEmbedder( | |
76 RenderViewHost* render_view_host, | |
77 int container_instance_id, | |
78 long long frame_id, | |
79 const std::string& src, | |
80 const gfx::Size& size) { | |
81 BrowserPluginHost* guest_observer = | |
82 GetGuestByContainerID(container_instance_id); | |
83 WebContentsImpl* guest_web_contents = | |
84 guest_observer ? | |
85 static_cast<WebContentsImpl*>(guest_observer->web_contents()): NULL; | |
86 if (!guest_observer) { | |
87 GURL url(src); | |
88 guest_web_contents = | |
89 static_cast<WebContentsImpl*>( | |
90 WebContents::Create( | |
91 web_contents()->GetBrowserContext(), | |
92 render_view_host->GetSiteInstance(), | |
93 MSG_ROUTING_NONE, | |
94 NULL, // base WebContents | |
95 NULL // session storage namespace | |
96 )); | |
97 guest_observer = | |
98 guest_web_contents->browser_plugin_host(); | |
99 guest_observer->set_embedder(static_cast<WebContentsImpl*>(web_contents())); | |
100 guest_observer->set_instance_id(container_instance_id); | |
101 guest_observer->set_url(url); | |
Charlie Reis
2012/05/18 20:35:24
Does the observer need to know the url? The fewer
Fady Samuel
2012/05/21 14:30:17
Done. Initial size will go away in a subsequent pa
| |
102 guest_observer->set_initial_size(size); | |
103 RegisterContainerInstance(container_instance_id, guest_observer); | |
104 AddGuest(guest_web_contents, frame_id); | |
105 } | |
106 | |
107 guest_observer->web_contents()->SetDelegate(guest_observer); | |
108 guest_observer->web_contents()->GetController().LoadURL( | |
109 guest_observer->url(), | |
110 Referrer(), | |
111 PAGE_TRANSITION_AUTO_SUBFRAME, | |
112 std::string()); | |
113 } | |
114 | |
115 void BrowserPluginHost::OnNavigateFromGuest( | |
116 PP_Instance instance, | |
117 const std::string& src) { | |
118 DCHECK(embedder()); | |
119 GURL url(src); | |
120 web_contents()->GetController().LoadURL( | |
121 url, | |
122 Referrer(), | |
123 PAGE_TRANSITION_AUTO_SUBFRAME, | |
124 std::string()); | |
125 } | |
126 | |
127 // TODO(fsamuel): This handler is all kinds of bad and could be racy. | |
Charlie Reis
2012/05/18 20:35:24
Please add more of an explanation why this is racy
Fady Samuel
2012/05/21 14:30:17
I don't think that's the issue. The problem here i
| |
128 // The correct solution is probably to send | |
129 // "BrowserPluginMsg_CompleteNavigation" over the pepper channel to the guest | |
130 // and then have the guest send the browser "BrowserPluginHostMsg_ResizeGuest" | |
131 // to resize appropriately. | |
132 void BrowserPluginHost::OnMapInstance(int container_instance_id, | |
133 PP_Instance instance) { | |
134 BrowserPluginHost* guest_observer = | |
135 GetGuestByContainerID(container_instance_id); | |
136 WebContentsImpl* guest_web_contents = | |
137 static_cast<WebContentsImpl*>(guest_observer->web_contents()); | |
138 RenderViewHost* rvh = guest_observer->pending_render_view_host() ? | |
139 guest_observer->pending_render_view_host() : | |
140 guest_web_contents->GetRenderViewHost(); | |
141 | |
142 guest_web_contents->GetView()->SizeContents(guest_observer->initial_size()); | |
143 | |
144 rvh->Send(new BrowserPluginMsg_CompleteNavigation( | |
145 rvh->GetRoutingID(), | |
146 instance)); | |
147 } | |
148 | |
149 void BrowserPluginHost::OnConnectToChannel( | |
150 const IPC::ChannelHandle& channel_handle) { | |
151 DCHECK(embedder()); | |
152 // Tell the BrowserPlugin in the embedder that we're done and that it can | |
153 // begin using the guest renderer. | |
154 embedder()->GetRenderProcessHost()->Send( | |
Charlie Reis
2012/05/18 20:35:24
This looks unsafe as well, as does the GetPendingS
Fady Samuel
2012/05/21 14:30:17
Yes, the guest BrowserPluginHost can keep track of
| |
155 new BrowserPluginMsg_LoadGuest( | |
156 instance_id(), | |
157 //embedder_web_contents->GetRenderProcessHost()->GetID(), | |
Charlie Reis
2012/05/18 20:35:24
Remove commented code.
Fady Samuel
2012/05/21 14:30:17
Done.
| |
158 web_contents()->GetPendingSiteInstance()->GetProcess()-> | |
159 GetID(), | |
160 channel_handle)); | |
161 } | |
162 | |
163 void BrowserPluginHost::AddGuest(WebContentsImpl* guest, int64 frame_id) { | |
164 guests_[guest] = frame_id; | |
165 } | |
166 | |
167 void BrowserPluginHost::RemoveGuest(WebContentsImpl* guest) { | |
168 guests_.erase(guest); | |
169 } | |
170 | |
171 void BrowserPluginHost::DestroyGuests() { | |
172 for (GuestMap::const_iterator it = guests_.begin(); | |
173 it != guests_.end(); ++it) { | |
174 WebContentsImpl* web_contents = it->first; | |
175 delete web_contents; | |
176 } | |
177 guests_.clear(); | |
178 guests_by_container_id_.clear(); | |
179 } | |
180 | |
181 void BrowserPluginHost::DidCommitProvisionalLoadForFrame( | |
182 int64 frame_id, | |
183 bool is_main_frame, | |
184 const GURL& url, | |
185 PageTransition transition_type, | |
186 RenderViewHost* render_view_host) { | |
187 // Clean-up guests that lie in the frame that we're navigating. | |
188 typedef std::set<WebContentsImpl*> GuestSet; | |
189 GuestSet guests_to_delete; | |
190 for (GuestMap::const_iterator it = guests_.begin(); | |
191 it != guests_.end(); ++it) { | |
192 WebContentsImpl* web_contents = it->first; | |
193 if (it->second == frame_id) { | |
194 guests_to_delete.insert(web_contents); | |
195 } | |
196 } | |
197 for (GuestSet::const_iterator it = guests_to_delete.begin(); | |
198 it != guests_to_delete.end(); ++it) { | |
199 delete *it; | |
200 guests_.erase(*it); | |
201 } | |
202 } | |
203 | |
204 void BrowserPluginHost::RenderViewDeleted(RenderViewHost* render_view_host) { | |
205 // TODO(fsamuel): For some reason ToT hangs when killing a guest, this wasn't | |
206 // the case earlier. Presumably, when a guest is killed/crashes, one of | |
207 // RenderViewDeleted, RenderViewGone or WebContentsDestroyed will get called. | |
208 // At that point, we should remove reference to this BrowserPluginHost | |
209 // from its embedder, in addition to destroying its guests, to ensure | |
210 // that we do not attempt a double delete. | |
211 DestroyGuests(); | |
212 } | |
213 | |
214 void BrowserPluginHost::RenderViewGone(base::TerminationStatus status) { | |
215 DestroyGuests(); | |
216 } | |
217 | |
218 void BrowserPluginHost::WebContentsDestroyed(WebContents* web_contents) { | |
219 DestroyGuests(); | |
220 } | |
221 | |
222 void BrowserPluginHost::Observe( | |
223 int type, | |
224 const NotificationSource& source, | |
225 const NotificationDetails& details) { | |
226 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); | |
227 bool visible = *Details<bool>(details).ptr(); | |
228 | |
229 // If the embedder is hidden we need to hide the guests as well. | |
230 for (GuestMap::const_iterator it = guests_.begin(); | |
231 it != guests_.end(); ++it) { | |
232 WebContentsImpl* web_contents = it->first; | |
233 if (visible) | |
234 web_contents->ShowContents(); | |
235 else | |
236 web_contents->HideContents(); | |
237 } | |
238 } | |
239 | |
240 } // namespace content | |
OLD | NEW |