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 "cc/surfaces/surface.h"
10 #include "cc/surfaces/surface_factory.h"
11 #include "cc/surfaces/surface_manager.h"
12 #include "cc/surfaces/surface_sequence.h"
13 #include "content/browser/browser_plugin/browser_plugin_guest.h"
14 #include "content/browser/compositor/surface_utils.h"
15 #include "content/browser/frame_host/render_widget_host_view_guest.h"
16 #include "content/browser/renderer_host/render_view_host_impl.h"
17 #include "content/common/browser_plugin/browser_plugin_messages.h"
18 #include "content/common/frame_messages.h"
19 #include "content/common/gpu/gpu_messages.h"
20 #include "content/common/input/web_touch_event_traits.h"
21 #include "content/common/view_messages.h"
22 #include "content/common/webplugin_geometry.h"
23 #include "content/public/common/content_switches.h"
24 #include "skia/ext/platform_canvas.h"
25 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
27 #if defined(OS_MACOSX)
28 #import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
32 #include "content/browser/renderer_host/ui_events_helper.h"
40 blink::WebGestureEvent
CreateFlingCancelEvent(double time_stamp
) {
41 blink::WebGestureEvent gesture_event
;
42 gesture_event
.timeStampSeconds
= time_stamp
;
43 gesture_event
.type
= blink::WebGestureEvent::GestureFlingCancel
;
44 gesture_event
.sourceDevice
= blink::WebGestureDeviceTouchscreen
;
47 #endif // defined(USE_AURA)
51 RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
52 RenderWidgetHost
* widget_host
,
53 BrowserPluginGuest
* guest
,
54 base::WeakPtr
<RenderWidgetHostViewBase
> platform_view
)
55 : RenderWidgetHostViewChildFrame(widget_host
),
56 // |guest| is NULL during test.
57 guest_(guest
? guest
->AsWeakPtr() : base::WeakPtr
<BrowserPluginGuest
>()),
58 platform_view_(platform_view
) {
60 gesture_recognizer_
.reset(ui::GestureRecognizer::Create());
61 gesture_recognizer_
->AddGestureEventHelper(this);
62 #endif // defined(USE_AURA)
65 RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
67 gesture_recognizer_
->RemoveGestureEventHelper(this);
68 #endif // defined(USE_AURA)
71 bool RenderWidgetHostViewGuest::OnMessageReceivedFromEmbedder(
72 const IPC::Message
& message
,
73 RenderWidgetHostImpl
* embedder
) {
75 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(RenderWidgetHostViewGuest
, message
,
77 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent
,
79 IPC_MESSAGE_UNHANDLED(handled
= false)
84 void RenderWidgetHostViewGuest::Show() {
85 // If the WebContents associated with us showed an interstitial page in the
86 // beginning, the teardown path might call WasShown() while |host_| is in
87 // the process of destruction. Avoid calling WasShown below in this case.
88 // TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the
89 // first place: http://crbug.com/273089.
91 // |guest_| is NULL during test.
92 if ((guest_
&& guest_
->is_in_destruction()) || !host_
->is_hidden())
94 // Make sure the size of this view matches the size of the WebContentsView.
95 // The two sizes may fall out of sync if we switch RenderWidgetHostViews,
96 // resize, and then switch page, as is the case with interstitial pages.
97 // NOTE: |guest_| is NULL in unit tests.
99 SetSize(guest_
->web_contents()->GetViewBounds().size());
100 host_
->WasShown(ui::LatencyInfo());
103 void RenderWidgetHostViewGuest::Hide() {
104 // |guest_| is NULL during test.
105 if ((guest_
&& guest_
->is_in_destruction()) || host_
->is_hidden())
110 void RenderWidgetHostViewGuest::SetSize(const gfx::Size
& size
) {
115 void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect
& rect
) {
116 SetSize(rect
.size());
119 void RenderWidgetHostViewGuest::Focus() {
120 // InterstitialPageImpl focuses views directly, so we place focus logic here.
121 // InterstitialPages are not WebContents, and so BrowserPluginGuest does not
122 // have direct access to the interstitial page's RenderWidgetHost.
124 guest_
->SetFocus(host_
, true, blink::WebFocusTypeNone
);
127 bool RenderWidgetHostViewGuest::HasFocus() const {
130 return guest_
->focused();
133 #if defined(USE_AURA)
134 void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
135 const TouchEventWithLatencyInfo
& touch
, InputEventAckState ack_result
) {
136 // TODO(fsamuel): Currently we will only take this codepath if the guest has
137 // requested touch events. A better solution is to always forward touchpresses
138 // to the embedder process to target a BrowserPlugin, and then route all
139 // subsequent touch points of that touchdown to the appropriate guest until
140 // that touch point is released.
141 ScopedVector
<ui::TouchEvent
> events
;
142 if (!MakeUITouchEventsFromWebTouchEvents(touch
, &events
, LOCAL_COORDINATES
))
145 ui::EventResult result
= (ack_result
==
146 INPUT_EVENT_ACK_STATE_CONSUMED
) ? ui::ER_HANDLED
: ui::ER_UNHANDLED
;
147 for (ScopedVector
<ui::TouchEvent
>::iterator iter
= events
.begin(),
148 end
= events
.end(); iter
!= end
; ++iter
) {
149 if (!gesture_recognizer_
->ProcessTouchEventPreDispatch(*iter
, this))
152 scoped_ptr
<ui::GestureRecognizer::Gestures
> gestures
;
153 gestures
.reset(gesture_recognizer_
->AckTouchEvent(
154 (*iter
)->unique_event_id(), result
, this));
155 ProcessGestures(gestures
.get());
160 gfx::Rect
RenderWidgetHostViewGuest::GetViewBounds() const {
164 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
165 gfx::Rect embedder_bounds
;
167 embedder_bounds
= rwhv
->GetViewBounds();
169 guest_
->GetScreenCoordinates(embedder_bounds
.origin()), size_
);
172 void RenderWidgetHostViewGuest::RenderProcessGone(
173 base::TerminationStatus status
,
175 // The |platform_view_| gets destroyed before we get here if this view
176 // is for an InterstitialPage.
178 platform_view_
->RenderProcessGone(status
, error_code
);
180 // Destroy the guest view instance only, so we don't end up calling
181 // platform_view_->Destroy().
185 void RenderWidgetHostViewGuest::Destroy() {
186 // The RenderWidgetHost's destruction led here, so don't call it.
189 if (platform_view_
) // The platform view might have been destroyed already.
190 platform_view_
->Destroy();
193 gfx::Size
RenderWidgetHostViewGuest::GetPhysicalBackingSize() const {
194 return RenderWidgetHostViewBase::GetPhysicalBackingSize();
197 base::string16
RenderWidgetHostViewGuest::GetSelectedText() const {
198 return platform_view_
->GetSelectedText();
201 void RenderWidgetHostViewGuest::SetTooltipText(
202 const base::string16
& tooltip_text
) {
204 guest_
->SetTooltipText(tooltip_text
);
207 void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
208 uint32 output_surface_id
,
209 scoped_ptr
<cc::CompositorFrame
> frame
) {
210 if (!guest_
|| !guest_
->attached()) {
211 // We shouldn't hang on to a surface while we are detached.
212 ClearCompositorSurfaceIfNecessary();
216 last_scroll_offset_
= frame
->metadata
.root_scroll_offset
;
217 // When not using surfaces, the frame just gets proxied to
218 // the embedder's renderer to be composited.
219 if (!frame
->delegated_frame_data
|| !use_surfaces_
) {
220 guest_
->SwapCompositorFrame(output_surface_id
,
221 host_
->GetProcess()->GetID(),
222 host_
->GetRoutingID(),
227 cc::RenderPass
* root_pass
=
228 frame
->delegated_frame_data
->render_pass_list
.back();
230 gfx::Size frame_size
= root_pass
->output_rect
.size();
231 float scale_factor
= frame
->metadata
.device_scale_factor
;
233 guest_
->UpdateGuestSizeIfNecessary(frame_size
, scale_factor
);
235 // Check whether we need to recreate the cc::Surface, which means the child
236 // frame renderer has changed its output surface, or size, or scale factor.
237 if (output_surface_id
!= last_output_surface_id_
&& surface_factory_
) {
238 surface_factory_
->Destroy(surface_id_
);
239 surface_factory_
.reset();
241 if (output_surface_id
!= last_output_surface_id_
||
242 frame_size
!= current_surface_size_
||
243 scale_factor
!= current_surface_scale_factor_
||
244 guest_
->has_attached_since_surface_set()) {
245 ClearCompositorSurfaceIfNecessary();
246 last_output_surface_id_
= output_surface_id
;
247 current_surface_size_
= frame_size
;
248 current_surface_scale_factor_
= scale_factor
;
251 if (!surface_factory_
) {
252 cc::SurfaceManager
* manager
= GetSurfaceManager();
253 surface_factory_
= make_scoped_ptr(new cc::SurfaceFactory(manager
, this));
256 if (surface_id_
.is_null()) {
257 surface_id_
= id_allocator_
->GenerateId();
258 surface_factory_
->Create(surface_id_
);
260 cc::SurfaceSequence sequence
= cc::SurfaceSequence(
261 id_allocator_
->id_namespace(), next_surface_sequence_
++);
262 // The renderer process will satisfy this dependency when it creates a
264 cc::SurfaceManager
* manager
= GetSurfaceManager();
265 manager
->GetSurfaceForId(surface_id_
)->AddDestructionDependency(sequence
);
266 guest_
->SetChildFrameSurface(surface_id_
, frame_size
, scale_factor
,
270 cc::SurfaceFactory::DrawCallback ack_callback
= base::Bind(
271 &RenderWidgetHostViewChildFrame::SurfaceDrawn
,
272 RenderWidgetHostViewChildFrame::AsWeakPtr(), output_surface_id
);
273 ack_pending_count_
++;
274 // If this value grows very large, something is going wrong.
275 DCHECK(ack_pending_count_
< 1000);
276 surface_factory_
->SubmitFrame(surface_id_
, frame
.Pass(), ack_callback
);
279 bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message
& msg
) {
280 if (!platform_view_
) {
281 // In theory, we can get here if there's a delay between DestroyGuestView()
282 // being called and when our destructor is invoked.
286 return platform_view_
->OnMessageReceived(msg
);
289 void RenderWidgetHostViewGuest::InitAsChild(
290 gfx::NativeView parent_view
) {
291 platform_view_
->InitAsChild(parent_view
);
294 void RenderWidgetHostViewGuest::InitAsPopup(
295 RenderWidgetHostView
* parent_host_view
, const gfx::Rect
& bounds
) {
296 // This should never get called.
300 void RenderWidgetHostViewGuest::InitAsFullscreen(
301 RenderWidgetHostView
* reference_host_view
) {
302 // This should never get called.
306 gfx::NativeView
RenderWidgetHostViewGuest::GetNativeView() const {
308 return gfx::NativeView();
310 RenderWidgetHostView
* rwhv
= guest_
->GetOwnerRenderWidgetHostView();
312 return gfx::NativeView();
313 return rwhv
->GetNativeView();
316 gfx::NativeViewId
RenderWidgetHostViewGuest::GetNativeViewId() const {
318 return static_cast<gfx::NativeViewId
>(NULL
);
320 RenderWidgetHostView
* rwhv
= guest_
->GetOwnerRenderWidgetHostView();
322 return static_cast<gfx::NativeViewId
>(NULL
);
323 return rwhv
->GetNativeViewId();
326 gfx::NativeViewAccessible
RenderWidgetHostViewGuest::GetNativeViewAccessible() {
328 return gfx::NativeViewAccessible();
330 RenderWidgetHostView
* rwhv
= guest_
->GetOwnerRenderWidgetHostView();
332 return gfx::NativeViewAccessible();
333 return rwhv
->GetNativeViewAccessible();
336 void RenderWidgetHostViewGuest::MovePluginWindows(
337 const std::vector
<WebPluginGeometry
>& moves
) {
338 platform_view_
->MovePluginWindows(moves
);
341 void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor
& cursor
) {
342 // InterstitialPages are not WebContents so we cannot intercept
343 // ViewHostMsg_SetCursor for interstitial pages in BrowserPluginGuest.
344 // All guest RenderViewHosts have RenderWidgetHostViewGuests however,
345 // and so we will always hit this code path.
348 guest_
->SendMessageToEmbedder(
349 new BrowserPluginMsg_SetCursor(guest_
->browser_plugin_instance_id(),
354 void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading
) {
355 platform_view_
->SetIsLoading(is_loading
);
358 void RenderWidgetHostViewGuest::TextInputTypeChanged(
359 ui::TextInputType type
,
360 ui::TextInputMode input_mode
,
361 bool can_compose_inline
,
366 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
369 // Forward the information to embedding RWHV.
370 rwhv
->TextInputTypeChanged(type
, input_mode
, can_compose_inline
, flags
);
373 void RenderWidgetHostViewGuest::ImeCancelComposition() {
377 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
380 // Forward the information to embedding RWHV.
381 rwhv
->ImeCancelComposition();
384 #if defined(OS_MACOSX) || defined(USE_AURA)
385 void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
386 const gfx::Range
& range
,
387 const std::vector
<gfx::Rect
>& character_bounds
) {
391 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
394 std::vector
<gfx::Rect
> guest_character_bounds
;
395 for (size_t i
= 0; i
< character_bounds
.size(); ++i
) {
396 guest_character_bounds
.push_back(gfx::Rect(
397 guest_
->GetScreenCoordinates(character_bounds
[i
].origin()),
398 character_bounds
[i
].size()));
400 // Forward the information to embedding RWHV.
401 rwhv
->ImeCompositionRangeChanged(range
, guest_character_bounds
);
405 void RenderWidgetHostViewGuest::SelectionChanged(const base::string16
& text
,
407 const gfx::Range
& range
) {
408 platform_view_
->SelectionChanged(text
, offset
, range
);
411 void RenderWidgetHostViewGuest::SelectionBoundsChanged(
412 const ViewHostMsg_SelectionBounds_Params
& params
) {
416 RenderWidgetHostViewBase
* rwhv
= GetOwnerRenderWidgetHostView();
419 ViewHostMsg_SelectionBounds_Params
guest_params(params
);
420 guest_params
.anchor_rect
.set_origin(
421 guest_
->GetScreenCoordinates(params
.anchor_rect
.origin()));
422 guest_params
.focus_rect
.set_origin(
423 guest_
->GetScreenCoordinates(params
.focus_rect
.origin()));
424 rwhv
->SelectionBoundsChanged(guest_params
);
427 void RenderWidgetHostViewGuest::SetBackgroundColor(SkColor color
) {
428 // Content embedders can toggle opaque backgrounds through this API.
429 // We plumb the value here so that BrowserPlugin updates its compositing
430 // state in response to this change. We also want to preserve this flag
431 // after recovering from a crash so we let BrowserPluginGuest store it.
434 RenderWidgetHostViewBase::SetBackgroundColor(color
);
435 bool opaque
= GetBackgroundOpaque();
436 host_
->SetBackgroundOpaque(opaque
);
437 guest_
->SetContentsOpaque(opaque
);
440 bool RenderWidgetHostViewGuest::LockMouse() {
441 return platform_view_
->LockMouse();
444 void RenderWidgetHostViewGuest::UnlockMouse() {
445 return platform_view_
->UnlockMouse();
448 void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo
* results
) {
451 RenderWidgetHostViewBase
* embedder_view
= GetOwnerRenderWidgetHostView();
453 embedder_view
->GetScreenInfo(results
);
456 #if defined(OS_MACOSX)
457 void RenderWidgetHostViewGuest::SetActive(bool active
) {
458 platform_view_
->SetActive(active
);
461 void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible
) {
462 platform_view_
->SetWindowVisibility(visible
);
465 void RenderWidgetHostViewGuest::WindowFrameChanged() {
466 platform_view_
->WindowFrameChanged();
469 void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
474 gfx::Rect guest_bounds
= GetViewBounds();
475 RenderWidgetHostView
* rwhv
= guest_
->GetOwnerRenderWidgetHostView();
476 gfx::Rect embedder_bounds
;
478 embedder_bounds
= rwhv
->GetViewBounds();
480 gfx::Vector2d guest_offset
= gfx::Vector2d(
481 // Horizontal offset of guest from embedder.
482 guest_bounds
.x() - embedder_bounds
.x(),
483 // Vertical offset from guest's top to embedder's bottom edge.
484 embedder_bounds
.bottom() - guest_bounds
.y());
486 RenderWidgetHostViewMacDictionaryHelper
helper(platform_view_
.get());
487 helper
.SetTargetView(rwhv
);
488 helper
.set_offset(guest_offset
);
489 helper
.ShowDefinitionForSelection();
492 bool RenderWidgetHostViewGuest::SupportsSpeech() const {
493 return platform_view_
->SupportsSpeech();
496 void RenderWidgetHostViewGuest::SpeakSelection() {
497 platform_view_
->SpeakSelection();
500 bool RenderWidgetHostViewGuest::IsSpeaking() const {
501 return platform_view_
->IsSpeaking();
504 void RenderWidgetHostViewGuest::StopSpeaking() {
505 platform_view_
->StopSpeaking();
508 bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
509 const NativeWebKeyboardEvent
& event
) {
513 #endif // defined(OS_MACOSX)
515 #if defined(OS_ANDROID) || defined(USE_AURA)
516 void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
517 const gfx::Rect
& rect_pixels
,
518 const SkBitmap
& zoomed_bitmap
) {
520 #endif // defined(OS_ANDROID) || defined(USE_AURA)
522 #if defined(OS_ANDROID)
523 void RenderWidgetHostViewGuest::LockCompositingSurface() {
526 void RenderWidgetHostViewGuest::UnlockCompositingSurface() {
528 #endif // defined(OS_ANDROID)
531 void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
532 gfx::NativeViewAccessible accessible_parent
) {
535 gfx::NativeViewId
RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
541 void RenderWidgetHostViewGuest::DestroyGuestView() {
542 host_
->SetView(NULL
);
544 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
547 bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
548 ui::GestureConsumer
* consumer
) {
549 CHECK_EQ(static_cast<RenderWidgetHostViewGuest
*>(consumer
), this);
553 void RenderWidgetHostViewGuest::DispatchGestureEvent(
554 ui::GestureEvent
* event
) {
555 ForwardGestureEventToRenderer(event
);
558 void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
559 ui::TouchEvent
* event
) {
563 blink::WebTouchEvent cancel_event
;
564 // TODO(rbyers): This event has no touches in it. Don't we need to know what
565 // touches are currently active in order to cancel them all properly?
566 WebTouchEventTraits::ResetType(blink::WebInputEvent::TouchCancel
,
567 event
->time_stamp().InSecondsF(),
570 host_
->ForwardTouchEventWithLatencyInfo(cancel_event
, *event
->latency());
573 bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
574 ui::GestureEvent
* gesture
) {
575 #if defined(USE_AURA)
579 if ((gesture
->type() == ui::ET_GESTURE_PINCH_BEGIN
||
580 gesture
->type() == ui::ET_GESTURE_PINCH_UPDATE
||
581 gesture
->type() == ui::ET_GESTURE_PINCH_END
) && !pinch_zoom_enabled_
) {
585 blink::WebGestureEvent web_gesture
=
586 MakeWebGestureEventFromUIEvent(*gesture
);
587 const gfx::Point
& client_point
= gesture
->location();
588 const gfx::Point
& screen_point
= gesture
->location();
590 web_gesture
.x
= client_point
.x();
591 web_gesture
.y
= client_point
.y();
592 web_gesture
.globalX
= screen_point
.x();
593 web_gesture
.globalY
= screen_point
.y();
595 if (web_gesture
.type
== blink::WebGestureEvent::Undefined
)
597 if (web_gesture
.type
== blink::WebGestureEvent::GestureTapDown
) {
598 host_
->ForwardGestureEvent(
599 CreateFlingCancelEvent(gesture
->time_stamp().InSecondsF()));
601 host_
->ForwardGestureEvent(web_gesture
);
608 void RenderWidgetHostViewGuest::ProcessGestures(
609 ui::GestureRecognizer::Gestures
* gestures
) {
610 if ((gestures
== NULL
) || gestures
->empty())
612 for (ui::GestureRecognizer::Gestures::iterator g_it
= gestures
->begin();
613 g_it
!= gestures
->end();
615 ForwardGestureEventToRenderer(*g_it
);
619 RenderWidgetHostViewBase
*
620 RenderWidgetHostViewGuest::GetOwnerRenderWidgetHostView() const {
621 return static_cast<RenderWidgetHostViewBase
*>(
622 guest_
->GetOwnerRenderWidgetHostView());
625 void RenderWidgetHostViewGuest::OnHandleInputEvent(
626 RenderWidgetHostImpl
* embedder
,
627 int browser_plugin_instance_id
,
628 const gfx::Rect
& guest_window_rect
,
629 const blink::WebInputEvent
* event
) {
630 if (blink::WebInputEvent::isMouseEventType(event
->type
)) {
631 host_
->ForwardMouseEvent(
632 *static_cast<const blink::WebMouseEvent
*>(event
));
636 if (event
->type
== blink::WebInputEvent::MouseWheel
) {
637 host_
->ForwardWheelEvent(
638 *static_cast<const blink::WebMouseWheelEvent
*>(event
));
642 if (blink::WebInputEvent::isKeyboardEventType(event
->type
)) {
643 if (!embedder
->GetLastKeyboardEvent())
645 NativeWebKeyboardEvent
keyboard_event(*embedder
->GetLastKeyboardEvent());
646 host_
->ForwardKeyboardEvent(keyboard_event
);
650 if (blink::WebInputEvent::isTouchEventType(event
->type
)) {
651 if (event
->type
== blink::WebInputEvent::TouchStart
&&
652 !embedder
->GetView()->HasFocus()) {
653 embedder
->GetView()->Focus();
656 host_
->ForwardTouchEventWithLatencyInfo(
657 *static_cast<const blink::WebTouchEvent
*>(event
),
662 if (blink::WebInputEvent::isGestureEventType(event
->type
)) {
663 host_
->ForwardGestureEvent(
664 *static_cast<const blink::WebGestureEvent
*>(event
));
669 } // namespace content