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/browser_plugin/browser_plugin_guest_manager.h"
     10 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
     11 #include "content/browser/web_contents/web_contents_impl.h"
     12 #include "content/common/browser_plugin/browser_plugin_constants.h"
     13 #include "content/common/browser_plugin/browser_plugin_messages.h"
     14 #include "content/common/drag_messages.h"
     15 #include "content/common/gpu/gpu_messages.h"
     16 #include "content/public/browser/browser_context.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/user_metrics.h"
     20 #include "content/public/common/content_switches.h"
     21 #include "content/public/common/result_codes.h"
     22 #include "content/public/common/url_constants.h"
     23 #include "net/base/escape.h"
     24 
     25 namespace content {
     26 
     27 // static
     28 BrowserPluginHostFactory* BrowserPluginEmbedder::factory_ = NULL;
     29 
     30 BrowserPluginEmbedder::BrowserPluginEmbedder(WebContentsImpl* web_contents)
     31     : WebContentsObserver(web_contents),
     32       next_get_render_view_request_id_(0) {
     33 }
     34 
     35 BrowserPluginEmbedder::~BrowserPluginEmbedder() {
     36   CleanUp();
     37 }
     38 
     39 // static
     40 BrowserPluginEmbedder* BrowserPluginEmbedder::Create(
     41     WebContentsImpl* web_contents) {
     42   if (factory_)
     43     return factory_->CreateBrowserPluginEmbedder(web_contents);
     44   return new BrowserPluginEmbedder(web_contents);
     45 }
     46 
     47 void BrowserPluginEmbedder::DragEnteredGuest(BrowserPluginGuest* guest) {
     48   guest_dragging_over_ = guest->AsWeakPtr();
     49 }
     50 
     51 void BrowserPluginEmbedder::DragLeftGuest(BrowserPluginGuest* guest) {
     52   // Avoid race conditions in switching between guests being hovered over by
     53   // only un-setting if the caller is marked as the guest being dragged over.
     54   if (guest_dragging_over_.get() == guest) {
     55     guest_dragging_over_.reset();
     56   }
     57 }
     58 
     59 void BrowserPluginEmbedder::StartDrag(BrowserPluginGuest* guest) {
     60   guest_started_drag_ = guest->AsWeakPtr();
     61 }
     62 
     63 void BrowserPluginEmbedder::StopDrag(BrowserPluginGuest* guest) {
     64   if (guest_started_drag_.get() == guest) {
     65     guest_started_drag_.reset();
     66   }
     67 }
     68 
     69 void BrowserPluginEmbedder::GetRenderViewHostAtPosition(
     70     int x, int y, const WebContents::GetRenderViewHostCallback& callback) {
     71   // Store the callback so we can call it later when we have the response.
     72   pending_get_render_view_callbacks_.insert(
     73       std::make_pair(next_get_render_view_request_id_, callback));
     74   Send(new BrowserPluginMsg_PluginAtPositionRequest(
     75       routing_id(),
     76       next_get_render_view_request_id_,
     77       gfx::Point(x, y)));
     78   ++next_get_render_view_request_id_;
     79 }
     80 
     81 void BrowserPluginEmbedder::DidSendScreenRects() {
     82   GetBrowserPluginGuestManager()->DidSendScreenRects(
     83       static_cast<WebContentsImpl*>(web_contents()));
     84 }
     85 
     86 bool BrowserPluginEmbedder::HandleKeyboardEvent(
     87     const NativeWebKeyboardEvent& event) {
     88   return GetBrowserPluginGuestManager()->UnlockMouseIfNecessary(
     89       static_cast<WebContentsImpl*>(web_contents()), event);
     90 }
     91 
     92 void BrowserPluginEmbedder::RenderProcessGone(base::TerminationStatus status) {
     93   CleanUp();
     94 }
     95 
     96 bool BrowserPluginEmbedder::OnMessageReceived(const IPC::Message& message) {
     97   bool handled = true;
     98   IPC_BEGIN_MESSAGE_MAP(BrowserPluginEmbedder, message)
     99     IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_AllocateInstanceID,
    100                         OnAllocateInstanceID)
    101     IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Attach, OnAttach)
    102     IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginAtPositionResponse,
    103                         OnPluginAtPositionResponse)
    104     IPC_MESSAGE_HANDLER_GENERIC(DragHostMsg_UpdateDragCursor,
    105                                 OnUpdateDragCursor(&handled));
    106     IPC_MESSAGE_UNHANDLED(handled = false)
    107   IPC_END_MESSAGE_MAP()
    108   return handled;
    109 }
    110 
    111 void BrowserPluginEmbedder::DragSourceEndedAt(int client_x, int client_y,
    112     int screen_x, int screen_y, WebKit::WebDragOperation operation) {
    113   if (guest_started_drag_.get()) {
    114     gfx::Point guest_offset =
    115         guest_started_drag_->GetScreenCoordinates(gfx::Point());
    116     guest_started_drag_->DragSourceEndedAt(client_x - guest_offset.x(),
    117         client_y - guest_offset.y(), screen_x, screen_y, operation);
    118   }
    119 }
    120 
    121 void BrowserPluginEmbedder::DragSourceMovedTo(int client_x, int client_y,
    122                                               int screen_x, int screen_y) {
    123   if (guest_started_drag_.get()) {
    124     gfx::Point guest_offset =
    125         guest_started_drag_->GetScreenCoordinates(gfx::Point());
    126     guest_started_drag_->DragSourceMovedTo(client_x - guest_offset.x(),
    127         client_y - guest_offset.y(), screen_x, screen_y);
    128   }
    129 }
    130 
    131 void BrowserPluginEmbedder::SystemDragEnded() {
    132   if (guest_started_drag_.get() &&
    133       (guest_started_drag_.get() != guest_dragging_over_.get()))
    134     guest_started_drag_->EndSystemDrag();
    135   guest_started_drag_.reset();
    136   guest_dragging_over_.reset();
    137 }
    138 
    139 void BrowserPluginEmbedder::OnUpdateDragCursor(bool* handled) {
    140   *handled = (guest_dragging_over_.get() != NULL);
    141 }
    142 
    143 void BrowserPluginEmbedder::CleanUp() {
    144   // CleanUp gets called when BrowserPluginEmbedder's WebContents goes away
    145   // or the associated RenderViewHost is destroyed or swapped out. Therefore we
    146   // don't need to care about the pending callbacks anymore.
    147   pending_get_render_view_callbacks_.clear();
    148 }
    149 
    150 BrowserPluginGuestManager*
    151     BrowserPluginEmbedder::GetBrowserPluginGuestManager() {
    152   BrowserPluginGuestManager* guest_manager = static_cast<WebContentsImpl*>(
    153       web_contents())->GetBrowserPluginGuestManager();
    154   if (!guest_manager) {
    155     guest_manager = BrowserPluginGuestManager::Create();
    156     web_contents()->GetBrowserContext()->SetUserData(
    157         browser_plugin::kBrowserPluginGuestManagerKeyName, guest_manager);
    158   }
    159   return guest_manager;
    160 }
    161 
    162 void BrowserPluginEmbedder::OnAllocateInstanceID(int request_id) {
    163   int instance_id = GetBrowserPluginGuestManager()->get_next_instance_id();
    164   Send(new BrowserPluginMsg_AllocateInstanceID_ACK(
    165       routing_id(), request_id, instance_id));
    166 }
    167 
    168 void BrowserPluginEmbedder::OnAttach(
    169     int instance_id,
    170     const BrowserPluginHostMsg_Attach_Params& params,
    171     const base::DictionaryValue& extra_params) {
    172   if (!GetBrowserPluginGuestManager()->CanEmbedderAccessInstanceIDMaybeKill(
    173           web_contents()->GetRenderProcessHost()->GetID(), instance_id))
    174     return;
    175 
    176   BrowserPluginGuest* guest =
    177       GetBrowserPluginGuestManager()->GetGuestByInstanceID(
    178           instance_id, web_contents()->GetRenderProcessHost()->GetID());
    179 
    180 
    181   if (guest) {
    182     // There is an implicit order expectation here:
    183     // 1. The content embedder is made aware of the attachment.
    184     // 2. BrowserPluginGuest::Attach is called.
    185     // 3. The content embedder issues queued events if any that happened
    186     //    prior to attachment.
    187     GetContentClient()->browser()->GuestWebContentsAttached(
    188         guest->GetWebContents(),
    189         web_contents(),
    190         extra_params);
    191     guest->Attach(static_cast<WebContentsImpl*>(web_contents()), params);
    192     return;
    193   }
    194 
    195   scoped_ptr<base::DictionaryValue> copy_extra_params(extra_params.DeepCopy());
    196   guest = GetBrowserPluginGuestManager()->CreateGuest(
    197       web_contents()->GetSiteInstance(),
    198       instance_id, params,
    199       copy_extra_params.Pass());
    200   if (guest) {
    201     GetContentClient()->browser()->GuestWebContentsAttached(
    202         guest->GetWebContents(),
    203         web_contents(),
    204         extra_params);
    205     guest->Initialize(static_cast<WebContentsImpl*>(web_contents()), params);
    206   }
    207 }
    208 
    209 void BrowserPluginEmbedder::OnPluginAtPositionResponse(
    210     int instance_id, int request_id, const gfx::Point& position) {
    211   const std::map<int, WebContents::GetRenderViewHostCallback>::iterator
    212       callback_iter = pending_get_render_view_callbacks_.find(request_id);
    213   if (callback_iter == pending_get_render_view_callbacks_.end())
    214     return;
    215 
    216   RenderViewHost* render_view_host;
    217   BrowserPluginGuest* guest = NULL;
    218   if (instance_id != browser_plugin::kInstanceIDNone) {
    219     guest = GetBrowserPluginGuestManager()->GetGuestByInstanceID(
    220                 instance_id, web_contents()->GetRenderProcessHost()->GetID());
    221   }
    222 
    223   if (guest)
    224     render_view_host = guest->GetWebContents()->GetRenderViewHost();
    225   else  // No plugin, use embedder's RenderViewHost.
    226     render_view_host = web_contents()->GetRenderViewHost();
    227 
    228   callback_iter->second.Run(render_view_host, position.x(), position.y());
    229   pending_get_render_view_callbacks_.erase(callback_iter);
    230 }
    231 
    232 }  // namespace content
    233