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