render_widget_host_view_guest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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.
4
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"
20
21#if defined(OS_MACOSX)
22#import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
23#endif
24
25#if defined(OS_WIN) || defined(USE_AURA)
26#include "content/browser/renderer_host/ui_events_helper.h"
27#endif
28
29namespace content {
30
31namespace {
32
33#if defined(OS_WIN) || defined(USE_AURA)
34blink::WebGestureEvent CreateFlingCancelEvent(double time_stamp) {
35  blink::WebGestureEvent gesture_event;
36  gesture_event.timeStampSeconds = time_stamp;
37  gesture_event.type = blink::WebGestureEvent::GestureFlingCancel;
38  gesture_event.sourceDevice = blink::WebGestureEvent::Touchscreen;
39  return gesture_event;
40}
41#endif  // defined(OS_WIN) || defined(USE_AURA)
42
43}  // namespace
44
45RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
46    RenderWidgetHost* widget_host,
47    BrowserPluginGuest* guest,
48    RenderWidgetHostView* platform_view)
49    : RenderWidgetHostViewChildFrame(widget_host),
50      // |guest| is NULL during test.
51      guest_(guest ? guest->AsWeakPtr() : base::WeakPtr<BrowserPluginGuest>()),
52      platform_view_(static_cast<RenderWidgetHostViewPort*>(platform_view)) {
53#if defined(OS_WIN) || defined(USE_AURA)
54  gesture_recognizer_.reset(ui::GestureRecognizer::Create());
55  gesture_recognizer_->AddGestureEventHelper(this);
56#endif  // defined(OS_WIN) || defined(USE_AURA)
57}
58
59RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
60#if defined(OS_WIN) || defined(USE_AURA)
61  gesture_recognizer_->RemoveGestureEventHelper(this);
62#endif  // defined(OS_WIN) || defined(USE_AURA)
63}
64
65void RenderWidgetHostViewGuest::WasShown() {
66  // If the WebContents associated with us showed an interstitial page in the
67  // beginning, the teardown path might call WasShown() while |host_| is in
68  // the process of destruction. Avoid calling WasShown below in this case.
69  // TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the
70  // first place: http://crbug.com/273089.
71  //
72  // |guest_| is NULL during test.
73  if ((guest_ && guest_->is_in_destruction()) || !host_->is_hidden())
74    return;
75  host_->WasShown();
76}
77
78void RenderWidgetHostViewGuest::WasHidden() {
79  // |guest_| is NULL during test.
80  if ((guest_ && guest_->is_in_destruction()) || host_->is_hidden())
81    return;
82  host_->WasHidden();
83}
84
85void RenderWidgetHostViewGuest::SetSize(const gfx::Size& size) {
86  size_ = size;
87  host_->WasResized();
88}
89
90void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect& rect) {
91  SetSize(rect.size());
92}
93
94#if defined(OS_WIN) || defined(USE_AURA)
95void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
96    const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
97  // TODO(fsamuel): Currently we will only take this codepath if the guest has
98  // requested touch events. A better solution is to always forward touchpresses
99  // to the embedder process to target a BrowserPlugin, and then route all
100  // subsequent touch points of that touchdown to the appropriate guest until
101  // that touch point is released.
102  ScopedVector<ui::TouchEvent> events;
103  if (!MakeUITouchEventsFromWebTouchEvents(touch, &events, LOCAL_COORDINATES))
104    return;
105
106  ui::EventResult result = (ack_result ==
107      INPUT_EVENT_ACK_STATE_CONSUMED) ? ui::ER_HANDLED : ui::ER_UNHANDLED;
108  for (ScopedVector<ui::TouchEvent>::iterator iter = events.begin(),
109      end = events.end(); iter != end; ++iter)  {
110    scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
111    gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture(
112        *(*iter), result, this));
113    ProcessGestures(gestures.get());
114  }
115}
116#endif
117
118gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const {
119  if (!guest_)
120    return gfx::Rect();
121
122  RenderWidgetHostViewPort* rwhv = static_cast<RenderWidgetHostViewPort*>(
123      guest_->GetEmbedderRenderWidgetHostView());
124  gfx::Rect embedder_bounds;
125  if (rwhv)
126    embedder_bounds = rwhv->GetViewBounds();
127  gfx::Rect shifted_rect = guest_->ToGuestRect(embedder_bounds);
128  shifted_rect.set_width(size_.width());
129  shifted_rect.set_height(size_.height());
130  return shifted_rect;
131}
132
133void RenderWidgetHostViewGuest::RenderProcessGone(
134    base::TerminationStatus status,
135    int error_code) {
136  platform_view_->RenderProcessGone(status, error_code);
137  // Destroy the guest view instance only, so we don't end up calling
138  // platform_view_->Destroy().
139  DestroyGuestView();
140}
141
142void RenderWidgetHostViewGuest::Destroy() {
143  // The RenderWidgetHost's destruction led here, so don't call it.
144  DestroyGuestView();
145
146  platform_view_->Destroy();
147}
148
149gfx::Size RenderWidgetHostViewGuest::GetPhysicalBackingSize() const {
150  return RenderWidgetHostViewBase::GetPhysicalBackingSize();
151}
152
153base::string16 RenderWidgetHostViewGuest::GetSelectedText() const {
154  return platform_view_->GetSelectedText();
155}
156
157void RenderWidgetHostViewGuest::SetTooltipText(
158    const base::string16& tooltip_text) {
159  platform_view_->SetTooltipText(tooltip_text);
160}
161
162void RenderWidgetHostViewGuest::AcceleratedSurfaceBuffersSwapped(
163    const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
164    int gpu_host_id) {
165  if (!guest_)
166    return;
167
168  // If accelerated surface buffers are getting swapped then we're not using
169  // the software path.
170  guest_->clear_damage_buffer();
171  FrameMsg_BuffersSwapped_Params guest_params;
172  guest_params.size = params.size;
173  guest_params.mailbox = params.mailbox;
174  guest_params.gpu_route_id = params.route_id;
175  guest_params.gpu_host_id = gpu_host_id;
176  guest_->SendMessageToEmbedder(
177      new BrowserPluginMsg_BuffersSwapped(guest_->instance_id(),
178                                          guest_params));
179}
180
181void RenderWidgetHostViewGuest::AcceleratedSurfacePostSubBuffer(
182    const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
183    int gpu_host_id) {
184  NOTREACHED();
185}
186
187void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
188    uint32 output_surface_id,
189    scoped_ptr<cc::CompositorFrame> frame) {
190  if (!guest_)
191    return;
192
193  guest_->clear_damage_buffer();
194
195  if (!guest_->attached()) {
196    // If the guest doesn't have an embedder then there's nothing to give the
197    // the frame to.
198    return;
199  }
200  if (frame->software_frame_data) {
201    cc::SoftwareFrameData* frame_data = frame->software_frame_data.get();
202#ifdef OS_WIN
203    base::SharedMemory shared_memory(frame_data->handle, true,
204                                     host_->GetProcess()->GetHandle());
205#else
206    base::SharedMemory shared_memory(frame_data->handle, true);
207#endif
208
209    RenderWidgetHostView* embedder_rwhv =
210        guest_->GetEmbedderRenderWidgetHostView();
211    base::ProcessHandle embedder_pid =
212        embedder_rwhv->GetRenderWidgetHost()->GetProcess()->GetHandle();
213
214    shared_memory.GiveToProcess(embedder_pid, &frame_data->handle);
215  }
216
217  FrameMsg_CompositorFrameSwapped_Params guest_params;
218  frame->AssignTo(&guest_params.frame);
219  guest_params.output_surface_id = output_surface_id;
220  guest_params.producing_route_id = host_->GetRoutingID();
221  guest_params.producing_host_id = host_->GetProcess()->GetID();
222
223  guest_->SendMessageToEmbedder(
224      new BrowserPluginMsg_CompositorFrameSwapped(guest_->instance_id(),
225                                                  guest_params));
226}
227
228bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) {
229  return platform_view_->OnMessageReceived(msg);
230}
231
232void RenderWidgetHostViewGuest::InitAsChild(
233    gfx::NativeView parent_view) {
234  platform_view_->InitAsChild(parent_view);
235}
236
237void RenderWidgetHostViewGuest::InitAsPopup(
238    RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
239  // This should never get called.
240  NOTREACHED();
241}
242
243void RenderWidgetHostViewGuest::InitAsFullscreen(
244    RenderWidgetHostView* reference_host_view) {
245  // This should never get called.
246  NOTREACHED();
247}
248
249gfx::NativeView RenderWidgetHostViewGuest::GetNativeView() const {
250  if (!guest_)
251    return gfx::NativeView();
252
253  RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
254  if (!rwhv)
255    return gfx::NativeView();
256  return rwhv->GetNativeView();
257}
258
259gfx::NativeViewId RenderWidgetHostViewGuest::GetNativeViewId() const {
260  if (!guest_)
261    return static_cast<gfx::NativeViewId>(NULL);
262
263  RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
264  if (!rwhv)
265    return static_cast<gfx::NativeViewId>(NULL);
266  return rwhv->GetNativeViewId();
267}
268
269gfx::NativeViewAccessible RenderWidgetHostViewGuest::GetNativeViewAccessible() {
270  if (!guest_)
271    return gfx::NativeViewAccessible();
272
273  RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
274  if (!rwhv)
275    return gfx::NativeViewAccessible();
276  return rwhv->GetNativeViewAccessible();
277}
278
279void RenderWidgetHostViewGuest::MovePluginWindows(
280    const gfx::Vector2d& scroll_offset,
281    const std::vector<WebPluginGeometry>& moves) {
282  platform_view_->MovePluginWindows(scroll_offset, moves);
283}
284
285void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) {
286  platform_view_->UpdateCursor(cursor);
287}
288
289void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) {
290  platform_view_->SetIsLoading(is_loading);
291}
292
293void RenderWidgetHostViewGuest::TextInputTypeChanged(
294    ui::TextInputType type,
295    ui::TextInputMode input_mode,
296    bool can_compose_inline) {
297  if (!guest_)
298    return;
299
300  RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
301      guest_->GetEmbedderRenderWidgetHostView());
302  if (!rwhv)
303    return;
304  // Forward the information to embedding RWHV.
305  rwhv->TextInputTypeChanged(type, input_mode, can_compose_inline);
306}
307
308void RenderWidgetHostViewGuest::ImeCancelComposition() {
309  if (!guest_)
310    return;
311
312  RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
313      guest_->GetEmbedderRenderWidgetHostView());
314  if (!rwhv)
315    return;
316  // Forward the information to embedding RWHV.
317  rwhv->ImeCancelComposition();
318}
319
320#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
321void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
322    const gfx::Range& range,
323    const std::vector<gfx::Rect>& character_bounds) {
324  if (!guest_)
325    return;
326
327  RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
328      guest_->GetEmbedderRenderWidgetHostView());
329  if (!rwhv)
330    return;
331  std::vector<gfx::Rect> guest_character_bounds;
332  for (size_t i = 0; i < character_bounds.size(); ++i) {
333    gfx::Rect guest_rect = guest_->ToGuestRect(character_bounds[i]);
334    guest_character_bounds.push_back(guest_rect);
335  }
336  // Forward the information to embedding RWHV.
337  rwhv->ImeCompositionRangeChanged(range, guest_character_bounds);
338}
339#endif
340
341void RenderWidgetHostViewGuest::DidUpdateBackingStore(
342    const gfx::Rect& scroll_rect,
343    const gfx::Vector2d& scroll_delta,
344    const std::vector<gfx::Rect>& copy_rects,
345    const std::vector<ui::LatencyInfo>& latency_info) {
346  NOTREACHED();
347}
348
349void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text,
350                                                 size_t offset,
351                                                 const gfx::Range& range) {
352  platform_view_->SelectionChanged(text, offset, range);
353}
354
355void RenderWidgetHostViewGuest::SelectionBoundsChanged(
356    const ViewHostMsg_SelectionBounds_Params& params) {
357  if (!guest_)
358    return;
359
360  RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
361      guest_->GetEmbedderRenderWidgetHostView());
362  if (!rwhv)
363    return;
364  ViewHostMsg_SelectionBounds_Params guest_params(params);
365  guest_params.anchor_rect = guest_->ToGuestRect(params.anchor_rect);
366  guest_params.focus_rect = guest_->ToGuestRect(params.focus_rect);
367  rwhv->SelectionBoundsChanged(guest_params);
368}
369
370#if defined(OS_ANDROID)
371void RenderWidgetHostViewGuest::SelectionRootBoundsChanged(
372    const gfx::Rect& bounds) {
373  if (!guest_)
374    return;
375
376  RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
377      guest_->GetEmbedderRenderWidgetHostView());
378  if (!rwhv)
379    return;
380
381  rwhv->SelectionRootBoundsChanged(guest_->ToGuestRect(bounds));
382}
383#endif
384
385void RenderWidgetHostViewGuest::CopyFromCompositingSurface(
386    const gfx::Rect& src_subrect,
387    const gfx::Size& dst_size,
388    const base::Callback<void(bool, const SkBitmap&)>& callback,
389    const SkBitmap::Config config) {
390  CHECK(guest_);
391  guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback);
392}
393
394void RenderWidgetHostViewGuest::SetBackground(const SkBitmap& background) {
395  platform_view_->SetBackground(background);
396}
397
398void RenderWidgetHostViewGuest::SetHasHorizontalScrollbar(
399    bool has_horizontal_scrollbar) {
400  platform_view_->SetHasHorizontalScrollbar(has_horizontal_scrollbar);
401}
402
403void RenderWidgetHostViewGuest::SetScrollOffsetPinning(
404    bool is_pinned_to_left, bool is_pinned_to_right) {
405  platform_view_->SetScrollOffsetPinning(
406      is_pinned_to_left, is_pinned_to_right);
407}
408
409bool RenderWidgetHostViewGuest::LockMouse() {
410  return platform_view_->LockMouse();
411}
412
413void RenderWidgetHostViewGuest::UnlockMouse() {
414  return platform_view_->UnlockMouse();
415}
416
417void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo* results) {
418  if (!guest_)
419    return;
420  RenderWidgetHostViewPort* embedder_view =
421      RenderWidgetHostViewPort::FromRWHV(
422          guest_->GetEmbedderRenderWidgetHostView());
423  if (embedder_view)
424    embedder_view->GetScreenInfo(results);
425}
426
427#if defined(OS_MACOSX)
428void RenderWidgetHostViewGuest::SetActive(bool active) {
429  platform_view_->SetActive(active);
430}
431
432void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag) {
433  platform_view_->SetTakesFocusOnlyOnMouseDown(flag);
434}
435
436void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) {
437  platform_view_->SetWindowVisibility(visible);
438}
439
440void RenderWidgetHostViewGuest::WindowFrameChanged() {
441  platform_view_->WindowFrameChanged();
442}
443
444void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
445  if (!guest_)
446    return;
447
448  gfx::Point origin;
449  gfx::Rect guest_bounds = GetViewBounds();
450  RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
451  gfx::Rect embedder_bounds;
452  if (rwhv)
453    embedder_bounds = rwhv->GetViewBounds();
454
455  gfx::Vector2d guest_offset = gfx::Vector2d(
456      // Horizontal offset of guest from embedder.
457      guest_bounds.x() - embedder_bounds.x(),
458      // Vertical offset from guest's top to embedder's bottom edge.
459      embedder_bounds.bottom() - guest_bounds.y());
460
461  RenderWidgetHostViewMacDictionaryHelper helper(platform_view_);
462  helper.SetTargetView(rwhv);
463  helper.set_offset(guest_offset);
464  helper.ShowDefinitionForSelection();
465}
466
467bool RenderWidgetHostViewGuest::SupportsSpeech() const {
468  return platform_view_->SupportsSpeech();
469}
470
471void RenderWidgetHostViewGuest::SpeakSelection() {
472  platform_view_->SpeakSelection();
473}
474
475bool RenderWidgetHostViewGuest::IsSpeaking() const {
476  return platform_view_->IsSpeaking();
477}
478
479void RenderWidgetHostViewGuest::StopSpeaking() {
480  platform_view_->StopSpeaking();
481}
482
483bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
484    const NativeWebKeyboardEvent& event) {
485  return false;
486}
487
488#endif  // defined(OS_MACOSX)
489
490#if defined(OS_ANDROID)
491void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
492    const gfx::Rect& target_rect,
493    const SkBitmap& zoomed_bitmap) {
494}
495#endif  // defined(OS_ANDROID)
496
497#if defined(TOOLKIT_GTK)
498GdkEventButton* RenderWidgetHostViewGuest::GetLastMouseDown() {
499  return NULL;
500}
501
502gfx::NativeView RenderWidgetHostViewGuest::BuildInputMethodsGtkMenu() {
503  return platform_view_->BuildInputMethodsGtkMenu();
504}
505#endif  // defined(TOOLKIT_GTK)
506
507#if defined(OS_WIN)
508void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
509    gfx::NativeViewAccessible accessible_parent) {
510}
511
512gfx::NativeViewId RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
513    const {
514  return NULL;
515}
516#endif
517
518void RenderWidgetHostViewGuest::DestroyGuestView() {
519  host_->SetView(NULL);
520  host_ = NULL;
521  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
522}
523
524bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
525    ui::GestureConsumer* consumer) {
526  CHECK_EQ(static_cast<RenderWidgetHostViewGuest*>(consumer), this);
527  return true;
528}
529
530void RenderWidgetHostViewGuest::DispatchPostponedGestureEvent(
531    ui::GestureEvent* event) {
532  ForwardGestureEventToRenderer(event);
533}
534
535void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
536    ui::TouchEvent* event) {
537  if (!host_)
538    return;
539
540  blink::WebTouchEvent cancel_event;
541  cancel_event.type = blink::WebInputEvent::TouchCancel;
542  cancel_event.timeStampSeconds = event->time_stamp().InSecondsF();
543  host_->ForwardTouchEventWithLatencyInfo(cancel_event, *event->latency());
544}
545
546bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
547    ui::GestureEvent* gesture) {
548#if defined(OS_WIN) || defined(USE_AURA)
549  if (!host_)
550    return false;
551
552  if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN ||
553      gesture->type() == ui::ET_GESTURE_PINCH_UPDATE ||
554      gesture->type() == ui::ET_GESTURE_PINCH_END) && !pinch_zoom_enabled_) {
555    return true;
556  }
557
558  blink::WebGestureEvent web_gesture =
559      MakeWebGestureEventFromUIEvent(*gesture);
560  const gfx::Point& client_point = gesture->location();
561  const gfx::Point& screen_point = gesture->location();
562
563  web_gesture.x = client_point.x();
564  web_gesture.y = client_point.y();
565  web_gesture.globalX = screen_point.x();
566  web_gesture.globalY = screen_point.y();
567
568  if (web_gesture.type == blink::WebGestureEvent::Undefined)
569    return false;
570  if (web_gesture.type == blink::WebGestureEvent::GestureTapDown) {
571    host_->ForwardGestureEvent(
572        CreateFlingCancelEvent(gesture->time_stamp().InSecondsF()));
573  }
574  host_->ForwardGestureEvent(web_gesture);
575  return true;
576#else
577  return false;
578#endif
579}
580
581void RenderWidgetHostViewGuest::ProcessGestures(
582    ui::GestureRecognizer::Gestures* gestures) {
583  if ((gestures == NULL) || gestures->empty())
584    return;
585  for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin();
586      g_it != gestures->end();
587      ++g_it) {
588    ForwardGestureEventToRenderer(*g_it);
589  }
590}
591
592SkBitmap::Config RenderWidgetHostViewGuest::PreferredReadbackFormat() {
593  return SkBitmap::kARGB_8888_Config;
594}
595
596}  // namespace content
597