Home | History | Annotate | Download | only in browser_plugin
      1 // Copyright (c) 2012 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 "content/browser/browser_plugin/browser_plugin_embedder.h"
      6 
      7 #include "base/values.h"
      8 #include "content/browser/browser_plugin/browser_plugin_guest.h"
      9 #include "content/browser/renderer_host/render_view_host_impl.h"
     10 #include "content/browser/web_contents/web_contents_impl.h"
     11 #include "content/common/browser_plugin/browser_plugin_constants.h"
     12 #include "content/common/browser_plugin/browser_plugin_messages.h"
     13 #include "content/common/drag_messages.h"
     14 #include "content/common/gpu/gpu_messages.h"
     15 #include "content/public/browser/browser_context.h"
     16 #include "content/public/browser/browser_plugin_guest_manager.h"
     17 #include "content/public/browser/content_browser_client.h"
     18 #include "content/public/browser/native_web_keyboard_event.h"
     19 #include "content/public/browser/render_view_host.h"
     20 #include "content/public/browser/user_metrics.h"
     21 #include "content/public/common/content_switches.h"
     22 #include "content/public/common/result_codes.h"
     23 #include "content/public/common/url_constants.h"
     24 #include "net/base/escape.h"
     25 #include "ui/events/keycodes/keyboard_codes.h"
     26 
     27 namespace content {
     28 
     29 BrowserPluginEmbedder::BrowserPluginEmbedder(WebContentsImpl* web_contents)
     30     : WebContentsObserver(web_contents),
     31       guest_drag_ending_(false),
     32       weak_ptr_factory_(this) {
     33 }
     34 
     35 BrowserPluginEmbedder::~BrowserPluginEmbedder() {
     36 }
     37 
     38 // static
     39 BrowserPluginEmbedder* BrowserPluginEmbedder::Create(
     40     WebContentsImpl* web_contents) {
     41   return new BrowserPluginEmbedder(web_contents);
     42 }
     43 
     44 void BrowserPluginEmbedder::DragEnteredGuest(BrowserPluginGuest* guest) {
     45   guest_dragging_over_ = guest->AsWeakPtr();
     46 }
     47 
     48 void BrowserPluginEmbedder::DragLeftGuest(BrowserPluginGuest* guest) {
     49   // Avoid race conditions in switching between guests being hovered over by
     50   // only un-setting if the caller is marked as the guest being dragged over.
     51   if (guest_dragging_over_.get() == guest) {
     52     guest_dragging_over_.reset();
     53   }
     54 }
     55 
     56 void BrowserPluginEmbedder::StartDrag(BrowserPluginGuest* guest) {
     57   guest_started_drag_ = guest->AsWeakPtr();
     58   guest_drag_ending_ = false;
     59 }
     60 
     61 WebContentsImpl* BrowserPluginEmbedder::GetWebContents() const {
     62   return static_cast<WebContentsImpl*>(web_contents());
     63 }
     64 
     65 BrowserPluginGuestManager*
     66 BrowserPluginEmbedder::GetBrowserPluginGuestManager() const {
     67   return GetWebContents()->GetBrowserContext()->GetGuestManager();
     68 }
     69 
     70 void BrowserPluginEmbedder::ClearGuestDragStateIfApplicable() {
     71   // The order at which we observe SystemDragEnded() and DragSourceEndedAt() is
     72   // platform dependent.
     73   // In OSX, we see SystemDragEnded() first, where in aura, we see
     74   // DragSourceEndedAt() first. For this reason, we check if both methods were
     75   // called before resetting |guest_started_drag_|.
     76   if (guest_drag_ending_) {
     77     if (guest_started_drag_)
     78       guest_started_drag_.reset();
     79   } else {
     80     guest_drag_ending_ = true;
     81   }
     82 }
     83 
     84 bool BrowserPluginEmbedder::DidSendScreenRectsCallback(
     85    WebContents* guest_web_contents) {
     86   static_cast<RenderViewHostImpl*>(
     87       guest_web_contents->GetRenderViewHost())->SendScreenRects();
     88   // Not handled => Iterate over all guests.
     89   return false;
     90 }
     91 
     92 void BrowserPluginEmbedder::DidSendScreenRects() {
     93   GetBrowserPluginGuestManager()->ForEachGuest(
     94           GetWebContents(), base::Bind(
     95               &BrowserPluginEmbedder::DidSendScreenRectsCallback,
     96               base::Unretained(this)));
     97 }
     98 
     99 bool BrowserPluginEmbedder::OnMessageReceived(const IPC::Message& message) {
    100   bool handled = true;
    101   IPC_BEGIN_MESSAGE_MAP(BrowserPluginEmbedder, message)
    102     IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Attach, OnAttach)
    103     IPC_MESSAGE_HANDLER_GENERIC(DragHostMsg_UpdateDragCursor,
    104                                 OnUpdateDragCursor(&handled));
    105     IPC_MESSAGE_UNHANDLED(handled = false)
    106   IPC_END_MESSAGE_MAP()
    107   return handled;
    108 }
    109 
    110 void BrowserPluginEmbedder::DragSourceEndedAt(int client_x, int client_y,
    111     int screen_x, int screen_y, blink::WebDragOperation operation) {
    112   if (guest_started_drag_) {
    113     gfx::Point guest_offset =
    114         guest_started_drag_->GetScreenCoordinates(gfx::Point());
    115     guest_started_drag_->DragSourceEndedAt(client_x - guest_offset.x(),
    116         client_y - guest_offset.y(), screen_x, screen_y, operation);
    117   }
    118   ClearGuestDragStateIfApplicable();
    119 }
    120 
    121 void BrowserPluginEmbedder::SystemDragEnded() {
    122   // When the embedder's drag/drop operation ends, we need to pass the message
    123   // to the guest that initiated the drag/drop operation. This will ensure that
    124   // the guest's RVH state is reset properly.
    125   if (guest_started_drag_)
    126     guest_started_drag_->EndSystemDrag();
    127   guest_dragging_over_.reset();
    128   ClearGuestDragStateIfApplicable();
    129 }
    130 
    131 void BrowserPluginEmbedder::OnUpdateDragCursor(bool* handled) {
    132   *handled = (guest_dragging_over_.get() != NULL);
    133 }
    134 
    135 void BrowserPluginEmbedder::OnAttach(
    136     int browser_plugin_instance_id,
    137     const BrowserPluginHostMsg_Attach_Params& params) {
    138   WebContents* guest_web_contents =
    139       GetBrowserPluginGuestManager()->GetGuestByInstanceID(
    140           GetWebContents(), browser_plugin_instance_id);
    141   if (!guest_web_contents)
    142     return;
    143   BrowserPluginGuest* guest = static_cast<WebContentsImpl*>(guest_web_contents)
    144                                   ->GetBrowserPluginGuest();
    145   guest->Attach(browser_plugin_instance_id, GetWebContents(), params);
    146 }
    147 
    148 bool BrowserPluginEmbedder::HandleKeyboardEvent(
    149     const NativeWebKeyboardEvent& event) {
    150   if ((event.windowsKeyCode != ui::VKEY_ESCAPE) ||
    151       (event.modifiers & blink::WebInputEvent::InputModifiers)) {
    152     return false;
    153   }
    154 
    155   bool event_consumed = false;
    156   GetBrowserPluginGuestManager()->ForEachGuest(
    157       GetWebContents(),
    158       base::Bind(&BrowserPluginEmbedder::UnlockMouseIfNecessaryCallback,
    159                  base::Unretained(this),
    160                  &event_consumed));
    161 
    162   return event_consumed;
    163 }
    164 
    165 bool BrowserPluginEmbedder::UnlockMouseIfNecessaryCallback(bool* mouse_unlocked,
    166                                                            WebContents* guest) {
    167   *mouse_unlocked |= static_cast<WebContentsImpl*>(guest)
    168                          ->GetBrowserPluginGuest()
    169                          ->mouse_locked();
    170   guest->GotResponseToLockMouseRequest(false);
    171 
    172   // Returns false to iterate over all guests.
    173   return false;
    174 }
    175 
    176 }  // namespace content
    177