Home | History | Annotate | Download | only in frame_host
      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 
     31 namespace content {
     32 
     33 namespace {
     34 
     35 #if defined(USE_AURA)
     36 blink::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 
     47 RenderWidgetHostViewGuest::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 
     61 RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
     62 #if defined(USE_AURA)
     63   gesture_recognizer_->RemoveGestureEventHelper(this);
     64 #endif  // defined(USE_AURA)
     65 }
     66 
     67 void 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 
     80 void 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 
     87 void RenderWidgetHostViewGuest::SetSize(const gfx::Size& size) {
     88   size_ = size;
     89   host_->WasResized();
     90 }
     91 
     92 void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect& rect) {
     93   SetSize(rect.size());
     94 }
     95 
     96 #if defined(USE_AURA)
     97 void 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 
    120 gfx::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 
    134 void 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 
    143 void RenderWidgetHostViewGuest::Destroy() {
    144   // The RenderWidgetHost's destruction led here, so don't call it.
    145   DestroyGuestView();
    146 
    147   platform_view_->Destroy();
    148 }
    149 
    150 gfx::Size RenderWidgetHostViewGuest::GetPhysicalBackingSize() const {
    151   return RenderWidgetHostViewBase::GetPhysicalBackingSize();
    152 }
    153 
    154 base::string16 RenderWidgetHostViewGuest::GetSelectedText() const {
    155   return platform_view_->GetSelectedText();
    156 }
    157 
    158 void RenderWidgetHostViewGuest::SetTooltipText(
    159     const base::string16& tooltip_text) {
    160   platform_view_->SetTooltipText(tooltip_text);
    161 }
    162 
    163 void 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 
    179 void RenderWidgetHostViewGuest::AcceleratedSurfacePostSubBuffer(
    180     const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
    181     int gpu_host_id) {
    182   NOTREACHED();
    183 }
    184 
    185 void 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 
    226 bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) {
    227   return platform_view_->OnMessageReceived(msg);
    228 }
    229 
    230 void RenderWidgetHostViewGuest::InitAsChild(
    231     gfx::NativeView parent_view) {
    232   platform_view_->InitAsChild(parent_view);
    233 }
    234 
    235 void RenderWidgetHostViewGuest::InitAsPopup(
    236     RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
    237   // This should never get called.
    238   NOTREACHED();
    239 }
    240 
    241 void RenderWidgetHostViewGuest::InitAsFullscreen(
    242     RenderWidgetHostView* reference_host_view) {
    243   // This should never get called.
    244   NOTREACHED();
    245 }
    246 
    247 gfx::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 
    257 gfx::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 
    267 gfx::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 
    277 void RenderWidgetHostViewGuest::MovePluginWindows(
    278     const std::vector<WebPluginGeometry>& moves) {
    279   platform_view_->MovePluginWindows(moves);
    280 }
    281 
    282 void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) {
    283   platform_view_->UpdateCursor(cursor);
    284 }
    285 
    286 void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) {
    287   platform_view_->SetIsLoading(is_loading);
    288 }
    289 
    290 void 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 
    302 void 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)
    314 void 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 
    333 void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text,
    334                                                  size_t offset,
    335                                                  const gfx::Range& range) {
    336   platform_view_->SelectionChanged(text, offset, range);
    337 }
    338 
    339 void 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 
    353 void 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 SkBitmap::Config config) {
    358   CHECK(guest_);
    359   guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback);
    360 }
    361 
    362 void RenderWidgetHostViewGuest::SetBackgroundOpaque(bool opaque) {
    363   platform_view_->SetBackgroundOpaque(opaque);
    364 }
    365 
    366 bool RenderWidgetHostViewGuest::LockMouse() {
    367   return platform_view_->LockMouse();
    368 }
    369 
    370 void RenderWidgetHostViewGuest::UnlockMouse() {
    371   return platform_view_->UnlockMouse();
    372 }
    373 
    374 void 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)
    383 void RenderWidgetHostViewGuest::SetActive(bool active) {
    384   platform_view_->SetActive(active);
    385 }
    386 
    387 void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag) {
    388   platform_view_->SetTakesFocusOnlyOnMouseDown(flag);
    389 }
    390 
    391 void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) {
    392   platform_view_->SetWindowVisibility(visible);
    393 }
    394 
    395 void RenderWidgetHostViewGuest::WindowFrameChanged() {
    396   platform_view_->WindowFrameChanged();
    397 }
    398 
    399 void 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 
    422 bool RenderWidgetHostViewGuest::SupportsSpeech() const {
    423   return platform_view_->SupportsSpeech();
    424 }
    425 
    426 void RenderWidgetHostViewGuest::SpeakSelection() {
    427   platform_view_->SpeakSelection();
    428 }
    429 
    430 bool RenderWidgetHostViewGuest::IsSpeaking() const {
    431   return platform_view_->IsSpeaking();
    432 }
    433 
    434 void RenderWidgetHostViewGuest::StopSpeaking() {
    435   platform_view_->StopSpeaking();
    436 }
    437 
    438 bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
    439     const NativeWebKeyboardEvent& event) {
    440   return false;
    441 }
    442 
    443 #endif  // defined(OS_MACOSX)
    444 
    445 #if defined(OS_ANDROID)
    446 void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
    447     const gfx::Rect& target_rect,
    448     const SkBitmap& zoomed_bitmap) {
    449 }
    450 
    451 void RenderWidgetHostViewGuest::LockCompositingSurface() {
    452 }
    453 
    454 void RenderWidgetHostViewGuest::UnlockCompositingSurface() {
    455 }
    456 #endif  // defined(OS_ANDROID)
    457 
    458 #if defined(OS_WIN)
    459 void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
    460     gfx::NativeViewAccessible accessible_parent) {
    461 }
    462 
    463 gfx::NativeViewId RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
    464     const {
    465   return NULL;
    466 }
    467 #endif
    468 
    469 void RenderWidgetHostViewGuest::DestroyGuestView() {
    470   host_->SetView(NULL);
    471   host_ = NULL;
    472   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    473 }
    474 
    475 bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
    476     ui::GestureConsumer* consumer) {
    477   CHECK_EQ(static_cast<RenderWidgetHostViewGuest*>(consumer), this);
    478   return true;
    479 }
    480 
    481 void RenderWidgetHostViewGuest::DispatchGestureEvent(
    482     ui::GestureEvent* event) {
    483   ForwardGestureEventToRenderer(event);
    484 }
    485 
    486 void 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 
    501 bool 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 
    536 void 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 
    547 SkBitmap::Config RenderWidgetHostViewGuest::PreferredReadbackFormat() {
    548   return SkBitmap::kARGB_8888_Config;
    549 }
    550 
    551 RenderWidgetHostViewBase*
    552 RenderWidgetHostViewGuest::GetGuestRenderWidgetHostView() const {
    553   return static_cast<RenderWidgetHostViewBase*>(
    554       guest_->GetEmbedderRenderWidgetHostView());
    555 }
    556 
    557 }  // namespace content
    558