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/input/web_touch_event_traits.h"
16 #include "content/common/view_messages.h"
17 #include "content/common/webplugin_geometry.h"
18 #include "content/public/common/content_switches.h"
19 #include "skia/ext/platform_canvas.h"
20 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
22 #if defined(OS_MACOSX)
23 #import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
27 #include "content/browser/renderer_host/ui_events_helper.h"
35 blink::WebGestureEvent
CreateFlingCancelEvent(double time_stamp
) {
36 blink::WebGestureEvent gesture_event
;
37 gesture_event
.timeStampSeconds
= time_stamp
;
38 gesture_event
.type
= blink::WebGestureEvent::GestureFlingCancel
;
39 gesture_event
.sourceDevice
= blink::WebGestureDeviceTouchscreen
;
42 #endif // defined(USE_AURA)
46 RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
47 RenderWidgetHost
* widget_host
,
48 BrowserPluginGuest
* guest
,
49 base::WeakPtr
<RenderWidgetHostViewBase
> platform_view
)
50 : RenderWidgetHostViewChildFrame(widget_host
),
51 // |guest| is NULL during test.
52 guest_(guest
? guest
->AsWeakPtr() : base::WeakPtr
<BrowserPluginGuest
>()),
53 platform_view_(platform_view
) {
55 gesture_recognizer_
.reset(ui::GestureRecognizer::Create());
56 gesture_recognizer_
->AddGestureEventHelper(this);
57 #endif // defined(USE_AURA)
60 RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
62 gesture_recognizer_
->RemoveGestureEventHelper(this);
63 #endif // defined(USE_AURA)
66 bool RenderWidgetHostViewGuest::OnMessageReceivedFromEmbedder(
67 const IPC::Message
& message
,
68 RenderWidgetHostImpl
* embedder
) {
70 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(RenderWidgetHostViewGuest
, message
,
72 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent
,
74 IPC_MESSAGE_UNHANDLED(handled
= false)
79 void RenderWidgetHostViewGuest::Show() {
80 // If the WebContents associated with us showed an interstitial page in the
81 // beginning, the teardown path might call WasShown() while |host_| is in
82 // the process of destruction. Avoid calling WasShown below in this case.
83 // TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the
84 // first place: http://crbug.com/273089.
86 // |guest_| is NULL during test.
87 if ((guest_
&& guest_
->is_in_destruction()) || !host_
->is_hidden())
89 // Make sure the size of this view matches the size of the WebContentsView.
90 // The two sizes may fall out of sync if we switch RenderWidgetHostViews,
91 // resize, and then switch page, as is the case with interstitial pages.
92 // NOTE: |guest_| is NULL in unit tests.
94 SetSize(guest_
->web_contents()->GetViewBounds().size());
95 host_
->WasShown(ui::LatencyInfo());
98 void RenderWidgetHostViewGuest::Hide() {
99 // |guest_| is NULL during test.
100 if ((guest_
&& guest_
->is_in_destruction()) || host_
->is_hidden())
105 void RenderWidgetHostViewGuest::SetSize(const gfx::Size
& size
) {
110 void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect
& rect
) {
111 SetSize(rect
.size());
114 void RenderWidgetHostViewGuest::Focus() {
115 // InterstitialPageImpl focuses views directly, so we place focus logic here.
116 // InterstitialPages are not WebContents, and so BrowserPluginGuest does not
117 // have direct access to the interstitial page's RenderWidgetHost.
119 guest_
->SetFocus(host_
, true, blink::WebFocusTypeNone
);
122 bool RenderWidgetHostViewGuest::HasFocus() const {
125 return guest_
->focused();
128 #if defined(USE_AURA)
129 void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
130 const TouchEventWithLatencyInfo
& touch
, InputEventAckState ack_result
) {
131 // TODO(fsamuel): Currently we will only take this codepath if the guest has
132 // requested touch events. A better solution is to always forward touchpresses
133 // to the embedder process to target a BrowserPlugin, and then route all
134 // subsequent touch points of that touchdown to the appropriate guest until
135 // that touch point is released.
136 ScopedVector
<ui::TouchEvent
> events
;
137 if (!MakeUITouchEventsFromWebTouchEvents(touch
, &events
, LOCAL_COORDINATES
))
140 ui::EventResult result
= (ack_result
==
141 INPUT_EVENT_ACK_STATE_CONSUMED
) ? ui::ER_HANDLED
: ui::ER_UNHANDLED
;
142 for (ScopedVector
<ui::TouchEvent
>::iterator iter
= events
.begin(),
143 end
= events
.end(); iter
!= end
; ++iter
) {
144 if (!gesture_recognizer_
->ProcessTouchEventPreDispatch(*iter
, this))
147 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
148 gestures
.reset(gesture_recognizer_
->AckSyncTouchEvent(
149 (*iter
)->unique_event_id(), result
, this));
150 ProcessGestures(gestures
.get());
155 gfx::Rect
RenderWidgetHostViewGuest::GetViewBounds() const {
159 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
160 gfx::Rect embedder_bounds
;
162 embedder_bounds
= rwhv
->GetViewBounds();
164 guest_
->GetScreenCoordinates(embedder_bounds
.origin()), size_
);
167 void RenderWidgetHostViewGuest::RenderProcessGone(
168 base::TerminationStatus status
,
170 platform_view_
->RenderProcessGone(status
, error_code
);
171 // Destroy the guest view instance only, so we don't end up calling
172 // platform_view_->Destroy().
176 void RenderWidgetHostViewGuest::Destroy() {
177 // The RenderWidgetHost's destruction led here, so don't call it.
180 if (platform_view_
) // The platform view might have been destroyed already.
181 platform_view_
->Destroy();
184 gfx::Size
RenderWidgetHostViewGuest::GetPhysicalBackingSize() const {
185 return RenderWidgetHostViewBase::GetPhysicalBackingSize();
188 base::string16
RenderWidgetHostViewGuest::GetSelectedText() const {
189 return platform_view_
->GetSelectedText();
192 void RenderWidgetHostViewGuest::SetTooltipText(
193 const base::string16
& tooltip_text
) {
195 guest_
->SetTooltipText(tooltip_text
);
198 void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
199 uint32 output_surface_id
,
200 scoped_ptr
<cc::CompositorFrame
> frame
) {
204 last_scroll_offset_
= frame
->metadata
.root_scroll_offset
;
205 guest_
->SwapCompositorFrame(output_surface_id
,
206 host_
->GetProcess()->GetID(),
207 host_
->GetRoutingID(),
211 bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message
& msg
) {
212 return platform_view_
->OnMessageReceived(msg
);
215 void RenderWidgetHostViewGuest::InitAsChild(
216 gfx::NativeView parent_view
) {
217 platform_view_
->InitAsChild(parent_view
);
220 void RenderWidgetHostViewGuest::InitAsPopup(
221 RenderWidgetHostView
* parent_host_view
, const gfx::Rect
& bounds
) {
222 // This should never get called.
226 void RenderWidgetHostViewGuest::InitAsFullscreen(
227 RenderWidgetHostView
* reference_host_view
) {
228 // This should never get called.
232 gfx::NativeView
RenderWidgetHostViewGuest::GetNativeView() const {
234 return gfx::NativeView();
236 RenderWidgetHostView
* rwhv
= guest_
->GetOwnerRenderWidgetHostView();
238 return gfx::NativeView();
239 return rwhv
->GetNativeView();
242 gfx::NativeViewId
RenderWidgetHostViewGuest::GetNativeViewId() const {
244 return static_cast<gfx::NativeViewId
>(NULL
);
246 RenderWidgetHostView
* rwhv
= guest_
->GetOwnerRenderWidgetHostView();
248 return static_cast<gfx::NativeViewId
>(NULL
);
249 return rwhv
->GetNativeViewId();
252 gfx::NativeViewAccessible
RenderWidgetHostViewGuest::GetNativeViewAccessible() {
254 return gfx::NativeViewAccessible();
256 RenderWidgetHostView
* rwhv
= guest_
->GetOwnerRenderWidgetHostView();
258 return gfx::NativeViewAccessible();
259 return rwhv
->GetNativeViewAccessible();
262 void RenderWidgetHostViewGuest::MovePluginWindows(
263 const std::vector
<WebPluginGeometry
>& moves
) {
264 platform_view_
->MovePluginWindows(moves
);
267 void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor
& cursor
) {
268 // InterstitialPages are not WebContents so we cannot intercept
269 // ViewHostMsg_SetCursor for interstitial pages in BrowserPluginGuest.
270 // All guest RenderViewHosts have RenderWidgetHostViewGuests however,
271 // and so we will always hit this code path.
274 guest_
->SendMessageToEmbedder(
275 new BrowserPluginMsg_SetCursor(guest_
->browser_plugin_instance_id(),
280 void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading
) {
281 platform_view_
->SetIsLoading(is_loading
);
284 void RenderWidgetHostViewGuest::TextInputTypeChanged(
285 ui::TextInputType type
,
286 ui::TextInputMode input_mode
,
287 bool can_compose_inline
,
292 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
295 // Forward the information to embedding RWHV.
296 rwhv
->TextInputTypeChanged(type
, input_mode
, can_compose_inline
, flags
);
299 void RenderWidgetHostViewGuest::ImeCancelComposition() {
303 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
306 // Forward the information to embedding RWHV.
307 rwhv
->ImeCancelComposition();
310 #if defined(OS_MACOSX) || defined(USE_AURA)
311 void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
312 const gfx::Range
& range
,
313 const std::vector
<gfx::Rect
>& character_bounds
) {
317 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
320 std::vector
<gfx::Rect
> guest_character_bounds
;
321 for (size_t i
= 0; i
< character_bounds
.size(); ++i
) {
322 guest_character_bounds
.push_back(gfx::Rect(
323 guest_
->GetScreenCoordinates(character_bounds
[i
].origin()),
324 character_bounds
[i
].size()));
326 // Forward the information to embedding RWHV.
327 rwhv
->ImeCompositionRangeChanged(range
, guest_character_bounds
);
331 void RenderWidgetHostViewGuest::SelectionChanged(const base::string16
& text
,
333 const gfx::Range
& range
) {
334 platform_view_
->SelectionChanged(text
, offset
, range
);
337 void RenderWidgetHostViewGuest::SelectionBoundsChanged(
338 const ViewHostMsg_SelectionBounds_Params
& params
) {
342 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
345 ViewHostMsg_SelectionBounds_Params
guest_params(params
);
346 guest_params
.anchor_rect
.set_origin(
347 guest_
->GetScreenCoordinates(params
.anchor_rect
.origin()));
348 guest_params
.focus_rect
.set_origin(
349 guest_
->GetScreenCoordinates(params
.focus_rect
.origin()));
350 rwhv
->SelectionBoundsChanged(guest_params
);
353 void RenderWidgetHostViewGuest::SetBackgroundColor(SkColor color
) {
354 // Content embedders can toggle opaque backgrounds through this API.
355 // We plumb the value here so that BrowserPlugin updates its compositing
356 // state in response to this change. We also want to preserve this flag
357 // after recovering from a crash so we let BrowserPluginGuest store it.
360 RenderWidgetHostViewBase::SetBackgroundColor(color
);
361 bool opaque
= GetBackgroundOpaque();
362 host_
->SetBackgroundOpaque(opaque
);
363 guest_
->SetContentsOpaque(opaque
);
366 bool RenderWidgetHostViewGuest::LockMouse() {
367 return platform_view_
->LockMouse();
370 void RenderWidgetHostViewGuest::UnlockMouse() {
371 return platform_view_
->UnlockMouse();
374 void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo
* results
) {
377 RenderWidgetHostViewBase
* embedder_view
= GetOwnerRenderWidgetHostView();
379 embedder_view
->GetScreenInfo(results
);
382 #if defined(OS_MACOSX)
383 void RenderWidgetHostViewGuest::SetActive(bool active
) {
384 platform_view_
->SetActive(active
);
387 void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible
) {
388 platform_view_
->SetWindowVisibility(visible
);
391 void RenderWidgetHostViewGuest::WindowFrameChanged() {
392 platform_view_
->WindowFrameChanged();
395 void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
400 gfx::Rect guest_bounds
= GetViewBounds();
401 RenderWidgetHostView
* rwhv
= guest_
->GetOwnerRenderWidgetHostView();
402 gfx::Rect embedder_bounds
;
404 embedder_bounds
= rwhv
->GetViewBounds();
406 gfx::Vector2d guest_offset
= gfx::Vector2d(
407 // Horizontal offset of guest from embedder.
408 guest_bounds
.x() - embedder_bounds
.x(),
409 // Vertical offset from guest's top to embedder's bottom edge.
410 embedder_bounds
.bottom() - guest_bounds
.y());
412 RenderWidgetHostViewMacDictionaryHelper
helper(platform_view_
.get());
413 helper
.SetTargetView(rwhv
);
414 helper
.set_offset(guest_offset
);
415 helper
.ShowDefinitionForSelection();
418 bool RenderWidgetHostViewGuest::SupportsSpeech() const {
419 return platform_view_
->SupportsSpeech();
422 void RenderWidgetHostViewGuest::SpeakSelection() {
423 platform_view_
->SpeakSelection();
426 bool RenderWidgetHostViewGuest::IsSpeaking() const {
427 return platform_view_
->IsSpeaking();
430 void RenderWidgetHostViewGuest::StopSpeaking() {
431 platform_view_
->StopSpeaking();
434 bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
435 const NativeWebKeyboardEvent
& event
) {
439 #endif // defined(OS_MACOSX)
441 #if defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
442 void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
443 const gfx::Rect
& rect_pixels
,
444 const SkBitmap
& zoomed_bitmap
) {
446 #endif // defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
448 #if defined(OS_ANDROID)
449 void RenderWidgetHostViewGuest::LockCompositingSurface() {
452 void RenderWidgetHostViewGuest::UnlockCompositingSurface() {
454 #endif // defined(OS_ANDROID)
457 void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
458 gfx::NativeViewAccessible accessible_parent
) {
461 gfx::NativeViewId
RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
467 void RenderWidgetHostViewGuest::DestroyGuestView() {
468 host_
->SetView(NULL
);
470 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
473 bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
474 ui::GestureConsumer
* consumer
) {
475 CHECK_EQ(static_cast<RenderWidgetHostViewGuest
*>(consumer
), this);
479 void RenderWidgetHostViewGuest::DispatchGestureEvent(
480 ui::GestureEvent
* event
) {
481 ForwardGestureEventToRenderer(event
);
484 void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
485 ui::TouchEvent
* event
) {
489 blink::WebTouchEvent cancel_event
;
490 // TODO(rbyers): This event has no touches in it. Don't we need to know what
491 // touches are currently active in order to cancel them all properly?
492 WebTouchEventTraits::ResetType(blink::WebInputEvent::TouchCancel
,
493 event
->time_stamp().InSecondsF(),
496 host_
->ForwardTouchEventWithLatencyInfo(cancel_event
, *event
->latency());
499 bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
500 ui::GestureEvent
* gesture
) {
501 #if defined(USE_AURA)
505 if ((gesture
->type() == ui::ET_GESTURE_PINCH_BEGIN
||
506 gesture
->type() == ui::ET_GESTURE_PINCH_UPDATE
||
507 gesture
->type() == ui::ET_GESTURE_PINCH_END
) && !pinch_zoom_enabled_
) {
511 blink::WebGestureEvent web_gesture
=
512 MakeWebGestureEventFromUIEvent(*gesture
);
513 const gfx::Point
& client_point
= gesture
->location();
514 const gfx::Point
& screen_point
= gesture
->location();
516 web_gesture
.x
= client_point
.x();
517 web_gesture
.y
= client_point
.y();
518 web_gesture
.globalX
= screen_point
.x();
519 web_gesture
.globalY
= screen_point
.y();
521 if (web_gesture
.type
== blink::WebGestureEvent::Undefined
)
523 if (web_gesture
.type
== blink::WebGestureEvent::GestureTapDown
) {
524 host_
->ForwardGestureEvent(
525 CreateFlingCancelEvent(gesture
->time_stamp().InSecondsF()));
527 host_
->ForwardGestureEvent(web_gesture
);
534 void RenderWidgetHostViewGuest::ProcessGestures(
535 ui::GestureRecognizer::Gestures
* gestures
) {
536 if ((gestures
== NULL
) || gestures
->empty())
538 for (ui::GestureRecognizer::Gestures::iterator g_it
= gestures
->begin();
539 g_it
!= gestures
->end();
541 ForwardGestureEventToRenderer(*g_it
);
545 SkColorType
RenderWidgetHostViewGuest::PreferredReadbackFormat() {
546 return kN32_SkColorType
;
549 RenderWidgetHostViewBase
*
550 RenderWidgetHostViewGuest::GetOwnerRenderWidgetHostView() const {
551 return static_cast<RenderWidgetHostViewBase
*>(
552 guest_
->GetOwnerRenderWidgetHostView());
555 void RenderWidgetHostViewGuest::OnHandleInputEvent(
556 RenderWidgetHostImpl
* embedder
,
557 int browser_plugin_instance_id
,
558 const gfx::Rect
& guest_window_rect
,
559 const blink::WebInputEvent
* event
) {
560 if (blink::WebInputEvent::isMouseEventType(event
->type
)) {
561 host_
->ForwardMouseEvent(
562 *static_cast<const blink::WebMouseEvent
*>(event
));
566 if (event
->type
== blink::WebInputEvent::MouseWheel
) {
567 host_
->ForwardWheelEvent(
568 *static_cast<const blink::WebMouseWheelEvent
*>(event
));
572 if (blink::WebInputEvent::isKeyboardEventType(event
->type
)) {
573 if (!embedder
->GetLastKeyboardEvent())
575 NativeWebKeyboardEvent
keyboard_event(*embedder
->GetLastKeyboardEvent());
576 host_
->ForwardKeyboardEvent(keyboard_event
);
580 if (blink::WebInputEvent::isTouchEventType(event
->type
)) {
581 host_
->ForwardTouchEventWithLatencyInfo(
582 *static_cast<const blink::WebTouchEvent
*>(event
),
587 if (blink::WebInputEvent::isGestureEventType(event
->type
)) {
588 host_
->ForwardGestureEvent(
589 *static_cast<const blink::WebGestureEvent
*>(event
));
594 } // namespace content