render_widget_host_view_guest.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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::WebGestureDeviceTouchscreen;
41  return gesture_event;
42}
43#endif  // defined(USE_AURA)
44
45}  // namespace
46
47RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
48    RenderWidgetHost* widget_host,
49    BrowserPluginGuest* guest,
50    RenderWidgetHostViewBase* platform_view)
51    : RenderWidgetHostViewChildFrame(widget_host),
52      // |guest| is NULL during test.
53      guest_(guest ? guest->AsWeakPtr() : base::WeakPtr<BrowserPluginGuest>()),
54      platform_view_(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  RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
125  gfx::Rect embedder_bounds;
126  if (rwhv)
127    embedder_bounds = rwhv->GetViewBounds();
128  gfx::Rect shifted_rect = guest_->ToGuestRect(embedder_bounds);
129  shifted_rect.set_width(size_.width());
130  shifted_rect.set_height(size_.height());
131  return shifted_rect;
132}
133
134void RenderWidgetHostViewGuest::RenderProcessGone(
135    base::TerminationStatus status,
136    int error_code) {
137  platform_view_->RenderProcessGone(status, error_code);
138  // Destroy the guest view instance only, so we don't end up calling
139  // platform_view_->Destroy().
140  DestroyGuestView();
141}
142
143void RenderWidgetHostViewGuest::Destroy() {
144  // The RenderWidgetHost's destruction led here, so don't call it.
145  DestroyGuestView();
146
147  platform_view_->Destroy();
148}
149
150gfx::Size RenderWidgetHostViewGuest::GetPhysicalBackingSize() const {
151  return RenderWidgetHostViewBase::GetPhysicalBackingSize();
152}
153
154base::string16 RenderWidgetHostViewGuest::GetSelectedText() const {
155  return platform_view_->GetSelectedText();
156}
157
158void RenderWidgetHostViewGuest::SetTooltipText(
159    const base::string16& tooltip_text) {
160  platform_view_->SetTooltipText(tooltip_text);
161}
162
163void RenderWidgetHostViewGuest::AcceleratedSurfaceBuffersSwapped(
164    const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
165    int gpu_host_id) {
166  if (!guest_)
167    return;
168
169  FrameMsg_BuffersSwapped_Params guest_params;
170  guest_params.size = params.size;
171  guest_params.mailbox = params.mailbox;
172  guest_params.gpu_route_id = params.route_id;
173  guest_params.gpu_host_id = gpu_host_id;
174  guest_->SendMessageToEmbedder(
175      new BrowserPluginMsg_BuffersSwapped(guest_->instance_id(),
176                                          guest_params));
177}
178
179void RenderWidgetHostViewGuest::AcceleratedSurfacePostSubBuffer(
180    const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
181    int gpu_host_id) {
182  NOTREACHED();
183}
184
185void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
186    uint32 output_surface_id,
187    scoped_ptr<cc::CompositorFrame> frame) {
188  if (!guest_)
189    return;
190
191  if (!guest_->attached()) {
192    // If the guest doesn't have an embedder then there's nothing to give the
193    // the frame to.
194    return;
195  }
196  base::SharedMemoryHandle software_frame_handle =
197      base::SharedMemory::NULLHandle();
198  if (frame->software_frame_data) {
199    cc::SoftwareFrameData* frame_data = frame->software_frame_data.get();
200    scoped_ptr<cc::SharedBitmap> bitmap =
201        HostSharedBitmapManager::current()->GetSharedBitmapFromId(
202            frame_data->size, frame_data->bitmap_id);
203    if (!bitmap)
204      return;
205
206    RenderWidgetHostView* embedder_rwhv =
207        guest_->GetEmbedderRenderWidgetHostView();
208    base::ProcessHandle embedder_pid =
209        embedder_rwhv->GetRenderWidgetHost()->GetProcess()->GetHandle();
210
211    bitmap->memory()->ShareToProcess(embedder_pid, &software_frame_handle);
212  }
213
214  FrameMsg_CompositorFrameSwapped_Params guest_params;
215  frame->AssignTo(&guest_params.frame);
216  guest_params.output_surface_id = output_surface_id;
217  guest_params.producing_route_id = host_->GetRoutingID();
218  guest_params.producing_host_id = host_->GetProcess()->GetID();
219  guest_params.shared_memory_handle = software_frame_handle;
220
221  guest_->SendMessageToEmbedder(
222      new BrowserPluginMsg_CompositorFrameSwapped(guest_->instance_id(),
223                                                  guest_params));
224}
225
226bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) {
227  return platform_view_->OnMessageReceived(msg);
228}
229
230void RenderWidgetHostViewGuest::InitAsChild(
231    gfx::NativeView parent_view) {
232  platform_view_->InitAsChild(parent_view);
233}
234
235void RenderWidgetHostViewGuest::InitAsPopup(
236    RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
237  // This should never get called.
238  NOTREACHED();
239}
240
241void RenderWidgetHostViewGuest::InitAsFullscreen(
242    RenderWidgetHostView* reference_host_view) {
243  // This should never get called.
244  NOTREACHED();
245}
246
247gfx::NativeView RenderWidgetHostViewGuest::GetNativeView() const {
248  if (!guest_)
249    return gfx::NativeView();
250
251  RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
252  if (!rwhv)
253    return gfx::NativeView();
254  return rwhv->GetNativeView();
255}
256
257gfx::NativeViewId RenderWidgetHostViewGuest::GetNativeViewId() const {
258  if (!guest_)
259    return static_cast<gfx::NativeViewId>(NULL);
260
261  RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
262  if (!rwhv)
263    return static_cast<gfx::NativeViewId>(NULL);
264  return rwhv->GetNativeViewId();
265}
266
267gfx::NativeViewAccessible RenderWidgetHostViewGuest::GetNativeViewAccessible() {
268  if (!guest_)
269    return gfx::NativeViewAccessible();
270
271  RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
272  if (!rwhv)
273    return gfx::NativeViewAccessible();
274  return rwhv->GetNativeViewAccessible();
275}
276
277void RenderWidgetHostViewGuest::MovePluginWindows(
278    const std::vector<WebPluginGeometry>& moves) {
279  platform_view_->MovePluginWindows(moves);
280}
281
282void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) {
283  platform_view_->UpdateCursor(cursor);
284}
285
286void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) {
287  platform_view_->SetIsLoading(is_loading);
288}
289
290void RenderWidgetHostViewGuest::TextInputStateChanged(
291    const ViewHostMsg_TextInputState_Params& params) {
292  if (!guest_)
293    return;
294
295  RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
296  if (!rwhv)
297    return;
298  // Forward the information to embedding RWHV.
299  rwhv->TextInputStateChanged(params);
300}
301
302void RenderWidgetHostViewGuest::ImeCancelComposition() {
303  if (!guest_)
304    return;
305
306  RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
307  if (!rwhv)
308    return;
309  // Forward the information to embedding RWHV.
310  rwhv->ImeCancelComposition();
311}
312
313#if defined(OS_MACOSX) || defined(USE_AURA)
314void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
315    const gfx::Range& range,
316    const std::vector<gfx::Rect>& character_bounds) {
317  if (!guest_)
318    return;
319
320  RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
321  if (!rwhv)
322    return;
323  std::vector<gfx::Rect> guest_character_bounds;
324  for (size_t i = 0; i < character_bounds.size(); ++i) {
325    gfx::Rect guest_rect = guest_->ToGuestRect(character_bounds[i]);
326    guest_character_bounds.push_back(guest_rect);
327  }
328  // Forward the information to embedding RWHV.
329  rwhv->ImeCompositionRangeChanged(range, guest_character_bounds);
330}
331#endif
332
333void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text,
334                                                 size_t offset,
335                                                 const gfx::Range& range) {
336  platform_view_->SelectionChanged(text, offset, range);
337}
338
339void RenderWidgetHostViewGuest::SelectionBoundsChanged(
340    const ViewHostMsg_SelectionBounds_Params& params) {
341  if (!guest_)
342    return;
343
344  RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
345  if (!rwhv)
346    return;
347  ViewHostMsg_SelectionBounds_Params guest_params(params);
348  guest_params.anchor_rect = guest_->ToGuestRect(params.anchor_rect);
349  guest_params.focus_rect = guest_->ToGuestRect(params.focus_rect);
350  rwhv->SelectionBoundsChanged(guest_params);
351}
352
353void RenderWidgetHostViewGuest::CopyFromCompositingSurface(
354    const gfx::Rect& src_subrect,
355    const gfx::Size& dst_size,
356    const base::Callback<void(bool, const SkBitmap&)>& callback,
357    const SkColorType color_type) {
358  CHECK(guest_);
359  guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback);
360}
361
362void RenderWidgetHostViewGuest::SetBackgroundOpaque(bool opaque) {
363  platform_view_->SetBackgroundOpaque(opaque);
364}
365
366bool RenderWidgetHostViewGuest::LockMouse() {
367  return platform_view_->LockMouse();
368}
369
370void RenderWidgetHostViewGuest::UnlockMouse() {
371  return platform_view_->UnlockMouse();
372}
373
374void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo* results) {
375  if (!guest_)
376    return;
377  RenderWidgetHostViewBase* embedder_view = GetGuestRenderWidgetHostView();
378  if (embedder_view)
379    embedder_view->GetScreenInfo(results);
380}
381
382#if defined(OS_MACOSX)
383void RenderWidgetHostViewGuest::SetActive(bool active) {
384  platform_view_->SetActive(active);
385}
386
387void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag) {
388  platform_view_->SetTakesFocusOnlyOnMouseDown(flag);
389}
390
391void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) {
392  platform_view_->SetWindowVisibility(visible);
393}
394
395void RenderWidgetHostViewGuest::WindowFrameChanged() {
396  platform_view_->WindowFrameChanged();
397}
398
399void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
400  if (!guest_)
401    return;
402
403  gfx::Point origin;
404  gfx::Rect guest_bounds = GetViewBounds();
405  RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
406  gfx::Rect embedder_bounds;
407  if (rwhv)
408    embedder_bounds = rwhv->GetViewBounds();
409
410  gfx::Vector2d guest_offset = gfx::Vector2d(
411      // Horizontal offset of guest from embedder.
412      guest_bounds.x() - embedder_bounds.x(),
413      // Vertical offset from guest's top to embedder's bottom edge.
414      embedder_bounds.bottom() - guest_bounds.y());
415
416  RenderWidgetHostViewMacDictionaryHelper helper(platform_view_);
417  helper.SetTargetView(rwhv);
418  helper.set_offset(guest_offset);
419  helper.ShowDefinitionForSelection();
420}
421
422bool RenderWidgetHostViewGuest::SupportsSpeech() const {
423  return platform_view_->SupportsSpeech();
424}
425
426void RenderWidgetHostViewGuest::SpeakSelection() {
427  platform_view_->SpeakSelection();
428}
429
430bool RenderWidgetHostViewGuest::IsSpeaking() const {
431  return platform_view_->IsSpeaking();
432}
433
434void RenderWidgetHostViewGuest::StopSpeaking() {
435  platform_view_->StopSpeaking();
436}
437
438bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
439    const NativeWebKeyboardEvent& event) {
440  return false;
441}
442
443#endif  // defined(OS_MACOSX)
444
445#if defined(OS_ANDROID)
446void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
447    const gfx::Rect& target_rect,
448    const SkBitmap& zoomed_bitmap) {
449}
450
451void RenderWidgetHostViewGuest::LockCompositingSurface() {
452}
453
454void RenderWidgetHostViewGuest::UnlockCompositingSurface() {
455}
456#endif  // defined(OS_ANDROID)
457
458#if defined(OS_WIN)
459void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
460    gfx::NativeViewAccessible accessible_parent) {
461}
462
463gfx::NativeViewId RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
464    const {
465  return NULL;
466}
467#endif
468
469void RenderWidgetHostViewGuest::DestroyGuestView() {
470  host_->SetView(NULL);
471  host_ = NULL;
472  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
473}
474
475bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
476    ui::GestureConsumer* consumer) {
477  CHECK_EQ(static_cast<RenderWidgetHostViewGuest*>(consumer), this);
478  return true;
479}
480
481void RenderWidgetHostViewGuest::DispatchGestureEvent(
482    ui::GestureEvent* event) {
483  ForwardGestureEventToRenderer(event);
484}
485
486void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
487    ui::TouchEvent* event) {
488  if (!host_)
489    return;
490
491  blink::WebTouchEvent cancel_event;
492  // TODO(rbyers): This event has no touches in it.  Don't we need to know what
493  // touches are currently active in order to cancel them all properly?
494  WebTouchEventTraits::ResetType(blink::WebInputEvent::TouchCancel,
495                                 event->time_stamp().InSecondsF(),
496                                 &cancel_event);
497
498  host_->ForwardTouchEventWithLatencyInfo(cancel_event, *event->latency());
499}
500
501bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
502    ui::GestureEvent* gesture) {
503#if defined(USE_AURA)
504  if (!host_)
505    return false;
506
507  if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN ||
508      gesture->type() == ui::ET_GESTURE_PINCH_UPDATE ||
509      gesture->type() == ui::ET_GESTURE_PINCH_END) && !pinch_zoom_enabled_) {
510    return true;
511  }
512
513  blink::WebGestureEvent web_gesture =
514      MakeWebGestureEventFromUIEvent(*gesture);
515  const gfx::Point& client_point = gesture->location();
516  const gfx::Point& screen_point = gesture->location();
517
518  web_gesture.x = client_point.x();
519  web_gesture.y = client_point.y();
520  web_gesture.globalX = screen_point.x();
521  web_gesture.globalY = screen_point.y();
522
523  if (web_gesture.type == blink::WebGestureEvent::Undefined)
524    return false;
525  if (web_gesture.type == blink::WebGestureEvent::GestureTapDown) {
526    host_->ForwardGestureEvent(
527        CreateFlingCancelEvent(gesture->time_stamp().InSecondsF()));
528  }
529  host_->ForwardGestureEvent(web_gesture);
530  return true;
531#else
532  return false;
533#endif
534}
535
536void RenderWidgetHostViewGuest::ProcessGestures(
537    ui::GestureRecognizer::Gestures* gestures) {
538  if ((gestures == NULL) || gestures->empty())
539    return;
540  for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin();
541      g_it != gestures->end();
542      ++g_it) {
543    ForwardGestureEventToRenderer(*g_it);
544  }
545}
546
547SkColorType RenderWidgetHostViewGuest::PreferredReadbackFormat() {
548  return kN32_SkColorType;
549}
550
551RenderWidgetHostViewBase*
552RenderWidgetHostViewGuest::GetGuestRenderWidgetHostView() const {
553  return static_cast<RenderWidgetHostViewBase*>(
554      guest_->GetEmbedderRenderWidgetHostView());
555}
556
557}  // namespace content
558