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