- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / browser_plugin / browser_plugin_embedder.cc
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
26 namespace content {
27
28 // static
29 BrowserPluginHostFactory* BrowserPluginEmbedder::factory_ = NULL;
30
31 BrowserPluginEmbedder::BrowserPluginEmbedder(WebContentsImpl* web_contents)
32     : WebContentsObserver(web_contents),
33       next_get_render_view_request_id_(0) {
34 }
35
36 BrowserPluginEmbedder::~BrowserPluginEmbedder() {
37   CleanUp();
38 }
39
40 // static
41 BrowserPluginEmbedder* BrowserPluginEmbedder::Create(
42     WebContentsImpl* web_contents) {
43   if (factory_)
44     return factory_->CreateBrowserPluginEmbedder(web_contents);
45   return new BrowserPluginEmbedder(web_contents);
46 }
47
48 void BrowserPluginEmbedder::DragEnteredGuest(BrowserPluginGuest* guest) {
49   guest_dragging_over_ = guest->AsWeakPtr();
50 }
51
52 void 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
60 void BrowserPluginEmbedder::StartDrag(BrowserPluginGuest* guest) {
61   guest_started_drag_ = guest->AsWeakPtr();
62 }
63
64 void BrowserPluginEmbedder::StopDrag(BrowserPluginGuest* guest) {
65   if (guest_started_drag_.get() == guest) {
66     guest_started_drag_.reset();
67   }
68 }
69
70 void 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
82 void BrowserPluginEmbedder::DidSendScreenRects() {
83   GetBrowserPluginGuestManager()->DidSendScreenRects(
84       static_cast<WebContentsImpl*>(web_contents()));
85 }
86
87 bool BrowserPluginEmbedder::HandleKeyboardEvent(
88     const NativeWebKeyboardEvent& event) {
89   return GetBrowserPluginGuestManager()->UnlockMouseIfNecessary(
90       static_cast<WebContentsImpl*>(web_contents()), event);
91 }
92
93 void BrowserPluginEmbedder::RenderProcessGone(base::TerminationStatus status) {
94   CleanUp();
95 }
96
97 bool 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
112 void 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
122 void 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
132 void 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
140 void BrowserPluginEmbedder::OnUpdateDragCursor(bool* handled) {
141   *handled = (guest_dragging_over_.get() != NULL);
142 }
143
144 void 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
151 BrowserPluginGuestManager*
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
163 void 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
169 void 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
210 void 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