Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: content/browser/browser_plugin/browser_plugin_host.cc

Issue 10560022: Browser Plugin: New Implementation (Browser Side) (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Address some of creis@'s comments. Handing off to Istiaque as I head for vacation. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 "base/utf_string_conversions.h"
8 #include "content/browser/browser_plugin/browser_plugin_host_helper.h"
9 #include "content/browser/renderer_host/render_view_host_impl.h"
10 #include "content/browser/web_contents/web_contents_impl.h"
11 #include "content/common/browser_plugin_messages.h"
12 #include "content/common/view_messages.h"
13 #include "content/port/browser/render_widget_host_view_port.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/render_widget_host_view.h"
20 #include "content/public/browser/site_instance.h"
21 #include "content/public/browser/web_contents_view.h"
22 #include "content/public/common/result_codes.h"
23 #include "content/public/common/url_constants.h"
24
25 namespace content {
26
27 namespace {
28 const int kGuestHangTimeout = 5000;
29 }
30
31 BrowserPluginHost::BrowserPluginHost(
32 WebContentsImpl* web_contents)
33 : WebContentsObserver(web_contents),
34 embedder_render_process_host_(NULL),
35 instance_id_(0),
36 damage_buffer_(NULL),
37 pending_update_counter_(0) {
38 // Listen to visibility changes so that an embedder hides its guests
39 // as well.
40 registrar_.Add(this,
41 NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
42 Source<WebContents>(web_contents));
43 // Construct plumbing helpers when a new RenderViewHost is created for
44 // this BrowserPluginHost's WebContentsImpl.
45 registrar_.Add(this,
46 NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
47 Source<WebContents>(web_contents));
48 }
49
50 BrowserPluginHost::~BrowserPluginHost() {
51 if (damage_buffer_)
52 delete damage_buffer_;
53 }
54
55 BrowserPluginHost* BrowserPluginHost::GetGuestByInstanceID(
56 int instance_id) const {
57 ContainerInstanceMap::const_iterator it =
58 guests_by_instance_id_.find(instance_id);
59 if (it != guests_by_instance_id_.end())
60 return it->second;
61 return NULL;
62 }
63
64 void BrowserPluginHost::AddGuest(int instance_id,
65 BrowserPluginHost* guest,
66 int64 frame_id) {
67 DCHECK(guests_by_instance_id_.find(instance_id) ==
68 guests_by_instance_id_.end());
69 guests_by_instance_id_[instance_id] = guest;
70 guests_[guest->web_contents()] = frame_id;
71 }
72
73 bool BrowserPluginHost::TakeFocus(bool reverse) {
74 embedder_render_process_host()->Send(
75 new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse));
76 return true;
77 }
78
79 void BrowserPluginHost::RendererUnresponsive(WebContents* source) {
80 if (embedder_render_process_host()) {
81 base::ProcessHandle process_handle =
82 web_contents()->GetRenderProcessHost()->GetHandle();
83 base::KillProcess(process_handle, RESULT_CODE_HUNG, false);
84 }
85 }
86
87 bool BrowserPluginHost::OnMessageReceived(const IPC::Message& message) {
88 return false;
89 }
90
91 void BrowserPluginHost::NavigateGuest(
92 RenderViewHost* render_view_host,
93 int instance_id,
94 int64 frame_id,
95 const std::string& src,
96 const gfx::Size& size) {
97 BrowserPluginHost* guest = GetGuestByInstanceID(instance_id);
98 WebContentsImpl* guest_web_contents = NULL;
99 GURL url(src);
100 if (!guest) {
101 std::string host = render_view_host->GetSiteInstance()->GetSite().host();
102 GURL guest_site(
103 base::StringPrintf("%s://%s", chrome::kGuestScheme, host.c_str()));
104 // The SiteInstance of a given guest is based on the fact that it's a guest
105 // in addition to which platform application the guest belongs to, rather
106 // than the URL that the guest is being navigated to.
107 SiteInstance* guest_site_instance =
108 SiteInstance::CreateForURL(web_contents()->GetBrowserContext(),
109 guest_site);
110 guest_web_contents =
111 static_cast<WebContentsImpl*>(
112 WebContents::Create(
113 web_contents()->GetBrowserContext(),
114 guest_site_instance,
115 MSG_ROUTING_NONE,
116 NULL, // base WebContents
117 NULL // session storage namespace
118 ));
119 guest = guest_web_contents->browser_plugin_host();
120 guest->set_embedder_render_process_host(
121 render_view_host->GetProcess());
122 guest->set_instance_id(instance_id);
123 guest_web_contents->GetMutableRendererPrefs()->
124 throttle_input_events = false;
125 AddGuest(instance_id, guest, frame_id);
126 } else {
127 guest_web_contents = static_cast<WebContentsImpl*>(guest->web_contents());
128 }
129 guest->web_contents()->SetDelegate(guest);
130 guest->web_contents()->GetController().LoadURL(
131 url,
132 Referrer(),
133 PAGE_TRANSITION_AUTO_SUBFRAME,
134 std::string());
135 if (!size.IsEmpty())
136 guest_web_contents->GetView()->SizeContents(size);
137 }
138
139 void BrowserPluginHost::SetDamageBuffer(TransportDIB* damage_buffer,
140 const gfx::Size& size,
141 float scale_factor) {
142 if (damage_buffer_)
143 delete damage_buffer_;
144 damage_buffer_ = damage_buffer;
145 damage_buffer_size_ = size;
146 damage_buffer_scale_factor_ = scale_factor;
147 }
148
149 void BrowserPluginHost::ResizeGuest(int instance_id,
150 TransportDIB* damage_buffer,
151 int width, int height,
152 bool resize_pending,
153 float scale_factor) {
154 BrowserPluginHost* guest = GetGuestByInstanceID(instance_id);
155 if (!guest)
156 return;
157 WebContentsImpl* guest_web_contents =
158 guest ? static_cast<WebContentsImpl*>(guest->web_contents()): NULL;
159 guest->SetDamageBuffer(damage_buffer, gfx::Size(width, height), scale_factor);
160 if (!resize_pending)
161 guest_web_contents->GetView()->SizeContents(gfx::Size(width, height));
162 }
163
164 void BrowserPluginHost::UpdateRect(
165 RenderViewHost* render_view_host,
166 const ViewHostMsg_UpdateRect_Params& params) {
167 // This handler is only of interest to us for the 2D software rendering path.
168 // needs_ack should always be true for the 2D path.
169 // TODO(fsamuel): Do we need to do something different in the 3D case?
170 if (!params.needs_ack)
171 return;
172
173 // Only copy damage if the guest's view size is equal to the damage buffer's
174 // size and the guest's scale factor is equal to the damage buffer's scale
175 // factor.
176 if (params.view_size.width() == damage_buffer_size().width() &&
177 params.view_size.height() == damage_buffer_size().height() &&
178 params.scale_factor == damage_buffer_scale_factor()) {
179 TransportDIB* dib = render_view_host->GetProcess()->
180 GetTransportDIB(params.bitmap);
181 if (dib) {
182 void* guest_memory = dib->memory();
183 void* embedder_memory = damage_buffer_->memory();
184 int size = std::min(dib->size(), damage_buffer_->size());
185 memcpy(embedder_memory, guest_memory, size);
186 }
187 }
188 DCHECK(embedder_render_process_host());
189 BrowserPluginMsg_UpdateRect_Params relay_params;
190 relay_params.bitmap_rect = params.bitmap_rect;
191 relay_params.dx = params.dx;
192 relay_params.dy = params.dy;
193 relay_params.scroll_rect = params.scroll_rect;
194 relay_params.copy_rects = params.copy_rects;
195 relay_params.view_size = params.view_size;
196 relay_params.scale_factor = params.scale_factor;
197 relay_params.is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack(
198 params.flags);
199
200 // We need to send the ACK to the same render_view_host that issued
201 // the UpdateRect. We keep track of this correspondence via a message_id.
202 int message_id = pending_update_counter_++;
203 pending_updates_.AddWithID(render_view_host, message_id);
204
205 gfx::Size param_size = gfx::Size(
206 params.view_size.width(),
207 params.view_size.height());
208 content::NotificationService::current()->Notify(
209 NOTIFICATION_BROWSER_PLUGIN_UPDATE_RECT,
210 content::Source<BrowserPluginHost>(this),
211 content::Details<const gfx::Size>(&param_size));
212
213 embedder_render_process_host()->Send(
214 new BrowserPluginMsg_UpdateRect(instance_id(),
215 message_id,
216 relay_params));
217 }
218
219 void BrowserPluginHost::UpdateRectACK(int message_id,
220 const gfx::Size& size) {
221 RenderViewHost* render_view_host = pending_updates_.Lookup(message_id);
222 // If the guest has crashed since it sent the initial ViewHostMsg_UpdateRect
223 // then the pending_updates_ map will have been cleared.
224 if (!render_view_host)
225 return;
226 pending_updates_.Remove(message_id);
227 render_view_host->Send(
228 new ViewMsg_UpdateRect_ACK(render_view_host->GetRoutingID()));
229 if (!size.IsEmpty())
230 render_view_host->GetView()->SetSize(size);
231 }
232
233 void BrowserPluginHost::HandleInputEvent(
234 RenderViewHost* render_view_host,
235 const gfx::Rect& guest_rect,
236 const WebKit::WebInputEvent& event,
237 IPC::Message* reply_message) {
238 guest_rect_ = guest_rect;
239 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
240 web_contents()->GetRenderViewHost());
241 IPC::Message* message = new ViewMsg_HandleInputEvent(
242 guest_rvh->GetRoutingID());
243
244 // Copy the WebInputEvent and modify the event type. The guest expects
245 // WebInputEvent::RawKeyDowns and not KeyDowns.
246 scoped_array<char> input_buffer(new char[event.size]);
247 memcpy(input_buffer.get(), &event, event.size);
248 WebKit::WebInputEvent* input_event =
249 reinterpret_cast<WebKit::WebInputEvent*>(input_buffer.get());
250 if (event.type == WebKit::WebInputEvent::KeyDown)
251 input_event->type = WebKit::WebInputEvent::RawKeyDown;
252
253 message->WriteData(input_buffer.get(), event.size);
254 // TODO(fsamuel): What do we need to do here? This is for keyboard shortcuts.
255 if (input_event->type == WebKit::WebInputEvent::RawKeyDown)
256 message->WriteBool(false);
257 guest_rvh->Send(message);
258
259 DCHECK(!pending_input_event_reply_.get());
260 pending_input_event_reply_.reset(reply_message);
261 guest_rvh->StartHangMonitorTimeout(
262 base::TimeDelta::FromMilliseconds(kGuestHangTimeout));
263 }
264
265 void BrowserPluginHost::HandleInputEventAck(RenderViewHost* render_view_host,
266 bool handled) {
267 DCHECK(pending_input_event_reply_.get());
268 IPC::Message* reply_message = pending_input_event_reply_.release();
269 BrowserPluginHostMsg_HandleInputEvent::WriteReplyParams(reply_message,
270 handled,
271 cursor_);
272 embedder_render_process_host()->Send(reply_message);
273 RenderViewHostImpl* guest_rvh =
274 static_cast<RenderViewHostImpl*>(render_view_host);
275 guest_rvh->StopHangMonitorTimeout();
276 }
277
278 void BrowserPluginHost::SetFocus(bool focused) {
279 RenderViewHost* render_view_host = web_contents()->GetRenderViewHost();
280 render_view_host->Send(
281 new ViewMsg_SetFocus(render_view_host->GetRoutingID(), focused));
282 }
283
284 void BrowserPluginHost::ShowWidget(RenderViewHost* render_view_host,
285 int route_id,
286 const gfx::Rect& initial_pos) {
287 RenderWidgetHostView* popup_rwhv =
288 static_cast<WebContentsImpl*>(web_contents())->
289 GetCreatedWidget(route_id);
290
291 RenderWidgetHostViewPort* widget_host_view =
292 RenderWidgetHostViewPort::FromRWHV(popup_rwhv);
293 if (!widget_host_view)
294 return;
295 gfx::Rect screen_pos(initial_pos);
296 screen_pos.Offset(guest_rect_.origin());
297 widget_host_view->InitAsPopup(web_contents()->GetRenderWidgetHostView(),
298 screen_pos);
299 RenderWidgetHostImpl* render_widget_host_impl =
300 RenderWidgetHostImpl::From(widget_host_view->GetRenderWidgetHost());
301 render_widget_host_impl->Init();
302 render_widget_host_impl->set_allow_privileged_mouse_lock(false);
303 }
304
305 void BrowserPluginHost::SetCursor(const WebCursor& cursor) {
306 cursor_ = cursor;
307 }
308
309 void BrowserPluginHost::DestroyGuests() {
310 for (GuestMap::const_iterator it = guests_.begin();
311 it != guests_.end(); ++it) {
312 WebContents* web_contents = it->first;
313 delete web_contents;
314 }
315 guests_.clear();
316 guests_by_instance_id_.clear();
317 }
318
319 void BrowserPluginHost::DestroyGuestByInstanceID(int instance_id) {
320
321 BrowserPluginHost* guest = GetGuestByInstanceID(instance_id);
322 if (!guest)
323 return;
324 WebContents* guest_web_contents = guest->web_contents();
325 DCHECK(guest_web_contents);
326 delete guest_web_contents;
327
328 GuestMap::iterator guest_it = guests_.find(guest_web_contents);
329 DCHECK(guest_it != guests_.end());
330
331 guests_.erase(guest_it);
332 guests_by_instance_id_.erase(instance_id);
333 }
334
335 void BrowserPluginHost::DidCommitProvisionalLoadForFrame(
336 int64 frame_id,
337 bool is_main_frame,
338 const GURL& url,
339 PageTransition transition_type,
340 RenderViewHost* render_view_host) {
341 // Clean-up guests that lie in the frame that we're navigating.
342 typedef std::set<WebContents*> GuestSet;
343 GuestSet guests_to_delete;
344 for (GuestMap::const_iterator it = guests_.begin();
345 it != guests_.end(); ++it) {
346 WebContents* web_contents = it->first;
347 if (it->second == frame_id) {
348 guests_to_delete.insert(web_contents);
349 }
350 }
351 for (GuestSet::const_iterator it = guests_to_delete.begin();
352 it != guests_to_delete.end(); ++it) {
353 int instance_id = static_cast<WebContentsImpl*>(*it)->
354 browser_plugin_host()->instance_id();
355 DestroyGuestByInstanceID(instance_id);
356 }
357 // If this is a guest, inform its embedder of the updated URL.
358 // TODO(creis, fsamuel): Ensure this is safe/secure.
359 if (is_main_frame && embedder_render_process_host()) {
360 embedder_render_process_host()->Send(
361 new BrowserPluginMsg_DidNavigate(instance_id(), url));
362 }
363 }
364
365 void BrowserPluginHost::RenderViewDeleted(RenderViewHost* render_view_host) {
366 DestroyGuests();
367 }
368
369 void BrowserPluginHost::RenderViewGone(base::TerminationStatus status) {
370 DestroyGuests();
371 if (embedder_render_process_host()) {
372 if (pending_input_event_reply_.get()) {
373 IPC::Message* reply_message = pending_input_event_reply_.release();
374 BrowserPluginHostMsg_HandleInputEvent::WriteReplyParams(reply_message,
375 false,
376 cursor_);
377 embedder_render_process_host()->Send(reply_message);
378 }
379 embedder_render_process_host()->Send(
380 new BrowserPluginMsg_GuestCrashed(instance_id()));
381 IDMap<RenderViewHost>::const_iterator iter(&pending_updates_);
382 while (!iter.IsAtEnd()) {
383 pending_updates_.Remove(iter.GetCurrentKey());
384 iter.Advance();
385 }
386 content::NotificationService::current()->Notify(
387 NOTIFICATION_BROWSER_PLUGIN_GUEST_CRASHED,
388 content::Source<BrowserPluginHost>(this),
389 content::NotificationService::NoDetails());
390 }
391 }
392
393 void BrowserPluginHost::Observe(
394 int type,
395 const NotificationSource& source,
396 const NotificationDetails& details) {
397 switch (type) {
398 case NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: {
399 RenderViewHost* render_view_host =
400 Details<RenderViewHost>(details).ptr();
401 // BrowserPluginHostHelper is destroyed when its associated RenderViewHost
402 // is destroyed.
403 new BrowserPluginHostHelper(this, render_view_host);
404 break;
405 }
406 case NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED: {
407 bool visible = *Details<bool>(details).ptr();
408 // If the embedder is hidden we need to hide the guests as well.
409 for (GuestMap::const_iterator it = guests_.begin();
410 it != guests_.end(); ++it) {
411 WebContents* web_contents = it->first;
412 if (visible)
413 web_contents->WasShown();
414 else
415 web_contents->WasHidden();
416 }
417 break;
418 }
419 default:
420 NOTREACHED() << "Unexpected notification type: " << type;
421 }
422 }
423
424 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698