1 // Copyright 2014 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 "base/bind_helpers.h"
6 #include "base/command_line.h"
7 #include "base/logging.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/browser/browser_plugin/browser_plugin_guest.h"
10 #include "content/browser/frame_host/render_widget_host_view_guest.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/common/browser_plugin/browser_plugin_messages.h"
13 #include "content/common/frame_messages.h"
14 #include "content/common/gpu/gpu_messages.h"
15 #include "content/common/host_shared_bitmap_manager.h"
16 #include "content/common/input/web_touch_event_traits.h"
17 #include "content/common/view_messages.h"
18 #include "content/common/webplugin_geometry.h"
19 #include "content/public/common/content_switches.h"
20 #include "skia/ext/platform_canvas.h"
21 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
23 #if defined(OS_MACOSX)
24 #import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
28 #include "content/browser/renderer_host/ui_events_helper.h"
36 blink::WebGestureEvent
CreateFlingCancelEvent(double time_stamp
) {
37 blink::WebGestureEvent gesture_event
;
38 gesture_event
.timeStampSeconds
= time_stamp
;
39 gesture_event
.type
= blink::WebGestureEvent::GestureFlingCancel
;
40 gesture_event
.sourceDevice
= blink::WebGestureEvent::Touchscreen
;
43 #endif // defined(USE_AURA)
47 RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
48 RenderWidgetHost
* widget_host
,
49 BrowserPluginGuest
* guest
,
50 RenderWidgetHostViewBase
* platform_view
)
51 : RenderWidgetHostViewChildFrame(widget_host
),
52 // |guest| is NULL during test.
53 guest_(guest
? guest
->AsWeakPtr() : base::WeakPtr
<BrowserPluginGuest
>()),
54 platform_view_(platform_view
) {
56 gesture_recognizer_
.reset(ui::GestureRecognizer::Create());
57 gesture_recognizer_
->AddGestureEventHelper(this);
58 #endif // defined(USE_AURA)
61 RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
63 gesture_recognizer_
->RemoveGestureEventHelper(this);
64 #endif // defined(USE_AURA)
67 void RenderWidgetHostViewGuest::WasShown() {
68 // If the WebContents associated with us showed an interstitial page in the
69 // beginning, the teardown path might call WasShown() while |host_| is in
70 // the process of destruction. Avoid calling WasShown below in this case.
71 // TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the
72 // first place: http://crbug.com/273089.
74 // |guest_| is NULL during test.
75 if ((guest_
&& guest_
->is_in_destruction()) || !host_
->is_hidden())
80 void RenderWidgetHostViewGuest::WasHidden() {
81 // |guest_| is NULL during test.
82 if ((guest_
&& guest_
->is_in_destruction()) || host_
->is_hidden())
87 void RenderWidgetHostViewGuest::SetSize(const gfx::Size
& size
) {
92 void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect
& rect
) {
97 void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
98 const TouchEventWithLatencyInfo
& touch
, InputEventAckState ack_result
) {
99 // TODO(fsamuel): Currently we will only take this codepath if the guest has
100 // requested touch events. A better solution is to always forward touchpresses
101 // to the embedder process to target a BrowserPlugin, and then route all
102 // subsequent touch points of that touchdown to the appropriate guest until
103 // that touch point is released.
104 ScopedVector
<ui::TouchEvent
> events
;
105 if (!MakeUITouchEventsFromWebTouchEvents(touch
, &events
, LOCAL_COORDINATES
))
108 ui::EventResult result
= (ack_result
==
109 INPUT_EVENT_ACK_STATE_CONSUMED
) ? ui::ER_HANDLED
: ui::ER_UNHANDLED
;
110 for (ScopedVector
<ui::TouchEvent
>::iterator iter
= events
.begin(),
111 end
= events
.end(); iter
!= end
; ++iter
) {
112 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
113 gestures
.reset(gesture_recognizer_
->ProcessTouchEventForGesture(
114 *(*iter
), result
, this));
115 ProcessGestures(gestures
.get());
120 gfx::Rect
RenderWidgetHostViewGuest::GetViewBounds() const {
124 RenderWidgetHostViewBase
* rwhv
= GetGuestRenderWidgetHostView();
125 gfx::Rect embedder_bounds
;
127 embedder_bounds
= rwhv
->GetViewBounds();
128 gfx::Rect shifted_rect
= guest_
->ToGuestRect(embedder_bounds
);
129 shifted_rect
.set_width(size_
.width());
130 shifted_rect
.set_height(size_
.height());
134 void RenderWidgetHostViewGuest::RenderProcessGone(
135 base::TerminationStatus status
,
137 platform_view_
->RenderProcessGone(status
, error_code
);
138 // Destroy the guest view instance only, so we don't end up calling
139 // platform_view_->Destroy().
143 void RenderWidgetHostViewGuest::Destroy() {
144 // The RenderWidgetHost's destruction led here, so don't call it.
147 platform_view_
->Destroy();
150 gfx::Size
RenderWidgetHostViewGuest::GetPhysicalBackingSize() const {
151 return RenderWidgetHostViewBase::GetPhysicalBackingSize();
154 base::string16
RenderWidgetHostViewGuest::GetSelectedText() const {
155 return platform_view_
->GetSelectedText();
158 void RenderWidgetHostViewGuest::SetTooltipText(
159 const base::string16
& tooltip_text
) {
160 platform_view_
->SetTooltipText(tooltip_text
);
163 void RenderWidgetHostViewGuest::AcceleratedSurfaceBuffersSwapped(
164 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params
& params
,
169 FrameMsg_BuffersSwapped_Params guest_params
;
170 guest_params
.size
= params
.size
;
171 guest_params
.mailbox
= params
.mailbox
;
172 guest_params
.gpu_route_id
= params
.route_id
;
173 guest_params
.gpu_host_id
= gpu_host_id
;
174 guest_
->SendMessageToEmbedder(
175 new BrowserPluginMsg_BuffersSwapped(guest_
->instance_id(),
179 void RenderWidgetHostViewGuest::AcceleratedSurfacePostSubBuffer(
180 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params
& params
,
185 void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
186 uint32 output_surface_id
,
187 scoped_ptr
<cc::CompositorFrame
> frame
) {
191 if (!guest_
->attached()) {
192 // If the guest doesn't have an embedder then there's nothing to give the
196 base::SharedMemoryHandle software_frame_handle
=
197 base::SharedMemory::NULLHandle();
198 if (frame
->software_frame_data
) {
199 cc::SoftwareFrameData
* frame_data
= frame
->software_frame_data
.get();
200 scoped_ptr
<cc::SharedBitmap
> bitmap
=
201 HostSharedBitmapManager::current()->GetSharedBitmapFromId(
202 frame_data
->size
, frame_data
->bitmap_id
);
206 RenderWidgetHostView
* embedder_rwhv
=
207 guest_
->GetEmbedderRenderWidgetHostView();
208 base::ProcessHandle embedder_pid
=
209 embedder_rwhv
->GetRenderWidgetHost()->GetProcess()->GetHandle();
211 bitmap
->memory()->ShareToProcess(embedder_pid
, &software_frame_handle
);
214 FrameMsg_CompositorFrameSwapped_Params guest_params
;
215 frame
->AssignTo(&guest_params
.frame
);
216 guest_params
.output_surface_id
= output_surface_id
;
217 guest_params
.producing_route_id
= host_
->GetRoutingID();
218 guest_params
.producing_host_id
= host_
->GetProcess()->GetID();
219 guest_params
.shared_memory_handle
= software_frame_handle
;
221 guest_
->SendMessageToEmbedder(
222 new BrowserPluginMsg_CompositorFrameSwapped(guest_
->instance_id(),
226 bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message
& msg
) {
227 return platform_view_
->OnMessageReceived(msg
);
230 void RenderWidgetHostViewGuest::InitAsChild(
231 gfx::NativeView parent_view
) {
232 platform_view_
->InitAsChild(parent_view
);
235 void RenderWidgetHostViewGuest::InitAsPopup(
236 RenderWidgetHostView
* parent_host_view
, const gfx::Rect
& pos
) {
237 // This should never get called.
241 void RenderWidgetHostViewGuest::InitAsFullscreen(
242 RenderWidgetHostView
* reference_host_view
) {
243 // This should never get called.
247 gfx::NativeView
RenderWidgetHostViewGuest::GetNativeView() const {
249 return gfx::NativeView();
251 RenderWidgetHostView
* rwhv
= guest_
->GetEmbedderRenderWidgetHostView();
253 return gfx::NativeView();
254 return rwhv
->GetNativeView();
257 gfx::NativeViewId
RenderWidgetHostViewGuest::GetNativeViewId() const {
259 return static_cast<gfx::NativeViewId
>(NULL
);
261 RenderWidgetHostView
* rwhv
= guest_
->GetEmbedderRenderWidgetHostView();
263 return static_cast<gfx::NativeViewId
>(NULL
);
264 return rwhv
->GetNativeViewId();
267 gfx::NativeViewAccessible
RenderWidgetHostViewGuest::GetNativeViewAccessible() {
269 return gfx::NativeViewAccessible();
271 RenderWidgetHostView
* rwhv
= guest_
->GetEmbedderRenderWidgetHostView();
273 return gfx::NativeViewAccessible();
274 return rwhv
->GetNativeViewAccessible();
277 void RenderWidgetHostViewGuest::MovePluginWindows(
278 const std::vector
<WebPluginGeometry
>& moves
) {
279 platform_view_
->MovePluginWindows(moves
);
282 void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor
& cursor
) {
283 platform_view_
->UpdateCursor(cursor
);
286 void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading
) {
287 platform_view_
->SetIsLoading(is_loading
);
290 void RenderWidgetHostViewGuest::TextInputTypeChanged(
291 ui::TextInputType type
,
292 ui::TextInputMode input_mode
,
293 bool can_compose_inline
) {
297 RenderWidgetHostViewBase
* rwhv
= GetGuestRenderWidgetHostView();
300 // Forward the information to embedding RWHV.
301 rwhv
->TextInputTypeChanged(type
, input_mode
, can_compose_inline
);
304 void RenderWidgetHostViewGuest::ImeCancelComposition() {
308 RenderWidgetHostViewBase
* rwhv
= GetGuestRenderWidgetHostView();
311 // Forward the information to embedding RWHV.
312 rwhv
->ImeCancelComposition();
315 #if defined(OS_MACOSX) || defined(USE_AURA)
316 void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
317 const gfx::Range
& range
,
318 const std::vector
<gfx::Rect
>& character_bounds
) {
322 RenderWidgetHostViewBase
* rwhv
= GetGuestRenderWidgetHostView();
325 std::vector
<gfx::Rect
> guest_character_bounds
;
326 for (size_t i
= 0; i
< character_bounds
.size(); ++i
) {
327 gfx::Rect guest_rect
= guest_
->ToGuestRect(character_bounds
[i
]);
328 guest_character_bounds
.push_back(guest_rect
);
330 // Forward the information to embedding RWHV.
331 rwhv
->ImeCompositionRangeChanged(range
, guest_character_bounds
);
335 void RenderWidgetHostViewGuest::SelectionChanged(const base::string16
& text
,
337 const gfx::Range
& range
) {
338 platform_view_
->SelectionChanged(text
, offset
, range
);
341 void RenderWidgetHostViewGuest::SelectionBoundsChanged(
342 const ViewHostMsg_SelectionBounds_Params
& params
) {
346 RenderWidgetHostViewBase
* rwhv
= GetGuestRenderWidgetHostView();
349 ViewHostMsg_SelectionBounds_Params
guest_params(params
);
350 guest_params
.anchor_rect
= guest_
->ToGuestRect(params
.anchor_rect
);
351 guest_params
.focus_rect
= guest_
->ToGuestRect(params
.focus_rect
);
352 rwhv
->SelectionBoundsChanged(guest_params
);
355 #if defined(OS_ANDROID)
356 void RenderWidgetHostViewGuest::SelectionRootBoundsChanged(
357 const gfx::Rect
& bounds
) {
361 RenderWidgetHostViewBase
* rwhv
= GetGuestRenderWidgetHostView();
365 rwhv
->SelectionRootBoundsChanged(guest_
->ToGuestRect(bounds
));
369 void RenderWidgetHostViewGuest::CopyFromCompositingSurface(
370 const gfx::Rect
& src_subrect
,
371 const gfx::Size
& dst_size
,
372 const base::Callback
<void(bool, const SkBitmap
&)>& callback
,
373 const SkBitmap::Config config
) {
375 guest_
->CopyFromCompositingSurface(src_subrect
, dst_size
, callback
);
378 void RenderWidgetHostViewGuest::SetBackground(const SkBitmap
& background
) {
379 platform_view_
->SetBackground(background
);
382 void RenderWidgetHostViewGuest::SetScrollOffsetPinning(
383 bool is_pinned_to_left
, bool is_pinned_to_right
) {
384 platform_view_
->SetScrollOffsetPinning(
385 is_pinned_to_left
, is_pinned_to_right
);
388 bool RenderWidgetHostViewGuest::LockMouse() {
389 return platform_view_
->LockMouse();
392 void RenderWidgetHostViewGuest::UnlockMouse() {
393 return platform_view_
->UnlockMouse();
396 void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo
* results
) {
399 RenderWidgetHostViewBase
* embedder_view
= GetGuestRenderWidgetHostView();
401 embedder_view
->GetScreenInfo(results
);
404 #if defined(OS_MACOSX)
405 void RenderWidgetHostViewGuest::SetActive(bool active
) {
406 platform_view_
->SetActive(active
);
409 void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag
) {
410 platform_view_
->SetTakesFocusOnlyOnMouseDown(flag
);
413 void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible
) {
414 platform_view_
->SetWindowVisibility(visible
);
417 void RenderWidgetHostViewGuest::WindowFrameChanged() {
418 platform_view_
->WindowFrameChanged();
421 void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
426 gfx::Rect guest_bounds
= GetViewBounds();
427 RenderWidgetHostView
* rwhv
= guest_
->GetEmbedderRenderWidgetHostView();
428 gfx::Rect embedder_bounds
;
430 embedder_bounds
= rwhv
->GetViewBounds();
432 gfx::Vector2d guest_offset
= gfx::Vector2d(
433 // Horizontal offset of guest from embedder.
434 guest_bounds
.x() - embedder_bounds
.x(),
435 // Vertical offset from guest's top to embedder's bottom edge.
436 embedder_bounds
.bottom() - guest_bounds
.y());
438 RenderWidgetHostViewMacDictionaryHelper
helper(platform_view_
);
439 helper
.SetTargetView(rwhv
);
440 helper
.set_offset(guest_offset
);
441 helper
.ShowDefinitionForSelection();
444 bool RenderWidgetHostViewGuest::SupportsSpeech() const {
445 return platform_view_
->SupportsSpeech();
448 void RenderWidgetHostViewGuest::SpeakSelection() {
449 platform_view_
->SpeakSelection();
452 bool RenderWidgetHostViewGuest::IsSpeaking() const {
453 return platform_view_
->IsSpeaking();
456 void RenderWidgetHostViewGuest::StopSpeaking() {
457 platform_view_
->StopSpeaking();
460 bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
461 const NativeWebKeyboardEvent
& event
) {
465 #endif // defined(OS_MACOSX)
467 #if defined(OS_ANDROID)
468 void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
469 const gfx::Rect
& target_rect
,
470 const SkBitmap
& zoomed_bitmap
) {
473 void RenderWidgetHostViewGuest::LockCompositingSurface() {
476 void RenderWidgetHostViewGuest::UnlockCompositingSurface() {
478 #endif // defined(OS_ANDROID)
481 void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
482 gfx::NativeViewAccessible accessible_parent
) {
485 gfx::NativeViewId
RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
491 void RenderWidgetHostViewGuest::DestroyGuestView() {
492 host_
->SetView(NULL
);
494 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
497 bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
498 ui::GestureConsumer
* consumer
) {
499 CHECK_EQ(static_cast<RenderWidgetHostViewGuest
*>(consumer
), this);
503 void RenderWidgetHostViewGuest::DispatchPostponedGestureEvent(
504 ui::GestureEvent
* event
) {
505 ForwardGestureEventToRenderer(event
);
508 void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
509 ui::TouchEvent
* event
) {
513 blink::WebTouchEvent cancel_event
;
514 // TODO(rbyers): This event has no touches in it. Don't we need to know what
515 // touches are currently active in order to cancel them all properly?
516 WebTouchEventTraits::ResetType(blink::WebInputEvent::TouchCancel
,
517 event
->time_stamp().InSecondsF(),
520 host_
->ForwardTouchEventWithLatencyInfo(cancel_event
, *event
->latency());
523 bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
524 ui::GestureEvent
* gesture
) {
525 #if defined(USE_AURA)
529 if ((gesture
->type() == ui::ET_GESTURE_PINCH_BEGIN
||
530 gesture
->type() == ui::ET_GESTURE_PINCH_UPDATE
||
531 gesture
->type() == ui::ET_GESTURE_PINCH_END
) && !pinch_zoom_enabled_
) {
535 blink::WebGestureEvent web_gesture
=
536 MakeWebGestureEventFromUIEvent(*gesture
);
537 const gfx::Point
& client_point
= gesture
->location();
538 const gfx::Point
& screen_point
= gesture
->location();
540 web_gesture
.x
= client_point
.x();
541 web_gesture
.y
= client_point
.y();
542 web_gesture
.globalX
= screen_point
.x();
543 web_gesture
.globalY
= screen_point
.y();
545 if (web_gesture
.type
== blink::WebGestureEvent::Undefined
)
547 if (web_gesture
.type
== blink::WebGestureEvent::GestureTapDown
) {
548 host_
->ForwardGestureEvent(
549 CreateFlingCancelEvent(gesture
->time_stamp().InSecondsF()));
551 host_
->ForwardGestureEvent(web_gesture
);
558 void RenderWidgetHostViewGuest::ProcessGestures(
559 ui::GestureRecognizer::Gestures
* gestures
) {
560 if ((gestures
== NULL
) || gestures
->empty())
562 for (ui::GestureRecognizer::Gestures::iterator g_it
= gestures
->begin();
563 g_it
!= gestures
->end();
565 ForwardGestureEventToRenderer(*g_it
);
569 SkBitmap::Config
RenderWidgetHostViewGuest::PreferredReadbackFormat() {
570 return SkBitmap::kARGB_8888_Config
;
573 RenderWidgetHostViewBase
*
574 RenderWidgetHostViewGuest::GetGuestRenderWidgetHostView() const {
575 return static_cast<RenderWidgetHostViewBase
*>(
576 guest_
->GetEmbedderRenderWidgetHostView());
579 } // namespace content