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 "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/renderer_host/render_view_host_impl.h"
11 #include "content/browser/renderer_host/render_widget_host_view_guest.h"
12 #include "content/common/browser_plugin/browser_plugin_messages.h"
13 #include "content/common/gpu/gpu_messages.h"
14 #include "content/common/view_messages.h"
15 #include "content/common/webplugin_geometry.h"
16 #include "content/public/common/content_switches.h"
17 #include "skia/ext/platform_canvas.h"
18 #include "third_party/WebKit/public/web/WebScreenInfo.h"
20 #if defined(OS_MACOSX)
21 #import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
24 #if defined(OS_WIN) || defined(USE_AURA)
25 #include "content/browser/renderer_host/ui_events_helper.h"
32 bool ShouldSendPinchGesture() {
33 static bool pinch_allowed
=
34 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePinch
);
38 WebKit::WebGestureEvent
CreateFlingCancelEvent(double time_stamp
) {
39 WebKit::WebGestureEvent gesture_event
;
40 gesture_event
.timeStampSeconds
= time_stamp
;
41 gesture_event
.type
= WebKit::WebGestureEvent::GestureFlingCancel
;
42 gesture_event
.sourceDevice
= WebKit::WebGestureEvent::Touchscreen
;
48 RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
49 RenderWidgetHost
* widget_host
,
50 BrowserPluginGuest
* guest
,
51 RenderWidgetHostView
* platform_view
)
52 : host_(RenderWidgetHostImpl::From(widget_host
)),
54 platform_view_(static_cast<RenderWidgetHostViewPort
*>(platform_view
)) {
55 #if defined(OS_WIN) || defined(USE_AURA)
56 gesture_recognizer_
.reset(ui::GestureRecognizer::Create());
57 gesture_recognizer_
->AddGestureEventHelper(this);
58 #endif // defined(OS_WIN) || defined(USE_AURA)
62 RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
63 #if defined(OS_WIN) || defined(USE_AURA)
64 gesture_recognizer_
->RemoveGestureEventHelper(this);
65 #endif // defined(OS_WIN) || defined(USE_AURA)
68 RenderWidgetHost
* RenderWidgetHostViewGuest::GetRenderWidgetHost() const {
72 void RenderWidgetHostViewGuest::WasShown() {
73 // If the WebContents associated with us showed an interstitial page in the
74 // beginning, the teardown path might call WasShown() while |host_| is in
75 // the process of destruction. Avoid calling WasShown below in this case.
76 // TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the
77 // first place: http://crbug.com/273089.
79 // |guest_| is NULL during test.
80 if ((guest_
&& guest_
->is_in_destruction()) || !host_
->is_hidden())
85 void RenderWidgetHostViewGuest::WasHidden() {
86 // |guest_| is NULL during test.
87 if ((guest_
&& guest_
->is_in_destruction()) || host_
->is_hidden())
92 void RenderWidgetHostViewGuest::SetSize(const gfx::Size
& size
) {
97 gfx::Rect
RenderWidgetHostViewGuest::GetBoundsInRootWindow() {
98 // We do not have any root window specific parts in this view.
99 return GetViewBounds();
102 gfx::GLSurfaceHandle
RenderWidgetHostViewGuest::GetCompositingSurface() {
103 return gfx::GLSurfaceHandle(gfx::kNullPluginWindow
, gfx::TEXTURE_TRANSPORT
);
106 #if defined(OS_WIN) || defined(USE_AURA)
107 void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
108 const TouchEventWithLatencyInfo
& touch
, InputEventAckState ack_result
) {
109 // TODO(fsamuel): Currently we will only take this codepath if the guest has
110 // requested touch events. A better solution is to always forward touchpresses
111 // to the embedder process to target a BrowserPlugin, and then route all
112 // subsequent touch points of that touchdown to the appropriate guest until
113 // that touch point is released.
114 ScopedVector
<ui::TouchEvent
> events
;
115 if (!MakeUITouchEventsFromWebTouchEvents(touch
, &events
, LOCAL_COORDINATES
))
118 ui::EventResult result
= (ack_result
==
119 INPUT_EVENT_ACK_STATE_CONSUMED
) ? ui::ER_HANDLED
: ui::ER_UNHANDLED
;
120 for (ScopedVector
<ui::TouchEvent
>::iterator iter
= events
.begin(),
121 end
= events
.end(); iter
!= end
; ++iter
) {
122 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
123 gestures
.reset(gesture_recognizer_
->ProcessTouchEventForGesture(
124 *(*iter
), result
, this));
125 ProcessGestures(gestures
.get());
130 void RenderWidgetHostViewGuest::Show() {
134 void RenderWidgetHostViewGuest::Hide() {
138 bool RenderWidgetHostViewGuest::IsShowing() {
139 return !host_
->is_hidden();
142 gfx::Rect
RenderWidgetHostViewGuest::GetViewBounds() const {
143 RenderWidgetHostViewPort
* rwhv
= static_cast<RenderWidgetHostViewPort
*>(
144 guest_
->GetEmbedderRenderWidgetHostView());
145 gfx::Rect embedder_bounds
;
147 embedder_bounds
= rwhv
->GetViewBounds();
148 gfx::Rect shifted_rect
= guest_
->ToGuestRect(embedder_bounds
);
149 shifted_rect
.set_width(size_
.width());
150 shifted_rect
.set_height(size_
.height());
154 void RenderWidgetHostViewGuest::RenderProcessGone(
155 base::TerminationStatus status
,
157 platform_view_
->RenderProcessGone(status
, error_code
);
158 // Destroy the guest view instance only, so we don't end up calling
159 // platform_view_->Destroy().
163 void RenderWidgetHostViewGuest::Destroy() {
164 // The RenderWidgetHost's destruction led here, so don't call it.
167 platform_view_
->Destroy();
170 void RenderWidgetHostViewGuest::SetTooltipText(const string16
& tooltip_text
) {
171 platform_view_
->SetTooltipText(tooltip_text
);
174 void RenderWidgetHostViewGuest::AcceleratedSurfaceBuffersSwapped(
175 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params
& params
,
177 // If accelerated surface buffers are getting swapped then we're not using
178 // the software path.
179 guest_
->clear_damage_buffer();
180 BrowserPluginMsg_BuffersSwapped_Params guest_params
;
181 guest_params
.size
= params
.size
;
182 guest_params
.mailbox_name
= params
.mailbox_name
;
183 guest_params
.route_id
= params
.route_id
;
184 guest_params
.host_id
= gpu_host_id
;
185 guest_
->SendMessageToEmbedder(
186 new BrowserPluginMsg_BuffersSwapped(guest_
->instance_id(), guest_params
));
189 void RenderWidgetHostViewGuest::AcceleratedSurfacePostSubBuffer(
190 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params
& params
,
195 void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
196 uint32 output_surface_id
,
197 scoped_ptr
<cc::CompositorFrame
> frame
) {
198 if (frame
->software_frame_data
) {
199 cc::SoftwareFrameData
* frame_data
= frame
->software_frame_data
.get();
201 base::SharedMemory
shared_memory(frame_data
->handle
, true,
202 host_
->GetProcess()->GetHandle());
204 base::SharedMemory
shared_memory(frame_data
->handle
, true);
207 RenderWidgetHostView
* embedder_view
=
208 guest_
->GetEmbedderRenderWidgetHostView();
209 base::ProcessHandle embedder_pid
=
210 embedder_view
->GetRenderWidgetHost()->GetProcess()->GetHandle();
212 shared_memory
.GiveToProcess(embedder_pid
, &frame_data
->handle
);
215 guest_
->clear_damage_buffer();
216 guest_
->SendMessageToEmbedder(
217 new BrowserPluginMsg_CompositorFrameSwapped(
218 guest_
->instance_id(),
220 host_
->GetRoutingID(),
222 host_
->GetProcess()->GetID()));
225 void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect
& rect
) {
226 SetSize(rect
.size());
229 bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message
& msg
) {
230 return platform_view_
->OnMessageReceived(msg
);
233 void RenderWidgetHostViewGuest::InitAsChild(
234 gfx::NativeView parent_view
) {
235 platform_view_
->InitAsChild(parent_view
);
238 void RenderWidgetHostViewGuest::InitAsPopup(
239 RenderWidgetHostView
* parent_host_view
, const gfx::Rect
& pos
) {
240 // This should never get called.
244 void RenderWidgetHostViewGuest::InitAsFullscreen(
245 RenderWidgetHostView
* reference_host_view
) {
246 // This should never get called.
250 gfx::NativeView
RenderWidgetHostViewGuest::GetNativeView() const {
251 return guest_
->GetEmbedderRenderWidgetHostView()->GetNativeView();
254 gfx::NativeViewId
RenderWidgetHostViewGuest::GetNativeViewId() const {
255 return guest_
->GetEmbedderRenderWidgetHostView()->GetNativeViewId();
258 gfx::NativeViewAccessible
RenderWidgetHostViewGuest::GetNativeViewAccessible() {
259 return guest_
->GetEmbedderRenderWidgetHostView()->GetNativeViewAccessible();
262 void RenderWidgetHostViewGuest::MovePluginWindows(
263 const gfx::Vector2d
& scroll_offset
,
264 const std::vector
<WebPluginGeometry
>& moves
) {
265 platform_view_
->MovePluginWindows(scroll_offset
, moves
);
268 void RenderWidgetHostViewGuest::Focus() {
271 void RenderWidgetHostViewGuest::Blur() {
274 bool RenderWidgetHostViewGuest::HasFocus() const {
278 bool RenderWidgetHostViewGuest::IsSurfaceAvailableForCopy() const {
283 void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor
& cursor
) {
284 platform_view_
->UpdateCursor(cursor
);
287 void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading
) {
288 platform_view_
->SetIsLoading(is_loading
);
291 void RenderWidgetHostViewGuest::TextInputTypeChanged(
292 ui::TextInputType type
,
293 ui::TextInputMode input_mode
,
294 bool can_compose_inline
) {
295 RenderWidgetHostViewPort::FromRWHV(
296 guest_
->GetEmbedderRenderWidgetHostView())->
297 TextInputTypeChanged(type
, input_mode
, can_compose_inline
);
300 void RenderWidgetHostViewGuest::ImeCancelComposition() {
301 platform_view_
->ImeCancelComposition();
304 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
305 void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
306 const gfx::Range
& range
,
307 const std::vector
<gfx::Rect
>& character_bounds
) {
311 void RenderWidgetHostViewGuest::DidUpdateBackingStore(
312 const gfx::Rect
& scroll_rect
,
313 const gfx::Vector2d
& scroll_delta
,
314 const std::vector
<gfx::Rect
>& copy_rects
,
315 const ui::LatencyInfo
& latency_info
) {
319 void RenderWidgetHostViewGuest::SelectionChanged(const string16
& text
,
321 const gfx::Range
& range
) {
322 platform_view_
->SelectionChanged(text
, offset
, range
);
325 void RenderWidgetHostViewGuest::SelectionBoundsChanged(
326 const ViewHostMsg_SelectionBounds_Params
& params
) {
327 platform_view_
->SelectionBoundsChanged(params
);
330 void RenderWidgetHostViewGuest::ScrollOffsetChanged() {
333 BackingStore
* RenderWidgetHostViewGuest::AllocBackingStore(
334 const gfx::Size
& size
) {
339 void RenderWidgetHostViewGuest::CopyFromCompositingSurface(
340 const gfx::Rect
& src_subrect
,
341 const gfx::Size
& /* dst_size */,
342 const base::Callback
<void(bool, const SkBitmap
&)>& callback
) {
343 callback
.Run(false, SkBitmap());
346 void RenderWidgetHostViewGuest::CopyFromCompositingSurfaceToVideoFrame(
347 const gfx::Rect
& src_subrect
,
348 const scoped_refptr
<media::VideoFrame
>& target
,
349 const base::Callback
<void(bool)>& callback
) {
354 bool RenderWidgetHostViewGuest::CanCopyToVideoFrame() const {
358 void RenderWidgetHostViewGuest::AcceleratedSurfaceSuspend() {
362 void RenderWidgetHostViewGuest::AcceleratedSurfaceRelease() {
365 bool RenderWidgetHostViewGuest::HasAcceleratedSurface(
366 const gfx::Size
& desired_size
) {
370 void RenderWidgetHostViewGuest::SetBackground(const SkBitmap
& background
) {
371 platform_view_
->SetBackground(background
);
374 #if defined(OS_WIN) && !defined(USE_AURA)
375 void RenderWidgetHostViewGuest::SetClickthroughRegion(SkRegion
* region
) {
379 void RenderWidgetHostViewGuest::SetHasHorizontalScrollbar(
380 bool has_horizontal_scrollbar
) {
381 platform_view_
->SetHasHorizontalScrollbar(has_horizontal_scrollbar
);
384 void RenderWidgetHostViewGuest::SetScrollOffsetPinning(
385 bool is_pinned_to_left
, bool is_pinned_to_right
) {
386 platform_view_
->SetScrollOffsetPinning(
387 is_pinned_to_left
, is_pinned_to_right
);
390 void RenderWidgetHostViewGuest::OnAcceleratedCompositingStateChange() {
393 bool RenderWidgetHostViewGuest::LockMouse() {
394 return platform_view_
->LockMouse();
397 void RenderWidgetHostViewGuest::UnlockMouse() {
398 return platform_view_
->UnlockMouse();
401 void RenderWidgetHostViewGuest::GetScreenInfo(WebKit::WebScreenInfo
* results
) {
402 RenderWidgetHostViewPort
* embedder_view
=
403 RenderWidgetHostViewPort::FromRWHV(
404 guest_
->GetEmbedderRenderWidgetHostView());
406 embedder_view
->GetScreenInfo(results
);
409 void RenderWidgetHostViewGuest::OnAccessibilityEvents(
410 const std::vector
<AccessibilityHostMsg_EventParams
>& params
) {
413 #if defined(OS_MACOSX)
414 void RenderWidgetHostViewGuest::SetActive(bool active
) {
415 platform_view_
->SetActive(active
);
418 void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag
) {
419 platform_view_
->SetTakesFocusOnlyOnMouseDown(flag
);
422 void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible
) {
423 platform_view_
->SetWindowVisibility(visible
);
426 void RenderWidgetHostViewGuest::WindowFrameChanged() {
427 platform_view_
->WindowFrameChanged();
430 void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
432 gfx::Rect guest_bounds
= GetViewBounds();
433 gfx::Rect embedder_bounds
=
434 guest_
->GetEmbedderRenderWidgetHostView()->GetViewBounds();
436 gfx::Vector2d guest_offset
= gfx::Vector2d(
437 // Horizontal offset of guest from embedder.
438 guest_bounds
.x() - embedder_bounds
.x(),
439 // Vertical offset from guest's top to embedder's bottom edge.
440 embedder_bounds
.bottom() - guest_bounds
.y());
442 RenderWidgetHostViewMacDictionaryHelper
helper(platform_view_
);
443 helper
.SetTargetView(guest_
->GetEmbedderRenderWidgetHostView());
444 helper
.set_offset(guest_offset
);
445 helper
.ShowDefinitionForSelection();
448 bool RenderWidgetHostViewGuest::SupportsSpeech() const {
449 return platform_view_
->SupportsSpeech();
452 void RenderWidgetHostViewGuest::SpeakSelection() {
453 platform_view_
->SpeakSelection();
456 bool RenderWidgetHostViewGuest::IsSpeaking() const {
457 return platform_view_
->IsSpeaking();
460 void RenderWidgetHostViewGuest::StopSpeaking() {
461 platform_view_
->StopSpeaking();
464 void RenderWidgetHostViewGuest::AboutToWaitForBackingStoreMsg() {
468 bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
469 const NativeWebKeyboardEvent
& event
) {
473 #endif // defined(OS_MACOSX)
475 #if defined(OS_ANDROID)
476 void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
477 const gfx::Rect
& target_rect
,
478 const SkBitmap
& zoomed_bitmap
) {
481 void RenderWidgetHostViewGuest::HasTouchEventHandlers(bool need_touch_events
) {
483 #endif // defined(OS_ANDROID)
485 #if defined(TOOLKIT_GTK)
486 GdkEventButton
* RenderWidgetHostViewGuest::GetLastMouseDown() {
490 gfx::NativeView
RenderWidgetHostViewGuest::BuildInputMethodsGtkMenu() {
491 return platform_view_
->BuildInputMethodsGtkMenu();
493 #endif // defined(TOOLKIT_GTK)
495 #if defined(OS_WIN) && !defined(USE_AURA)
496 void RenderWidgetHostViewGuest::WillWmDestroy() {
500 #if defined(OS_WIN) && defined(USE_AURA)
501 void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
502 gfx::NativeViewAccessible accessible_parent
) {
506 void RenderWidgetHostViewGuest::DestroyGuestView() {
507 host_
->SetView(NULL
);
509 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
512 bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
513 ui::GestureConsumer
* consumer
) {
514 CHECK_EQ(static_cast<RenderWidgetHostViewGuest
*>(consumer
), this);
518 void RenderWidgetHostViewGuest::DispatchPostponedGestureEvent(
519 ui::GestureEvent
* event
) {
520 ForwardGestureEventToRenderer(event
);
523 void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
524 ui::TouchEvent
* event
) {
528 WebKit::WebTouchEvent cancel_event
;
529 cancel_event
.type
= WebKit::WebInputEvent::TouchCancel
;
530 cancel_event
.timeStampSeconds
= event
->time_stamp().InSecondsF();
531 host_
->ForwardTouchEventWithLatencyInfo(cancel_event
, *event
->latency());
534 bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
535 ui::GestureEvent
* gesture
) {
536 #if defined(OS_WIN) || defined(USE_AURA)
540 // Pinch gestures are disabled by default on windows desktop. See
541 // crbug.com/128477 and crbug.com/148816
542 if ((gesture
->type() == ui::ET_GESTURE_PINCH_BEGIN
||
543 gesture
->type() == ui::ET_GESTURE_PINCH_UPDATE
||
544 gesture
->type() == ui::ET_GESTURE_PINCH_END
) &&
545 !ShouldSendPinchGesture()) {
549 WebKit::WebGestureEvent web_gesture
=
550 MakeWebGestureEventFromUIEvent(*gesture
);
551 const gfx::Point
& client_point
= gesture
->location();
552 const gfx::Point
& screen_point
= gesture
->location();
554 web_gesture
.x
= client_point
.x();
555 web_gesture
.y
= client_point
.y();
556 web_gesture
.globalX
= screen_point
.x();
557 web_gesture
.globalY
= screen_point
.y();
559 if (web_gesture
.type
== WebKit::WebGestureEvent::Undefined
)
561 if (web_gesture
.type
== WebKit::WebGestureEvent::GestureTapDown
) {
562 host_
->ForwardGestureEvent(
563 CreateFlingCancelEvent(gesture
->time_stamp().InSecondsF()));
565 host_
->ForwardGestureEvent(web_gesture
);
572 void RenderWidgetHostViewGuest::ProcessGestures(
573 ui::GestureRecognizer::Gestures
* gestures
) {
574 if ((gestures
== NULL
) || gestures
->empty())
576 for (ui::GestureRecognizer::Gestures::iterator g_it
= gestures
->begin();
577 g_it
!= gestures
->end();
579 ForwardGestureEventToRenderer(*g_it
);
584 } // namespace content