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.
5 #include "content/browser/browser_plugin/browser_plugin_guest.h"
9 #include "base/string_util.h"
10 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
11 #include "content/browser/browser_plugin/browser_plugin_guest_helper.h"
12 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/browser/renderer_host/render_widget_host_impl.h"
15 #include "content/browser/web_contents/web_contents_impl.h"
16 #include "content/common/browser_plugin_messages.h"
17 #include "content/common/content_constants_internal.h"
18 #include "content/common/view_messages.h"
19 #include "content/port/browser/render_view_host_delegate_view.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/notification_types.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/render_widget_host_view.h"
24 #include "content/public/browser/resource_request_details.h"
25 #include "content/public/browser/user_metrics.h"
26 #include "content/public/browser/web_contents_view.h"
27 #include "content/public/common/result_codes.h"
28 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
29 #include "net/base/net_errors.h"
30 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
31 #include "ui/surface/transport_dib.h"
32 #include "webkit/glue/webdropdata.h"
33 #include "webkit/glue/resource_type.h"
35 #if defined(OS_MACOSX)
36 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
42 BrowserPluginHostFactory
* BrowserPluginGuest::factory_
= NULL
;
44 BrowserPluginGuest::BrowserPluginGuest(
46 WebContentsImpl
* web_contents
,
47 const BrowserPluginHostMsg_CreateGuest_Params
& params
)
48 : WebContentsObserver(web_contents
),
49 embedder_web_contents_(NULL
),
50 instance_id_(instance_id
),
52 damage_buffer_size_(0),
53 remote_damage_buffer_handle_(0),
55 damage_buffer_scale_factor_(1.0f
),
56 pending_update_counter_(0),
58 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs
)),
59 focused_(params
.focused
),
60 visible_(params
.visible
),
61 auto_size_enabled_(params
.auto_size_params
.enable
),
62 max_auto_size_(params
.auto_size_params
.max_size
),
63 min_auto_size_(params
.auto_size_params
.min_size
) {
67 void BrowserPluginGuest::InstallHelper(
68 content::RenderViewHost
* render_view_host
) {
69 // |render_view_host| manages the ownership of this BrowserPluginGuestHelper.
70 new BrowserPluginGuestHelper(this, render_view_host
);
72 notification_registrar_
.Add(
73 this, content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT
,
74 content::Source
<content::WebContents
>(web_contents()));
77 BrowserPluginGuest::~BrowserPluginGuest() {
81 BrowserPluginGuest
* BrowserPluginGuest::Create(
83 WebContentsImpl
* web_contents
,
84 const BrowserPluginHostMsg_CreateGuest_Params
& params
) {
85 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Create"));
87 return factory_
->CreateBrowserPluginGuest(instance_id
,
91 return new BrowserPluginGuest(instance_id
, web_contents
,params
);
94 void BrowserPluginGuest::Observe(int type
,
95 const NotificationSource
& source
,
96 const NotificationDetails
& details
) {
98 case NOTIFICATION_RESOURCE_RECEIVED_REDIRECT
: {
99 DCHECK_EQ(Source
<WebContents
>(source
).ptr(), web_contents());
100 ResourceRedirectDetails
* resource_redirect_details
=
101 Details
<ResourceRedirectDetails
>(details
).ptr();
103 resource_redirect_details
->resource_type
== ResourceType::MAIN_FRAME
;
104 LoadRedirect(resource_redirect_details
->url
,
105 resource_redirect_details
->new_url
,
110 NOTREACHED() << "Unexpected notification sent.";
115 bool BrowserPluginGuest::ViewTakeFocus(bool reverse
) {
116 SendMessageToEmbedder(
117 new BrowserPluginMsg_AdvanceFocus(embedder_routing_id(),
123 void BrowserPluginGuest::Go(int relative_index
) {
124 web_contents()->GetController().GoToOffset(relative_index
);
127 bool BrowserPluginGuest::CanDownload(RenderViewHost
* render_view_host
,
129 const std::string
& request_method
) {
130 // TODO(fsamuel): We disable downloads in guests for now, but we will later
131 // expose API to allow embedders to handle them.
132 // Note: it seems content_shell ignores this. This should be fixed
133 // for debugging and test purposes.
137 bool BrowserPluginGuest::HandleContextMenu(
138 const ContextMenuParams
& params
) {
139 // TODO(fsamuel): We have a do nothing context menu handler for now until
140 // we implement the Apps Context Menu API for Browser Plugin (see
141 // http://crbug.com/140315).
145 void BrowserPluginGuest::RendererUnresponsive(WebContents
* source
) {
147 web_contents()->GetRenderProcessHost()->GetID();
148 SendMessageToEmbedder(
149 new BrowserPluginMsg_GuestUnresponsive(embedder_routing_id(),
152 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Hung"));
155 void BrowserPluginGuest::RendererResponsive(WebContents
* source
) {
157 web_contents()->GetRenderProcessHost()->GetID();
158 SendMessageToEmbedder(
159 new BrowserPluginMsg_GuestResponsive(embedder_routing_id(),
162 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Responsive"));
165 void BrowserPluginGuest::RunFileChooser(WebContents
* web_contents
,
166 const FileChooserParams
& params
) {
167 embedder_web_contents_
->GetDelegate()->RunFileChooser(web_contents
, params
);
170 bool BrowserPluginGuest::ShouldFocusPageAfterCrash() {
171 // Rather than managing focus in WebContentsImpl::RenderViewReady, we will
172 // manage the focus ourselves.
176 void BrowserPluginGuest::SetIsAcceptingTouchEvents(bool accept
) {
177 SendMessageToEmbedder(
178 new BrowserPluginMsg_ShouldAcceptTouchEvents(embedder_routing_id(),
183 void BrowserPluginGuest::SetVisibility(bool embedder_visible
, bool visible
) {
185 if (embedder_visible
&& visible
)
186 web_contents()->WasShown();
188 web_contents()->WasHidden();
191 void BrowserPluginGuest::DragStatusUpdate(WebKit::WebDragStatus drag_status
,
192 const WebDropData
& drop_data
,
193 WebKit::WebDragOperationsMask mask
,
194 const gfx::Point
& location
) {
195 RenderViewHost
* host
= web_contents()->GetRenderViewHost();
196 switch (drag_status
) {
197 case WebKit::WebDragStatusEnter
:
198 host
->DragTargetDragEnter(drop_data
, location
, location
, mask
, 0);
200 case WebKit::WebDragStatusOver
:
201 host
->DragTargetDragOver(location
, location
, mask
, 0);
203 case WebKit::WebDragStatusLeave
:
204 host
->DragTargetDragLeave();
206 case WebKit::WebDragStatusDrop
:
207 host
->DragTargetDrop(location
, location
, 0);
209 case WebKit::WebDragStatusUnknown
:
214 void BrowserPluginGuest::SetSize(
215 const BrowserPluginHostMsg_AutoSize_Params
& auto_size_params
,
216 const BrowserPluginHostMsg_ResizeGuest_Params
& resize_guest_params
) {
217 bool old_auto_size_enabled
= auto_size_enabled_
;
218 gfx::Size old_max_size
= max_auto_size_
;
219 gfx::Size old_min_size
= min_auto_size_
;
220 auto_size_enabled_
= auto_size_params
.enable
;
221 max_auto_size_
= auto_size_params
.max_size
;
222 min_auto_size_
= auto_size_params
.min_size
;
223 if (auto_size_enabled_
&& (!old_auto_size_enabled
||
224 (old_max_size
!= max_auto_size_
) ||
225 (old_min_size
!= min_auto_size_
))) {
226 web_contents()->GetRenderViewHost()->EnableAutoResize(
227 min_auto_size_
, max_auto_size_
);
228 // TODO(fsamuel): If we're changing autosize parameters, then we force
229 // the guest to completely repaint itself, because BrowserPlugin has
230 // allocated a new damage buffer and expects a full frame of pixels.
231 // Ideally, we shouldn't need to do this because we shouldn't need to
232 // allocate a new damage buffer unless |max_auto_size_| has changed.
233 // However, even in that case, layout may not change and so we may
234 // not get a full frame worth of pixels.
235 web_contents()->GetRenderViewHost()->Send(new ViewMsg_Repaint(
236 web_contents()->GetRenderViewHost()->GetRoutingID(),
238 } else if (!auto_size_enabled_
&& old_auto_size_enabled
) {
239 web_contents()->GetRenderViewHost()->DisableAutoResize(
240 resize_guest_params
.view_size
);
242 Resize(embedder_web_contents_
->GetRenderViewHost(), resize_guest_params
);
245 void BrowserPluginGuest::UpdateDragCursor(WebKit::WebDragOperation operation
) {
246 RenderViewHostImpl
* embedder_render_view_host
=
247 static_cast<RenderViewHostImpl
*>(
248 embedder_web_contents_
->GetRenderViewHost());
249 CHECK(embedder_render_view_host
);
250 RenderViewHostDelegateView
* view
=
251 embedder_render_view_host
->GetDelegate()->GetDelegateView();
253 view
->UpdateDragCursor(operation
);
256 WebContents
* BrowserPluginGuest::GetWebContents() {
257 return web_contents();
260 void BrowserPluginGuest::Terminate() {
261 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Terminate"));
262 base::ProcessHandle process_handle
=
263 web_contents()->GetRenderProcessHost()->GetHandle();
264 base::KillProcess(process_handle
, RESULT_CODE_KILLED
, false);
267 void BrowserPluginGuest::Resize(
268 RenderViewHost
* embedder_rvh
,
269 const BrowserPluginHostMsg_ResizeGuest_Params
& params
) {
270 // BrowserPlugin manages resize flow control itself and does not depend
271 // on RenderWidgetHost's mechanisms for flow control, so we reset those flags
273 RenderWidgetHostImpl
* render_widget_host
=
274 RenderWidgetHostImpl::From(web_contents()->GetRenderViewHost());
275 render_widget_host
->ResetSizeAndRepaintPendingFlags();
276 if (!TransportDIB::is_valid_id(params
.damage_buffer_id
)) {
277 // Invalid transport dib, so just resize the WebContents.
278 if (!params
.view_size
.IsEmpty())
279 web_contents()->GetView()->SizeContents(params
.view_size
);
282 TransportDIB
* damage_buffer
=
283 GetDamageBufferFromEmbedder(embedder_rvh
, params
);
284 SetDamageBuffer(damage_buffer
,
286 params
.damage_buffer_size
,
287 params
.damage_buffer_id
.handle
,
290 params
.scale_factor
);
291 web_contents()->GetView()->SizeContents(params
.view_size
);
294 TransportDIB
* BrowserPluginGuest::GetDamageBufferFromEmbedder(
295 RenderViewHost
* embedder_rvh
,
296 const BrowserPluginHostMsg_ResizeGuest_Params
& params
) {
297 TransportDIB
* damage_buffer
= NULL
;
299 // On Windows we need to duplicate the handle from the remote process.
301 DuplicateHandle(embedder_rvh
->GetProcess()->GetHandle(),
302 params
.damage_buffer_id
.handle
,
305 STANDARD_RIGHTS_REQUIRED
| FILE_MAP_READ
| FILE_MAP_WRITE
,
308 damage_buffer
= TransportDIB::Map(section
);
309 #elif defined(OS_MACOSX)
310 // On OSX, we need the handle to map the transport dib.
311 damage_buffer
= TransportDIB::Map(params
.damage_buffer_handle
);
312 #elif defined(OS_ANDROID)
313 damage_buffer
= TransportDIB::Map(params
.damage_buffer_id
);
314 #elif defined(OS_POSIX)
315 damage_buffer
= TransportDIB::Map(params
.damage_buffer_id
.shmkey
);
316 #endif // defined(OS_POSIX)
317 DCHECK(damage_buffer
);
318 return damage_buffer
;
321 void BrowserPluginGuest::SetDamageBuffer(
322 TransportDIB
* damage_buffer
,
324 int damage_buffer_size
,
325 TransportDIB::Handle remote_handle
,
327 const gfx::Size
& damage_view_size
,
328 float scale_factor
) {
329 // Sanity check: Verify that we've correctly shared the damage buffer memory
330 // between the embedder and browser processes.
331 DCHECK(*static_cast<unsigned int*>(damage_buffer
->memory()) == 0xdeadbeef);
332 damage_buffer_
.reset(damage_buffer
);
334 damage_buffer_size_
= damage_buffer_size
;
335 remote_damage_buffer_handle_
= remote_handle
;
337 damage_view_size_
= damage_view_size
;
338 damage_buffer_scale_factor_
= scale_factor
;
341 gfx::Point
BrowserPluginGuest::GetScreenCoordinates(
342 const gfx::Point
& relative_position
) const {
343 gfx::Point
screen_pos(relative_position
);
344 screen_pos
+= guest_window_rect_
.OffsetFromOrigin();
348 int BrowserPluginGuest::embedder_routing_id() const {
349 return embedder_web_contents_
->GetRoutingID();
352 bool BrowserPluginGuest::InAutoSizeBounds(const gfx::Size
& size
) const {
353 return size
.width() <= max_auto_size_
.width() &&
354 size
.height() <= max_auto_size_
.height();
357 void BrowserPluginGuest::UpdateRect(
358 RenderViewHost
* render_view_host
,
359 const ViewHostMsg_UpdateRect_Params
& params
) {
360 BrowserPluginMsg_UpdateRect_Params relay_params
;
361 relay_params
.view_size
= params
.view_size
;
362 relay_params
.scale_factor
= params
.scale_factor
;
363 relay_params
.is_resize_ack
= ViewHostMsg_UpdateRect_Flags::is_resize_ack(
366 // HW accelerated case, acknowledge resize only
367 if (!params
.needs_ack
) {
368 #if defined(OS_MACOSX)
369 relay_params
.damage_buffer_identifier
= 0;
371 relay_params
.damage_buffer_identifier
= TransportDIB::DefaultHandleValue();
373 SendMessageToEmbedder(new BrowserPluginMsg_UpdateRect(
374 embedder_routing_id(),
381 // Only copy damage if the guest is in autosize mode and the guest's view size
382 // is less than the maximum size or the guest's view size is equal to the
383 // damage buffer's size and the guest's scale factor is equal to the damage
384 // buffer's scale factor.
385 // The scaling change can happen due to asynchronous updates of the DPI on a
386 // resolution change.
387 if (((auto_size_enabled_
&& InAutoSizeBounds(params
.view_size
)) ||
388 (params
.view_size
.width() == damage_view_size().width() &&
389 params
.view_size
.height() == damage_view_size().height())) &&
390 params
.scale_factor
== damage_buffer_scale_factor()) {
391 TransportDIB
* dib
= render_view_host
->GetProcess()->
392 GetTransportDIB(params
.bitmap
);
395 size_t guest_damage_buffer_size
= params
.bitmap_rect
.width() *
396 params
.bitmap_rect
.height() * 4;
397 size_t embedder_damage_buffer_size
= damage_buffer_size_
;
399 size_t guest_damage_buffer_size
= dib
->size();
400 size_t embedder_damage_buffer_size
= damage_buffer_
->size();
402 void* guest_memory
= dib
->memory();
403 void* embedder_memory
= damage_buffer_
->memory();
404 size_t size
= std::min(guest_damage_buffer_size
,
405 embedder_damage_buffer_size
);
406 memcpy(embedder_memory
, guest_memory
, size
);
409 #if defined(OS_MACOSX)
410 relay_params
.damage_buffer_identifier
= damage_buffer_
->id();
411 #elif defined(OS_WIN)
412 // On Windows, the handle used locally differs from the handle received from
413 // the embedder process, since we duplicate the remote handle.
414 relay_params
.damage_buffer_identifier
= remote_damage_buffer_handle_
;
416 relay_params
.damage_buffer_identifier
= damage_buffer_
->handle();
418 relay_params
.bitmap_rect
= params
.bitmap_rect
;
419 relay_params
.scroll_delta
= params
.scroll_delta
;
420 relay_params
.scroll_rect
= params
.scroll_rect
;
421 relay_params
.copy_rects
= params
.copy_rects
;
423 // We need to send the ACK to the same render_view_host that issued
424 // the UpdateRect. We keep track of this correspondence via a message_id.
425 int message_id
= pending_update_counter_
++;
426 pending_updates_
.AddWithID(render_view_host
, message_id
);
428 SendMessageToEmbedder(new BrowserPluginMsg_UpdateRect(embedder_routing_id(),
434 void BrowserPluginGuest::UpdateRectACK(
436 const BrowserPluginHostMsg_AutoSize_Params
& auto_size_params
,
437 const BrowserPluginHostMsg_ResizeGuest_Params
& resize_guest_params
) {
438 RenderViewHost
* render_view_host
= pending_updates_
.Lookup(message_id
);
439 // If the guest has crashed since it sent the initial ViewHostMsg_UpdateRect
440 // then the pending_updates_ map will have been cleared.
441 if (render_view_host
) {
442 pending_updates_
.Remove(message_id
);
443 render_view_host
->Send(
444 new ViewMsg_UpdateRect_ACK(render_view_host
->GetRoutingID()));
446 SetSize(auto_size_params
, resize_guest_params
);
449 void BrowserPluginGuest::HandleInputEvent(RenderViewHost
* render_view_host
,
450 const gfx::Rect
& guest_window_rect
,
451 const gfx::Rect
& guest_screen_rect
,
452 const WebKit::WebInputEvent
& event
) {
453 guest_window_rect_
= guest_window_rect
;
454 guest_screen_rect_
= guest_screen_rect
;
455 RenderViewHostImpl
* guest_rvh
= static_cast<RenderViewHostImpl
*>(
456 web_contents()->GetRenderViewHost());
458 IPC::Message
* message
= NULL
;
460 // TODO(fsamuel): What should we do for keyboard_shortcut field?
461 if (event
.type
== WebKit::WebInputEvent::KeyDown
) {
462 CHECK_EQ(sizeof(WebKit::WebKeyboardEvent
), event
.size
);
463 WebKit::WebKeyboardEvent key_event
;
464 memcpy(&key_event
, &event
, event
.size
);
465 key_event
.type
= WebKit::WebInputEvent::RawKeyDown
;
466 message
= new ViewMsg_HandleInputEvent(routing_id(), &key_event
, false);
468 message
= new ViewMsg_HandleInputEvent(routing_id(), &event
, false);
471 guest_rvh
->Send(message
);
472 guest_rvh
->StartHangMonitorTimeout(guest_hang_timeout_
);
475 void BrowserPluginGuest::HandleInputEventAck(RenderViewHost
* render_view_host
,
477 RenderViewHostImpl
* guest_rvh
=
478 static_cast<RenderViewHostImpl
*>(render_view_host
);
479 guest_rvh
->StopHangMonitorTimeout();
482 void BrowserPluginGuest::Stop() {
483 web_contents()->Stop();
486 void BrowserPluginGuest::Reload() {
487 // TODO(fsamuel): Don't check for repost because we don't want to show
488 // Chromium's repost warning. We might want to implement a separate API
489 // for registering a callback if a repost is about to happen.
490 web_contents()->GetController().Reload(false);
493 void BrowserPluginGuest::SetFocus(bool focused
) {
494 if (focused_
== focused
)
497 Send(new ViewMsg_SetFocus(routing_id(), focused
));
500 void BrowserPluginGuest::ShowWidget(RenderViewHost
* render_view_host
,
502 const gfx::Rect
& initial_pos
) {
503 gfx::Rect
screen_pos(initial_pos
);
504 screen_pos
.Offset(guest_screen_rect_
.OffsetFromOrigin());
505 static_cast<WebContentsImpl
*>(web_contents())->ShowCreatedWidget(route_id
,
509 #if defined(OS_MACOSX)
510 void BrowserPluginGuest::ShowPopup(RenderViewHost
* render_view_host
,
511 const ViewHostMsg_ShowPopup_Params
& params
) {
512 gfx::Rect
translated_bounds(params
.bounds
);
513 translated_bounds
.Offset(guest_window_rect_
.OffsetFromOrigin());
514 BrowserPluginPopupMenuHelper
popup_menu_helper(
515 embedder_web_contents_
->GetRenderViewHost(), render_view_host
);
516 popup_menu_helper
.ShowPopupMenu(translated_bounds
,
518 params
.item_font_size
,
519 params
.selected_item
,
521 params
.right_aligned
,
522 params
.allow_multiple_selection
);
526 void BrowserPluginGuest::SetCursor(const WebCursor
& cursor
) {
527 SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(embedder_routing_id(),
532 void BrowserPluginGuest::DidStartProvisionalLoadForFrame(
534 int64 parent_frame_id
,
536 const GURL
& validated_url
,
538 RenderViewHost
* render_view_host
) {
539 // Inform the embedder of the loadStart.
540 SendMessageToEmbedder(
541 new BrowserPluginMsg_LoadStart(embedder_routing_id(),
547 void BrowserPluginGuest::DidFailProvisionalLoad(
550 const GURL
& validated_url
,
552 const string16
& error_description
,
553 RenderViewHost
* render_view_host
) {
554 // Translate the |error_code| into an error string.
555 std::string error_type
;
556 RemoveChars(net::ErrorToString(error_code
), "net::", &error_type
);
557 // Inform the embedder of the loadAbort.
558 SendMessageToEmbedder(
559 new BrowserPluginMsg_LoadAbort(embedder_routing_id(),
566 void BrowserPluginGuest::LoadRedirect(
570 SendMessageToEmbedder(
571 new BrowserPluginMsg_LoadRedirect(embedder_routing_id(),
578 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
582 PageTransition transition_type
,
583 RenderViewHost
* render_view_host
) {
584 // Inform its embedder of the updated URL.
585 BrowserPluginMsg_LoadCommit_Params params
;
587 params
.is_top_level
= is_main_frame
;
588 params
.process_id
= render_view_host
->GetProcess()->GetID();
589 params
.current_entry_index
=
590 web_contents()->GetController().GetCurrentEntryIndex();
592 web_contents()->GetController().GetEntryCount();
593 SendMessageToEmbedder(
594 new BrowserPluginMsg_LoadCommit(embedder_routing_id(),
597 RecordAction(UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
600 void BrowserPluginGuest::DidStopLoading(RenderViewHost
* render_view_host
) {
601 SendMessageToEmbedder(new BrowserPluginMsg_LoadStop(embedder_routing_id(),
605 void BrowserPluginGuest::RenderViewReady() {
606 // TODO(fsamuel): Investigate whether it's possible to update state earlier
607 // here (see http://crbug.com/158151).
608 Send(new ViewMsg_SetFocus(routing_id(), focused_
));
609 bool embedder_visible
=
610 embedder_web_contents_
->GetBrowserPluginEmbedder()->visible();
611 SetVisibility(embedder_visible
, visible());
612 if (auto_size_enabled_
) {
613 web_contents()->GetRenderViewHost()->EnableAutoResize(
614 min_auto_size_
, max_auto_size_
);
616 web_contents()->GetRenderViewHost()->DisableAutoResize(damage_view_size_
);
620 void BrowserPluginGuest::RenderViewGone(base::TerminationStatus status
) {
621 int process_id
= web_contents()->GetRenderProcessHost()->GetID();
622 SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(embedder_routing_id(),
626 IDMap
<RenderViewHost
>::const_iterator
iter(&pending_updates_
);
627 while (!iter
.IsAtEnd()) {
628 pending_updates_
.Remove(iter
.GetCurrentKey());
633 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED
:
634 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Killed"));
636 case base::TERMINATION_STATUS_PROCESS_CRASHED
:
637 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Crashed"));
639 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION
:
640 RecordAction(UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
647 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message
* msg
) {
648 embedder_web_contents_
->Send(msg
);
651 } // namespace content