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/view_messages.h"
16 #include "content/common/webplugin_geometry.h"
17 #include "content/public/common/content_switches.h"
18 #include "skia/ext/platform_canvas.h"
19 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
21 #if defined(OS_MACOSX)
22 #import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
25 #if defined(OS_WIN) || defined(USE_AURA)
26 #include "content/browser/renderer_host/ui_events_helper.h"
33 #if defined(OS_WIN) || defined(USE_AURA)
34 bool ShouldSendPinchGesture() {
35 static bool pinch_allowed =
36 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePinch);
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::WebGestureEvent::Touchscreen;
47 #endif // defined(OS_WIN) || defined(USE_AURA)
51 RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
52 RenderWidgetHost* widget_host,
53 BrowserPluginGuest* guest,
54 RenderWidgetHostView* platform_view)
55 : RenderWidgetHostViewChildFrame(widget_host),
57 platform_view_(static_cast<RenderWidgetHostViewPort*>(platform_view)) {
58 #if defined(OS_WIN) || defined(USE_AURA)
59 gesture_recognizer_.reset(ui::GestureRecognizer::Create());
60 gesture_recognizer_->AddGestureEventHelper(this);
61 #endif // defined(OS_WIN) || defined(USE_AURA)
64 RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
65 #if defined(OS_WIN) || defined(USE_AURA)
66 gesture_recognizer_->RemoveGestureEventHelper(this);
67 #endif // defined(OS_WIN) || defined(USE_AURA)
70 void RenderWidgetHostViewGuest::WasShown() {
71 // If the WebContents associated with us showed an interstitial page in the
72 // beginning, the teardown path might call WasShown() while |host_| is in
73 // the process of destruction. Avoid calling WasShown below in this case.
74 // TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the
75 // first place: http://crbug.com/273089.
77 // |guest_| is NULL during test.
78 if ((guest_ && guest_->is_in_destruction()) || !host_->is_hidden())
83 void RenderWidgetHostViewGuest::WasHidden() {
84 // |guest_| is NULL during test.
85 if ((guest_ && guest_->is_in_destruction()) || host_->is_hidden())
90 void RenderWidgetHostViewGuest::SetSize(const gfx::Size& size) {
95 void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect& rect) {
99 #if defined(OS_WIN) || defined(USE_AURA)
100 void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
101 const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
102 // TODO(fsamuel): Currently we will only take this codepath if the guest has
103 // requested touch events. A better solution is to always forward touchpresses
104 // to the embedder process to target a BrowserPlugin, and then route all
105 // subsequent touch points of that touchdown to the appropriate guest until
106 // that touch point is released.
107 ScopedVector<ui::TouchEvent> events;
108 if (!MakeUITouchEventsFromWebTouchEvents(touch, &events, LOCAL_COORDINATES))
111 ui::EventResult result = (ack_result ==
112 INPUT_EVENT_ACK_STATE_CONSUMED) ? ui::ER_HANDLED : ui::ER_UNHANDLED;
113 for (ScopedVector<ui::TouchEvent>::iterator iter = events.begin(),
114 end = events.end(); iter != end; ++iter) {
115 scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
116 gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture(
117 *(*iter), result, this));
118 ProcessGestures(gestures.get());
123 gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const {
124 RenderWidgetHostViewPort* rwhv = static_cast<RenderWidgetHostViewPort*>(
125 guest_->GetEmbedderRenderWidgetHostView());
126 gfx::Rect embedder_bounds;
128 embedder_bounds = rwhv->GetViewBounds();
129 gfx::Rect shifted_rect = guest_->ToGuestRect(embedder_bounds);
130 shifted_rect.set_width(size_.width());
131 shifted_rect.set_height(size_.height());
135 void RenderWidgetHostViewGuest::RenderProcessGone(
136 base::TerminationStatus status,
138 platform_view_->RenderProcessGone(status, error_code);
139 // Destroy the guest view instance only, so we don't end up calling
140 // platform_view_->Destroy().
144 void RenderWidgetHostViewGuest::Destroy() {
145 // The RenderWidgetHost's destruction led here, so don't call it.
148 platform_view_->Destroy();
151 gfx::Size RenderWidgetHostViewGuest::GetPhysicalBackingSize() const {
152 return RenderWidgetHostViewBase::GetPhysicalBackingSize();
155 void RenderWidgetHostViewGuest::SetTooltipText(
156 const base::string16& tooltip_text) {
157 platform_view_->SetTooltipText(tooltip_text);
160 void RenderWidgetHostViewGuest::AcceleratedSurfaceBuffersSwapped(
161 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
163 // If accelerated surface buffers are getting swapped then we're not using
164 // the software path.
165 guest_->clear_damage_buffer();
166 FrameMsg_BuffersSwapped_Params guest_params;
167 guest_params.size = params.size;
168 guest_params.mailbox_name = params.mailbox_name;
169 guest_params.gpu_route_id = params.route_id;
170 guest_params.gpu_host_id = gpu_host_id;
171 guest_->SendMessageToEmbedder(
172 new BrowserPluginMsg_BuffersSwapped(guest_->instance_id(),
176 void RenderWidgetHostViewGuest::AcceleratedSurfacePostSubBuffer(
177 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
182 void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
183 uint32 output_surface_id,
184 scoped_ptr<cc::CompositorFrame> frame) {
185 guest_->clear_damage_buffer();
187 if (!guest_->attached()) {
188 // If the guest doesn't have an embedder then there's nothing to give the
192 if (frame->software_frame_data) {
193 cc::SoftwareFrameData* frame_data = frame->software_frame_data.get();
195 base::SharedMemory shared_memory(frame_data->handle, true,
196 host_->GetProcess()->GetHandle());
198 base::SharedMemory shared_memory(frame_data->handle, true);
201 RenderWidgetHostView* embedder_rwhv =
202 guest_->GetEmbedderRenderWidgetHostView();
203 base::ProcessHandle embedder_pid =
204 embedder_rwhv->GetRenderWidgetHost()->GetProcess()->GetHandle();
206 shared_memory.GiveToProcess(embedder_pid, &frame_data->handle);
209 FrameMsg_CompositorFrameSwapped_Params guest_params;
210 frame->AssignTo(&guest_params.frame);
211 guest_params.output_surface_id = output_surface_id;
212 guest_params.producing_route_id = host_->GetRoutingID();
213 guest_params.producing_host_id = host_->GetProcess()->GetID();
215 guest_->SendMessageToEmbedder(
216 new BrowserPluginMsg_CompositorFrameSwapped(guest_->instance_id(),
220 bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) {
221 return platform_view_->OnMessageReceived(msg);
224 void RenderWidgetHostViewGuest::InitAsChild(
225 gfx::NativeView parent_view) {
226 platform_view_->InitAsChild(parent_view);
229 void RenderWidgetHostViewGuest::InitAsPopup(
230 RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
231 // This should never get called.
235 void RenderWidgetHostViewGuest::InitAsFullscreen(
236 RenderWidgetHostView* reference_host_view) {
237 // This should never get called.
241 gfx::NativeView RenderWidgetHostViewGuest::GetNativeView() const {
242 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
244 return gfx::NativeView();
245 return rwhv->GetNativeView();
248 gfx::NativeViewId RenderWidgetHostViewGuest::GetNativeViewId() const {
249 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
251 return static_cast<gfx::NativeViewId>(NULL);
252 return rwhv->GetNativeViewId();
255 gfx::NativeViewAccessible RenderWidgetHostViewGuest::GetNativeViewAccessible() {
256 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
258 return gfx::NativeViewAccessible();
259 return rwhv->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::UpdateCursor(const WebCursor& cursor) {
269 platform_view_->UpdateCursor(cursor);
272 void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) {
273 platform_view_->SetIsLoading(is_loading);
276 void RenderWidgetHostViewGuest::TextInputTypeChanged(
277 ui::TextInputType type,
278 ui::TextInputMode input_mode,
279 bool can_compose_inline) {
280 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
281 guest_->GetEmbedderRenderWidgetHostView());
284 // Forward the information to embedding RWHV.
285 rwhv->TextInputTypeChanged(type, input_mode, can_compose_inline);
288 void RenderWidgetHostViewGuest::ImeCancelComposition() {
289 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
290 guest_->GetEmbedderRenderWidgetHostView());
293 // Forward the information to embedding RWHV.
294 rwhv->ImeCancelComposition();
297 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
298 void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
299 const gfx::Range& range,
300 const std::vector<gfx::Rect>& character_bounds) {
301 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
302 guest_->GetEmbedderRenderWidgetHostView());
305 std::vector<gfx::Rect> guest_character_bounds;
306 for (size_t i = 0; i < character_bounds.size(); ++i) {
307 gfx::Rect guest_rect = guest_->ToGuestRect(character_bounds[i]);
308 guest_character_bounds.push_back(guest_rect);
310 // Forward the information to embedding RWHV.
311 rwhv->ImeCompositionRangeChanged(range, guest_character_bounds);
315 void RenderWidgetHostViewGuest::DidUpdateBackingStore(
316 const gfx::Rect& scroll_rect,
317 const gfx::Vector2d& scroll_delta,
318 const std::vector<gfx::Rect>& copy_rects,
319 const std::vector<ui::LatencyInfo>& latency_info) {
323 void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text,
325 const gfx::Range& range) {
326 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
327 guest_->GetEmbedderRenderWidgetHostView());
330 // Forward the information to embedding RWHV.
331 rwhv->SelectionChanged(text, offset, range);
334 void RenderWidgetHostViewGuest::SelectionBoundsChanged(
335 const ViewHostMsg_SelectionBounds_Params& params) {
336 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
337 guest_->GetEmbedderRenderWidgetHostView());
340 ViewHostMsg_SelectionBounds_Params guest_params(params);
341 guest_params.anchor_rect = guest_->ToGuestRect(params.anchor_rect);
342 guest_params.focus_rect = guest_->ToGuestRect(params.focus_rect);
343 rwhv->SelectionBoundsChanged(guest_params);
346 void RenderWidgetHostViewGuest::CopyFromCompositingSurface(
347 const gfx::Rect& src_subrect,
348 const gfx::Size& dst_size,
349 const base::Callback<void(bool, const SkBitmap&)>& callback,
350 const SkBitmap::Config config) {
352 guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback);
355 void RenderWidgetHostViewGuest::SetBackground(const SkBitmap& background) {
356 platform_view_->SetBackground(background);
359 void RenderWidgetHostViewGuest::SetHasHorizontalScrollbar(
360 bool has_horizontal_scrollbar) {
361 platform_view_->SetHasHorizontalScrollbar(has_horizontal_scrollbar);
364 void RenderWidgetHostViewGuest::SetScrollOffsetPinning(
365 bool is_pinned_to_left, bool is_pinned_to_right) {
366 platform_view_->SetScrollOffsetPinning(
367 is_pinned_to_left, is_pinned_to_right);
370 bool RenderWidgetHostViewGuest::LockMouse() {
371 return platform_view_->LockMouse();
374 void RenderWidgetHostViewGuest::UnlockMouse() {
375 return platform_view_->UnlockMouse();
378 void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo* results) {
379 RenderWidgetHostViewPort* embedder_view =
380 RenderWidgetHostViewPort::FromRWHV(
381 guest_->GetEmbedderRenderWidgetHostView());
383 embedder_view->GetScreenInfo(results);
386 #if defined(OS_MACOSX)
387 void RenderWidgetHostViewGuest::SetActive(bool active) {
388 platform_view_->SetActive(active);
391 void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag) {
392 platform_view_->SetTakesFocusOnlyOnMouseDown(flag);
395 void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) {
396 platform_view_->SetWindowVisibility(visible);
399 void RenderWidgetHostViewGuest::WindowFrameChanged() {
400 platform_view_->WindowFrameChanged();
403 void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
405 gfx::Rect guest_bounds = GetViewBounds();
406 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
407 gfx::Rect embedder_bounds;
409 embedder_bounds = rwhv->GetViewBounds();
411 gfx::Vector2d guest_offset = gfx::Vector2d(
412 // Horizontal offset of guest from embedder.
413 guest_bounds.x() - embedder_bounds.x(),
414 // Vertical offset from guest's top to embedder's bottom edge.
415 embedder_bounds.bottom() - guest_bounds.y());
417 RenderWidgetHostViewMacDictionaryHelper helper(platform_view_);
418 helper.SetTargetView(rwhv);
419 helper.set_offset(guest_offset);
420 helper.ShowDefinitionForSelection();
423 bool RenderWidgetHostViewGuest::SupportsSpeech() const {
424 return platform_view_->SupportsSpeech();
427 void RenderWidgetHostViewGuest::SpeakSelection() {
428 platform_view_->SpeakSelection();
431 bool RenderWidgetHostViewGuest::IsSpeaking() const {
432 return platform_view_->IsSpeaking();
435 void RenderWidgetHostViewGuest::StopSpeaking() {
436 platform_view_->StopSpeaking();
439 bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
440 const NativeWebKeyboardEvent& event) {
444 #endif // defined(OS_MACOSX)
446 #if defined(OS_ANDROID)
447 void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
448 const gfx::Rect& target_rect,
449 const SkBitmap& zoomed_bitmap) {
452 void RenderWidgetHostViewGuest::HasTouchEventHandlers(bool need_touch_events) {
454 #endif // defined(OS_ANDROID)
456 #if defined(TOOLKIT_GTK)
457 GdkEventButton* RenderWidgetHostViewGuest::GetLastMouseDown() {
461 gfx::NativeView RenderWidgetHostViewGuest::BuildInputMethodsGtkMenu() {
462 return platform_view_->BuildInputMethodsGtkMenu();
464 #endif // defined(TOOLKIT_GTK)
467 void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
468 gfx::NativeViewAccessible accessible_parent) {
471 gfx::NativeViewId RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
477 void RenderWidgetHostViewGuest::DestroyGuestView() {
478 host_->SetView(NULL);
480 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
483 bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
484 ui::GestureConsumer* consumer) {
485 CHECK_EQ(static_cast<RenderWidgetHostViewGuest*>(consumer), this);
489 void RenderWidgetHostViewGuest::DispatchPostponedGestureEvent(
490 ui::GestureEvent* event) {
491 ForwardGestureEventToRenderer(event);
494 void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
495 ui::TouchEvent* event) {
499 blink::WebTouchEvent cancel_event;
500 cancel_event.type = blink::WebInputEvent::TouchCancel;
501 cancel_event.timeStampSeconds = event->time_stamp().InSecondsF();
502 host_->ForwardTouchEventWithLatencyInfo(cancel_event, *event->latency());
505 bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
506 ui::GestureEvent* gesture) {
507 #if defined(OS_WIN) || defined(USE_AURA)
511 // Pinch gestures are disabled by default on windows desktop. See
512 // crbug.com/128477 and crbug.com/148816
513 if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN ||
514 gesture->type() == ui::ET_GESTURE_PINCH_UPDATE ||
515 gesture->type() == ui::ET_GESTURE_PINCH_END) &&
516 !ShouldSendPinchGesture()) {
520 blink::WebGestureEvent web_gesture =
521 MakeWebGestureEventFromUIEvent(*gesture);
522 const gfx::Point& client_point = gesture->location();
523 const gfx::Point& screen_point = gesture->location();
525 web_gesture.x = client_point.x();
526 web_gesture.y = client_point.y();
527 web_gesture.globalX = screen_point.x();
528 web_gesture.globalY = screen_point.y();
530 if (web_gesture.type == blink::WebGestureEvent::Undefined)
532 if (web_gesture.type == blink::WebGestureEvent::GestureTapDown) {
533 host_->ForwardGestureEvent(
534 CreateFlingCancelEvent(gesture->time_stamp().InSecondsF()));
536 host_->ForwardGestureEvent(web_gesture);
543 void RenderWidgetHostViewGuest::ProcessGestures(
544 ui::GestureRecognizer::Gestures* gestures) {
545 if ((gestures == NULL) || gestures->empty())
547 for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin();
548 g_it != gestures->end();
550 ForwardGestureEventToRenderer(*g_it);
555 } // namespace content