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