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