blob: 06c94ccc6a32503114185b00f57ced0ce4696ebc [file] [log] [blame]
[email protected]7a846df2012-09-20 19:17:391// 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_guest.h"
6
7#include <algorithm>
8
[email protected]cf200a562013-05-03 16:24:299#include "base/command_line.h"
[email protected]95f861e2013-07-18 02:07:1710#include "base/message_loop/message_loop.h"
[email protected]10994d132013-06-11 07:16:1811#include "base/strings/string_util.h"
[email protected]74ebfb12013-06-07 20:48:0012#include "base/strings/utf_string_conversions.h"
[email protected]c88b2a562012-10-27 03:36:5613#include "content/browser/browser_plugin/browser_plugin_embedder.h"
[email protected]7a846df2012-09-20 19:17:3914#include "content/browser/browser_plugin/browser_plugin_guest_helper.h"
[email protected]8eb04562013-03-06 03:41:1415#include "content/browser/browser_plugin/browser_plugin_guest_manager.h"
[email protected]7a846df2012-09-20 19:17:3916#include "content/browser/browser_plugin/browser_plugin_host_factory.h"
[email protected]f85f5032013-04-03 09:01:5417#include "content/browser/browser_thread_impl.h"
18#include "content/browser/loader/resource_dispatcher_host_impl.h"
[email protected]7a846df2012-09-20 19:17:3919#include "content/browser/renderer_host/render_view_host_impl.h"
20#include "content/browser/renderer_host/render_widget_host_impl.h"
21#include "content/browser/web_contents/web_contents_impl.h"
[email protected]c4538072013-03-18 02:17:5522#include "content/browser/web_contents/web_contents_view_guest.h"
[email protected]8eb04562013-03-06 03:41:1423#include "content/common/browser_plugin/browser_plugin_constants.h"
[email protected]703dd662013-03-05 07:37:4224#include "content/common/browser_plugin/browser_plugin_messages.h"
[email protected]f8501b12012-12-07 04:55:4325#include "content/common/content_constants_internal.h"
[email protected]a7fac9a2012-12-18 23:26:0726#include "content/common/drag_messages.h"
[email protected]cc8ed212013-02-07 22:31:0327#include "content/common/gpu/gpu_messages.h"
[email protected]c084330e02013-04-27 01:08:1528#include "content/common/input_messages.h"
[email protected]c006fb52013-03-01 09:36:4529#include "content/common/view_messages.h"
[email protected]972cdd82012-10-12 00:19:0330#include "content/port/browser/render_view_host_delegate_view.h"
[email protected]8eb04562013-03-06 03:41:1431#include "content/public/browser/browser_context.h"
[email protected]44703cc72013-01-24 04:56:0632#include "content/public/browser/content_browser_client.h"
[email protected]e4a55a52013-03-09 01:32:4933#include "content/public/browser/geolocation_permission_context.h"
[email protected]31942c82012-10-05 17:01:5434#include "content/public/browser/notification_service.h"
35#include "content/public/browser/notification_types.h"
[email protected]7a846df2012-09-20 19:17:3936#include "content/public/browser/render_process_host.h"
37#include "content/public/browser/render_widget_host_view.h"
[email protected]31942c82012-10-05 17:01:5438#include "content/public/browser/resource_request_details.h"
[email protected]2fae2c42012-10-03 21:20:0439#include "content/public/browser/user_metrics.h"
[email protected]1a0c0052012-11-05 21:06:2640#include "content/public/browser/web_contents_view.h"
[email protected]cf200a562013-05-03 16:24:2941#include "content/public/common/content_switches.h"
[email protected]dc293a72013-07-01 11:11:2242#include "content/public/common/drop_data.h"
[email protected]c006fb52013-03-01 09:36:4543#include "content/public/common/media_stream_request.h"
[email protected]7a846df2012-09-20 19:17:3944#include "content/public/common/result_codes.h"
[email protected]f85f5032013-04-03 09:01:5445#include "net/url_request/url_request.h"
[email protected]2255a9332013-06-17 05:12:3146#include "third_party/WebKit/public/web/WebCursorInfo.h"
[email protected]6dd17a8a2013-05-01 05:50:1047#include "ui/base/keycodes/keyboard_codes.h"
[email protected]7a846df2012-09-20 19:17:3948#include "ui/surface/transport_dib.h"
[email protected]d0fcff72013-07-23 02:45:4349#include "webkit/common/resource_type.h"
[email protected]7a846df2012-09-20 19:17:3950
[email protected]4f89d9d2012-12-12 01:38:4851#if defined(OS_MACOSX)
52#include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
53#endif
54
[email protected]7a846df2012-09-20 19:17:3955namespace content {
56
57// static
58BrowserPluginHostFactory* BrowserPluginGuest::factory_ = NULL;
59
[email protected]cf4c9e052013-05-04 04:53:4460// Parent class for the various types of permission requests, each of which
61// should be able to handle the response to their permission request.
[email protected]291dcf32013-07-28 08:02:1462class BrowserPluginGuest::PermissionRequest :
63 public base::RefCounted<BrowserPluginGuest::PermissionRequest> {
[email protected]cf4c9e052013-05-04 04:53:4464 public:
[email protected]1c514fc2013-07-24 07:30:5365 virtual void Respond(bool should_allow, const std::string& user_input) = 0;
[email protected]cf4c9e052013-05-04 04:53:4466 protected:
[email protected]abc7d5c2013-05-15 09:19:2567 PermissionRequest() {
68 RecordAction(UserMetricsAction("BrowserPlugin.Guest.PermissionRequest"));
69 }
[email protected]291dcf32013-07-28 08:02:1470 virtual ~PermissionRequest() {}
71 // Friend RefCounted so that the dtor can be non-public.
72 friend class base::RefCounted<BrowserPluginGuest::PermissionRequest>;
[email protected]cf4c9e052013-05-04 04:53:4473};
74
75class BrowserPluginGuest::DownloadRequest : public PermissionRequest {
76 public:
77 explicit DownloadRequest(base::Callback<void(bool)> callback)
[email protected]dadac572013-06-12 22:52:0278 : callback_(callback) {
79 RecordAction(
80 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Download"));
81 }
[email protected]1c514fc2013-07-24 07:30:5382 virtual void Respond(bool should_allow,
83 const std::string& user_input) OVERRIDE {
[email protected]cf4c9e052013-05-04 04:53:4484 callback_.Run(should_allow);
85 }
[email protected]b60b88942013-07-20 05:58:4286
[email protected]cf4c9e052013-05-04 04:53:4487 private:
[email protected]291dcf32013-07-28 08:02:1488 virtual ~DownloadRequest() {}
[email protected]cf4c9e052013-05-04 04:53:4489 base::Callback<void(bool)> callback_;
90};
91
92class BrowserPluginGuest::GeolocationRequest : public PermissionRequest {
93 public:
94 GeolocationRequest(GeolocationCallback callback,
95 int bridge_id,
[email protected]cf4c9e052013-05-04 04:53:4496 base::WeakPtrFactory<BrowserPluginGuest>* weak_ptr_factory)
97 : callback_(callback),
98 bridge_id_(bridge_id),
[email protected]dadac572013-06-12 22:52:0299 weak_ptr_factory_(weak_ptr_factory) {
100 RecordAction(
101 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Geolocation"));
102 }
[email protected]cf4c9e052013-05-04 04:53:44103
[email protected]1c514fc2013-07-24 07:30:53104 virtual void Respond(bool should_allow,
105 const std::string& user_input) OVERRIDE {
[email protected]291dcf32013-07-28 08:02:14106 base::WeakPtr<BrowserPluginGuest> guest(weak_ptr_factory_->GetWeakPtr());
107
108 WebContents* web_contents = guest->embedder_web_contents();
[email protected]cf4c9e052013-05-04 04:53:44109 if (should_allow && web_contents) {
110 // If renderer side embedder decides to allow gelocation, we need to check
111 // if the app/embedder itself has geolocation access.
112 BrowserContext* browser_context = web_contents->GetBrowserContext();
113 if (browser_context) {
114 GeolocationPermissionContext* geolocation_context =
115 browser_context->GetGeolocationPermissionContext();
116 if (geolocation_context) {
117 base::Callback<void(bool)> geolocation_callback = base::Bind(
118 &BrowserPluginGuest::SetGeolocationPermission,
[email protected]291dcf32013-07-28 08:02:14119 guest,
[email protected]cf4c9e052013-05-04 04:53:44120 callback_,
121 bridge_id_);
122 geolocation_context->RequestGeolocationPermission(
123 web_contents->GetRenderProcessHost()->GetID(),
124 web_contents->GetRoutingID(),
125 // The geolocation permission request here is not initiated
126 // through WebGeolocationPermissionRequest. We are only interested
127 // in the fact whether the embedder/app has geolocation
128 // permission. Therefore we use an invalid |bridge_id|.
129 -1 /* bridge_id */,
130 web_contents->GetURL(),
131 geolocation_callback);
132 return;
133 }
134 }
135 }
[email protected]291dcf32013-07-28 08:02:14136 guest->SetGeolocationPermission(callback_, bridge_id_, false);
[email protected]cf4c9e052013-05-04 04:53:44137 }
[email protected]b60b88942013-07-20 05:58:42138
[email protected]cf4c9e052013-05-04 04:53:44139 private:
[email protected]291dcf32013-07-28 08:02:14140 virtual ~GeolocationRequest() {}
[email protected]cf4c9e052013-05-04 04:53:44141 base::Callback<void(bool)> callback_;
142 int bridge_id_;
[email protected]cf4c9e052013-05-04 04:53:44143 base::WeakPtrFactory<BrowserPluginGuest>* weak_ptr_factory_;
144};
145
146class BrowserPluginGuest::MediaRequest : public PermissionRequest {
147 public:
148 MediaRequest(const MediaStreamRequest& request,
149 const MediaResponseCallback& callback,
150 BrowserPluginGuest* guest)
151 : request_(request),
152 callback_(callback),
[email protected]dadac572013-06-12 22:52:02153 guest_(guest) {
154 RecordAction(
155 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Media"));
156 }
[email protected]cf4c9e052013-05-04 04:53:44157
[email protected]1c514fc2013-07-24 07:30:53158 virtual void Respond(bool should_allow,
159 const std::string& user_input) OVERRIDE {
[email protected]cf4c9e052013-05-04 04:53:44160 WebContentsImpl* web_contents = guest_->embedder_web_contents();
161 if (should_allow && web_contents) {
162 // Re-route the request to the embedder's WebContents; the guest gets the
163 // permission this way.
164 web_contents->RequestMediaAccessPermission(request_, callback_);
165 } else {
166 // Deny the request.
167 callback_.Run(MediaStreamDevices(), scoped_ptr<MediaStreamUI>());
168 }
[email protected]e06008d852013-07-18 02:31:22169 }
[email protected]b60b88942013-07-20 05:58:42170
[email protected]cf4c9e052013-05-04 04:53:44171 private:
[email protected]291dcf32013-07-28 08:02:14172 virtual ~MediaRequest() {}
[email protected]cf4c9e052013-05-04 04:53:44173 MediaStreamRequest request_;
174 MediaResponseCallback callback_;
175 BrowserPluginGuest* guest_;
176};
177
178class BrowserPluginGuest::NewWindowRequest : public PermissionRequest {
179 public:
180 NewWindowRequest(int instance_id, BrowserPluginGuest* guest)
181 : instance_id_(instance_id),
[email protected]dadac572013-06-12 22:52:02182 guest_(guest) {
183 RecordAction(
184 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.NewWindow"));
185 }
[email protected]cf4c9e052013-05-04 04:53:44186
[email protected]1c514fc2013-07-24 07:30:53187 virtual void Respond(bool should_allow,
188 const std::string& user_input) OVERRIDE {
[email protected]cf4c9e052013-05-04 04:53:44189 int embedder_render_process_id =
190 guest_->embedder_web_contents()->GetRenderProcessHost()->GetID();
191 BrowserPluginGuest* guest =
192 guest_->GetWebContents()->GetBrowserPluginGuestManager()->
193 GetGuestByInstanceID(instance_id_, embedder_render_process_id);
194 if (!guest) {
195 LOG(INFO) << "Guest not found. Instance ID: " << instance_id_;
196 return;
197 }
198
199 // If we do not destroy the guest then we allow the new window.
200 if (!should_allow)
201 guest->Destroy();
202 }
[email protected]b60b88942013-07-20 05:58:42203
[email protected]cf4c9e052013-05-04 04:53:44204 private:
[email protected]291dcf32013-07-28 08:02:14205 virtual ~NewWindowRequest() {}
[email protected]cf4c9e052013-05-04 04:53:44206 int instance_id_;
207 BrowserPluginGuest* guest_;
208};
209
[email protected]1c514fc2013-07-24 07:30:53210class BrowserPluginGuest::JavaScriptDialogRequest : public PermissionRequest {
211 public:
212 JavaScriptDialogRequest(const DialogClosedCallback& callback)
213 : callback_(callback) {
214 RecordAction(
215 UserMetricsAction(
216 "BrowserPlugin.Guest.PermissionRequest.JavaScriptDialog"));
217 }
218
219 virtual void Respond(bool should_allow,
220 const std::string& user_input) OVERRIDE {
221 callback_.Run(should_allow, UTF8ToUTF16(user_input));
222 }
223
[email protected]1c514fc2013-07-24 07:30:53224 private:
[email protected]291dcf32013-07-28 08:02:14225 virtual ~JavaScriptDialogRequest() {}
226 DialogClosedCallback callback_;
[email protected]1c514fc2013-07-24 07:30:53227};
228
[email protected]b60b88942013-07-20 05:58:42229class BrowserPluginGuest::PointerLockRequest : public PermissionRequest {
230 public:
231 PointerLockRequest(BrowserPluginGuest* guest)
232 : guest_(guest) {
233 RecordAction(
234 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.PointerLock"));
235 }
236
[email protected]1c514fc2013-07-24 07:30:53237 virtual void Respond(bool should_allow,
238 const std::string& user_input) OVERRIDE {
[email protected]b60b88942013-07-20 05:58:42239 guest_->SendMessageToEmbedder(
240 new BrowserPluginMsg_SetMouseLock(guest_->instance_id(), should_allow));
241 }
242
[email protected]b60b88942013-07-20 05:58:42243 private:
[email protected]291dcf32013-07-28 08:02:14244 virtual ~PointerLockRequest() {}
[email protected]b60b88942013-07-20 05:58:42245 BrowserPluginGuest* guest_;
246};
247
[email protected]c006fb52013-03-01 09:36:45248namespace {
[email protected]e4a55a52013-03-09 01:32:49249const size_t kNumMaxOutstandingPermissionRequests = 1024;
[email protected]c4538072013-03-18 02:17:55250
[email protected]1c514fc2013-07-24 07:30:53251std::string WindowOpenDispositionToString(
[email protected]c4538072013-03-18 02:17:55252 WindowOpenDisposition window_open_disposition) {
253 switch (window_open_disposition) {
[email protected]1c514fc2013-07-24 07:30:53254 case IGNORE_ACTION:
255 return "ignore";
256 case SAVE_TO_DISK:
257 return "save_to_disk";
258 case CURRENT_TAB:
259 return "current_tab";
260 case NEW_BACKGROUND_TAB:
261 return "new_background_tab";
262 case NEW_FOREGROUND_TAB:
263 return "new_foreground_tab";
264 case NEW_WINDOW:
265 return "new_window";
266 case NEW_POPUP:
267 return "new_popup";
268 default:
269 NOTREACHED() << "Unknown Window Open Disposition";
270 return "ignore";
271 }
272}
273
274std::string JavaScriptMessageTypeToString(JavaScriptMessageType message_type) {
275 switch (message_type) {
276 case JAVASCRIPT_MESSAGE_TYPE_ALERT:
277 return "alert";
278 case JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
279 return "confirm";
280 case JAVASCRIPT_MESSAGE_TYPE_PROMPT:
281 return "prompt";
282 default:
283 NOTREACHED() << "Unknown JavaScript Message Type.";
284 return "unknown";
[email protected]c4538072013-03-18 02:17:55285 }
286}
287
[email protected]f85f5032013-04-03 09:01:54288// Called on IO thread.
289static std::string RetrieveDownloadURLFromRequestId(
290 RenderViewHost* render_view_host,
291 int url_request_id) {
292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
293
294 int render_process_id = render_view_host->GetProcess()->GetID();
295 GlobalRequestID global_id(render_process_id, url_request_id);
296 net::URLRequest* url_request =
297 ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id);
298 if (url_request)
299 return url_request->url().possibly_invalid_spec();
[email protected]007b3f82013-04-09 08:46:45300 return std::string();
[email protected]f85f5032013-04-03 09:01:54301}
302
[email protected]cf4c9e052013-05-04 04:53:44303} // namespace
[email protected]c006fb52013-03-01 09:36:45304
[email protected]ce0e2602013-03-15 20:53:27305class BrowserPluginGuest::EmbedderRenderViewHostObserver
306 : public RenderViewHostObserver {
307 public:
308 explicit EmbedderRenderViewHostObserver(BrowserPluginGuest* guest)
309 : RenderViewHostObserver(
310 guest->embedder_web_contents()->GetRenderViewHost()),
311 browser_plugin_guest_(guest) {
312 }
313
314 virtual ~EmbedderRenderViewHostObserver() {
315 }
316
317 // RenderViewHostObserver:
318 virtual void RenderViewHostDestroyed(
319 RenderViewHost* render_view_host) OVERRIDE {
[email protected]6dd17a8a2013-05-01 05:50:10320 browser_plugin_guest_->embedder_web_contents_ = NULL;
[email protected]ce0e2602013-03-15 20:53:27321 browser_plugin_guest_->Destroy();
322 }
323
324 private:
325 BrowserPluginGuest* browser_plugin_guest_;
326
327 DISALLOW_COPY_AND_ASSIGN(EmbedderRenderViewHostObserver);
328};
329
[email protected]dd8c8232012-11-03 00:49:36330BrowserPluginGuest::BrowserPluginGuest(
331 int instance_id,
[email protected]0c6d41752013-05-01 15:49:09332 WebContentsImpl* web_contents,
333 BrowserPluginGuest* opener,
334 bool has_render_view)
[email protected]7a846df2012-09-20 19:17:39335 : WebContentsObserver(web_contents),
[email protected]69e797f2013-04-30 01:10:22336 weak_ptr_factory_(this),
[email protected]8eb04562013-03-06 03:41:14337 embedder_web_contents_(NULL),
[email protected]7a846df2012-09-20 19:17:39338 instance_id_(instance_id),
[email protected]4d1afd62012-12-21 03:09:40339 damage_buffer_sequence_id_(0),
[email protected]7a846df2012-09-20 19:17:39340 damage_buffer_size_(0),
[email protected]fda17082012-10-04 00:25:21341 damage_buffer_scale_factor_(1.0f),
[email protected]caaf2482013-05-01 20:33:32342 guest_device_scale_factor_(1.0f),
[email protected]7a846df2012-09-20 19:17:39343 guest_hang_timeout_(
[email protected]f8501b12012-12-07 04:55:43344 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)),
[email protected]c4538072013-03-18 02:17:55345 focused_(false),
[email protected]861f9782013-03-05 03:29:54346 mouse_locked_(false),
[email protected]a25acea72013-03-10 23:41:28347 pending_lock_request_(false),
[email protected]93564f72013-02-15 13:26:19348 embedder_visible_(true),
[email protected]af1718c2013-08-12 19:59:19349 next_permission_request_id_(browser_plugin::kInvalidPermissionRequestID),
[email protected]0c6d41752013-05-01 15:49:09350 has_render_view_(has_render_view) {
[email protected]7a846df2012-09-20 19:17:39351 DCHECK(web_contents);
[email protected]93564f72013-02-15 13:26:19352 web_contents->SetDelegate(this);
[email protected]0c6d41752013-05-01 15:49:09353 if (opener)
354 opener_ = opener->AsWeakPtr();
[email protected]8eb04562013-03-06 03:41:14355 GetWebContents()->GetBrowserPluginGuestManager()->AddGuest(instance_id_,
356 GetWebContents());
[email protected]b5a40842012-11-28 15:26:11357}
358
[email protected]eb72af632013-04-30 01:05:21359bool BrowserPluginGuest::AddMessageToConsole(WebContents* source,
360 int32 level,
361 const string16& message,
362 int32 line_no,
363 const string16& source_id) {
[email protected]4c0e8272013-07-03 23:39:22364 if (!delegate_)
365 return false;
366
367 delegate_->AddMessageToConsole(level, message, line_no, source_id);
368 return true;
[email protected]eb72af632013-04-30 01:05:21369}
370
[email protected]c4538072013-03-18 02:17:55371void BrowserPluginGuest::DestroyUnattachedWindows() {
372 // Destroy() reaches in and removes the BrowserPluginGuest from its opener's
373 // pending_new_windows_ set. To avoid mutating the set while iterating, we
374 // create a copy of the pending new windows set and iterate over the copy.
375 PendingWindowMap pending_new_windows(pending_new_windows_);
376 // Clean up unattached new windows opened by this guest.
377 for (PendingWindowMap::const_iterator it = pending_new_windows.begin();
378 it != pending_new_windows.end(); ++it) {
379 it->first->Destroy();
380 }
381 // All pending windows should be removed from the set after Destroy() is
382 // called on all of them.
383 DCHECK_EQ(0ul, pending_new_windows_.size());
384}
385
[email protected]af1718c2013-08-12 19:59:19386void BrowserPluginGuest::RespondToPermissionRequest(
387 int request_id,
388 bool should_allow,
389 const std::string& user_input) {
390 RequestMap::iterator request_itr = permission_request_map_.find(request_id);
391 if (request_itr == permission_request_map_.end()) {
392 LOG(INFO) << "Not a valid request ID.";
393 return;
394 }
395 request_itr->second->Respond(should_allow, user_input);
396 permission_request_map_.erase(request_itr);
397}
398
[email protected]291dcf32013-07-28 08:02:14399int BrowserPluginGuest::RequestPermission(
400 BrowserPluginPermissionType permission_type,
401 scoped_refptr<BrowserPluginGuest::PermissionRequest> request,
402 const base::DictionaryValue& request_info) {
[email protected]af1718c2013-08-12 19:59:19403 if (!delegate_) {
404 request->Respond(false, "");
405 return browser_plugin::kInvalidPermissionRequestID;
406 }
407
408 int request_id = ++next_permission_request_id_;
[email protected]291dcf32013-07-28 08:02:14409 permission_request_map_[request_id] = request;
410
[email protected]af1718c2013-08-12 19:59:19411 BrowserPluginGuestDelegate::PermissionResponseCallback callback =
412 base::Bind(&BrowserPluginGuest::RespondToPermissionRequest,
413 AsWeakPtr(),
414 request_id);
415 // If BrowserPluginGuestDelegate hasn't handled the permission then we simply
416 // reject it immediately.
417 if (!delegate_->RequestPermission(permission_type, request_info, callback))
418 callback.Run(false, "");
[email protected]291dcf32013-07-28 08:02:14419
420 return request_id;
421}
422
[email protected]b371a5652013-02-20 11:25:51423void BrowserPluginGuest::Destroy() {
[email protected]c4538072013-03-18 02:17:55424 if (!attached() && opener())
425 opener()->pending_new_windows_.erase(this);
426 DestroyUnattachedWindows();
[email protected]8eb04562013-03-06 03:41:14427 GetWebContents()->GetBrowserPluginGuestManager()->RemoveGuest(instance_id_);
428 delete GetWebContents();
[email protected]b371a5652013-02-20 11:25:51429}
430
[email protected]3997b1b22012-12-20 01:02:54431bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
432 const IPC::Message& message) {
433 bool handled = true;
434 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
[email protected]cc8ed212013-02-07 22:31:03435 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_BuffersSwappedACK,
436 OnSwapBuffersACK)
[email protected]f5b4b0f2013-04-02 18:16:28437 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameACK,
438 OnCompositorFrameACK)
[email protected]3997b1b22012-12-20 01:02:54439 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
440 OnDragStatusUpdate)
[email protected]6dd17a8a2013-05-01 05:50:10441 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
442 OnExecuteEditCommand)
[email protected]3997b1b22012-12-20 01:02:54443 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent,
444 OnHandleInputEvent)
[email protected]861f9782013-03-05 03:29:54445 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
[email protected]5e7967972013-01-15 22:45:33446 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_NavigateGuest, OnNavigateGuest)
[email protected]b371a5652013-02-20 11:25:51447 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed)
[email protected]3997b1b22012-12-20 01:02:54448 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
[email protected]3997b1b22012-12-20 01:02:54449 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetSize)
[email protected]b77fac52013-06-01 01:03:46450 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
451 OnSetEditCommandsForNextKeyEvent)
[email protected]3997b1b22012-12-20 01:02:54452 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
[email protected]25bcc8f2013-01-09 02:49:25453 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetName, OnSetName)
[email protected]3997b1b22012-12-20 01:02:54454 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
[email protected]861f9782013-03-05 03:29:54455 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
[email protected]32deec62013-05-15 23:55:04456 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
[email protected]3997b1b22012-12-20 01:02:54457 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateRect_ACK, OnUpdateRectACK)
458 IPC_MESSAGE_UNHANDLED(handled = false)
459 IPC_END_MESSAGE_MAP()
460 return handled;
461}
462
463void BrowserPluginGuest::Initialize(
[email protected]8eb04562013-03-06 03:41:14464 WebContentsImpl* embedder_web_contents,
[email protected]4b4ed582013-05-01 00:16:23465 const BrowserPluginHostMsg_Attach_Params& params) {
[email protected]c4538072013-03-18 02:17:55466 focused_ = params.focused;
467 guest_visible_ = params.visible;
[email protected]32deec62013-05-15 23:55:04468 guest_window_rect_ = params.resize_guest_params.view_rect;
469
[email protected]50de3222013-03-20 15:36:13470 if (!params.name.empty())
471 name_ = params.name;
[email protected]c4538072013-03-18 02:17:55472 auto_size_enabled_ = params.auto_size_params.enable;
473 max_auto_size_ = params.auto_size_params.max_size;
474 min_auto_size_ = params.auto_size_params.min_size;
475
476 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
477 // be attached.
478 embedder_web_contents_ = embedder_web_contents;
479
[email protected]2b3c7b32013-07-24 23:47:42480 WebContentsViewGuest* new_view =
481 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
482 new_view->OnGuestInitialized(embedder_web_contents->GetView());
483
[email protected]7a846df2012-09-20 19:17:39484 // |render_view_host| manages the ownership of this BrowserPluginGuestHelper.
[email protected]8eb04562013-03-06 03:41:14485 new BrowserPluginGuestHelper(this, GetWebContents()->GetRenderViewHost());
486
[email protected]8eb04562013-03-06 03:41:14487 RendererPreferences* renderer_prefs =
488 GetWebContents()->GetMutableRendererPrefs();
489 // Copy renderer preferences (and nothing else) from the embedder's
490 // WebContents to the guest.
491 //
492 // For GTK and Aura this is necessary to get proper renderer configuration
493 // values for caret blinking interval, colors related to selection and
494 // focus.
495 *renderer_prefs = *embedder_web_contents_->GetMutableRendererPrefs();
496
[email protected]8eb04562013-03-06 03:41:14497 // We would like the guest to report changes to frame names so that we can
498 // update the BrowserPlugin's corresponding 'name' attribute.
499 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
500 renderer_prefs->report_frame_name_changes = true;
501 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
502 // navigations still continue to function inside the app.
503 renderer_prefs->browser_handles_all_top_level_requests = false;
[email protected]31942c82012-10-05 17:01:54504
[email protected]93564f72013-02-15 13:26:19505 // Listen to embedder visibility changes so that the guest is in a 'shown'
506 // state if both the embedder is visible and the BrowserPlugin is marked as
507 // visible.
508 notification_registrar_.Add(
[email protected]ce0e2602013-03-15 20:53:27509 this, NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
[email protected]b371a5652013-02-20 11:25:51510 Source<WebContents>(embedder_web_contents_));
511
[email protected]ce0e2602013-03-15 20:53:27512 embedder_rvh_observer_.reset(new EmbedderRenderViewHostObserver(this));
[email protected]93564f72013-02-15 13:26:19513
[email protected]3997b1b22012-12-20 01:02:54514 OnSetSize(instance_id_, params.auto_size_params, params.resize_guest_params);
[email protected]44703cc72013-01-24 04:56:06515
[email protected]93564f72013-02-15 13:26:19516 // Create a swapped out RenderView for the guest in the embedder render
517 // process, so that the embedder can access the guest's window object.
518 int guest_routing_id =
[email protected]8eb04562013-03-06 03:41:14519 GetWebContents()->CreateSwappedOutRenderView(
520 embedder_web_contents_->GetSiteInstance());
[email protected]d752fe62013-03-01 03:46:01521 SendMessageToEmbedder(
522 new BrowserPluginMsg_GuestContentWindowReady(instance_id_,
523 guest_routing_id));
[email protected]93564f72013-02-15 13:26:19524
525 if (!params.src.empty())
526 OnNavigateGuest(instance_id_, params.src);
527
[email protected]0c6d41752013-05-01 15:49:09528 has_render_view_ = true;
[email protected]d10bbddf2013-06-06 23:38:31529
530 if (!embedder_web_contents_->
531 GetWebkitPrefs().accelerated_compositing_enabled) {
532 WebPreferences prefs = GetWebContents()->GetWebkitPrefs();
533 prefs.accelerated_compositing_enabled = false;
534 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
535 }
[email protected]523c89de2013-06-12 16:30:04536
537 // Enable input method for guest if it's enabled for the embedder.
538 if (static_cast<RenderViewHostImpl*>(
539 embedder_web_contents_->GetRenderViewHost())->input_method_active()) {
540 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
541 GetWebContents()->GetRenderViewHost());
542 guest_rvh->SetInputMethodActive(true);
543 }
[email protected]7a846df2012-09-20 19:17:39544}
545
546BrowserPluginGuest::~BrowserPluginGuest() {
[email protected]697f16b52013-05-10 06:01:18547 while (!pending_messages_.empty()) {
548 delete pending_messages_.front();
549 pending_messages_.pop();
550 }
[email protected]7a846df2012-09-20 19:17:39551}
552
553// static
554BrowserPluginGuest* BrowserPluginGuest::Create(
555 int instance_id,
[email protected]738f57a2013-06-29 21:06:54556 WebContentsImpl* web_contents,
557 scoped_ptr<base::DictionaryValue> extra_params) {
[email protected]2fae2c42012-10-03 21:20:04558 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Create"));
[email protected]738f57a2013-06-29 21:06:54559 BrowserPluginGuest* guest = NULL;
560 if (factory_) {
561 guest = factory_->CreateBrowserPluginGuest(instance_id, web_contents);
562 } else {
563 guest = new BrowserPluginGuest(instance_id, web_contents, NULL, false);
564 }
565 web_contents->SetBrowserPluginGuest(guest);
[email protected]4c0e8272013-07-03 23:39:22566 BrowserPluginGuestDelegate* delegate = NULL;
[email protected]738f57a2013-06-29 21:06:54567 GetContentClient()->browser()->GuestWebContentsCreated(
[email protected]4c0e8272013-07-03 23:39:22568 web_contents, NULL, &delegate, extra_params.Pass());
569 guest->SetDelegate(delegate);
[email protected]738f57a2013-06-29 21:06:54570 return guest;
[email protected]0c6d41752013-05-01 15:49:09571}
572
573// static
574BrowserPluginGuest* BrowserPluginGuest::CreateWithOpener(
575 int instance_id,
576 WebContentsImpl* web_contents,
577 BrowserPluginGuest* opener,
578 bool has_render_view) {
[email protected]738f57a2013-06-29 21:06:54579 BrowserPluginGuest* guest =
580 new BrowserPluginGuest(
581 instance_id, web_contents, opener, has_render_view);
582 web_contents->SetBrowserPluginGuest(guest);
[email protected]4c0e8272013-07-03 23:39:22583 BrowserPluginGuestDelegate* delegate = NULL;
[email protected]738f57a2013-06-29 21:06:54584 GetContentClient()->browser()->GuestWebContentsCreated(
[email protected]4c0e8272013-07-03 23:39:22585 web_contents, opener->GetWebContents(), &delegate,
[email protected]738f57a2013-06-29 21:06:54586 scoped_ptr<base::DictionaryValue>());
[email protected]4c0e8272013-07-03 23:39:22587 guest->SetDelegate(delegate);
[email protected]738f57a2013-06-29 21:06:54588 return guest;
[email protected]7a846df2012-09-20 19:17:39589}
590
[email protected]44327692013-02-26 21:21:22591RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() {
592 return embedder_web_contents_->GetRenderWidgetHostView();
593}
594
[email protected]3997b1b22012-12-20 01:02:54595void BrowserPluginGuest::UpdateVisibility() {
596 OnSetVisibility(instance_id_, visible());
597}
598
[email protected]32deec62013-05-15 23:55:04599// screen.
600gfx::Rect BrowserPluginGuest::ToGuestRect(const gfx::Rect& bounds) {
601 gfx::Rect guest_rect(bounds);
602 guest_rect.Offset(guest_window_rect_.OffsetFromOrigin());
603 return guest_rect;
604}
605
[email protected]31942c82012-10-05 17:01:54606void BrowserPluginGuest::Observe(int type,
607 const NotificationSource& source,
608 const NotificationDetails& details) {
609 switch (type) {
[email protected]93564f72013-02-15 13:26:19610 case NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED: {
611 DCHECK_EQ(Source<WebContents>(source).ptr(), embedder_web_contents_);
612 embedder_visible_ = *Details<bool>(details).ptr();
613 UpdateVisibility();
614 break;
615 }
[email protected]31942c82012-10-05 17:01:54616 default:
617 NOTREACHED() << "Unexpected notification sent.";
618 break;
619 }
620}
621
[email protected]c4538072013-03-18 02:17:55622void BrowserPluginGuest::AddNewContents(WebContents* source,
623 WebContents* new_contents,
624 WindowOpenDisposition disposition,
625 const gfx::Rect& initial_pos,
626 bool user_gesture,
627 bool* was_blocked) {
[email protected]d70bea92013-04-05 04:23:34628 if (was_blocked)
629 *was_blocked = false;
[email protected]c4538072013-03-18 02:17:55630 RequestNewWindowPermission(static_cast<WebContentsImpl*>(new_contents),
631 disposition, initial_pos, user_gesture);
632}
633
[email protected]f85f5032013-04-03 09:01:54634void BrowserPluginGuest::CanDownload(
635 RenderViewHost* render_view_host,
636 int request_id,
637 const std::string& request_method,
638 const base::Callback<void(bool)>& callback) {
[email protected]cf4c9e052013-05-04 04:53:44639 if (permission_request_map_.size() >= kNumMaxOutstandingPermissionRequests) {
[email protected]f85f5032013-04-03 09:01:54640 // Deny the download request.
641 callback.Run(false);
642 return;
643 }
644
[email protected]f85f5032013-04-03 09:01:54645 BrowserThread::PostTaskAndReplyWithResult(
646 BrowserThread::IO, FROM_HERE,
647 base::Bind(&RetrieveDownloadURLFromRequestId,
648 render_view_host, request_id),
649 base::Bind(&BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId,
650 weak_ptr_factory_.GetWeakPtr(),
651 request_method,
[email protected]291dcf32013-07-28 08:02:14652 callback));
[email protected]4aefa0c2012-10-04 20:01:19653}
654
[email protected]f9fb1032013-05-02 22:12:57655void BrowserPluginGuest::CloseContents(WebContents* source) {
[email protected]c84c6af2013-07-04 02:36:04656 if (!delegate_)
657 return;
658
659 delegate_->Close();
[email protected]f9fb1032013-05-02 22:12:57660}
661
[email protected]1c514fc2013-07-24 07:30:53662JavaScriptDialogManager* BrowserPluginGuest::GetJavaScriptDialogManager() {
663 return this;
664}
665
[email protected]cb8d7cf22013-06-19 04:16:43666bool BrowserPluginGuest::HandleContextMenu(const ContextMenuParams& params) {
667 // TODO(fsamuel): We show the regular page context menu handler for now until
[email protected]14d59b332012-10-05 01:40:28668 // we implement the Apps Context Menu API for Browser Plugin (see
669 // http://crbug.com/140315).
[email protected]cb8d7cf22013-06-19 04:16:43670 return false; // Will be handled by WebContentsViewGuest.
[email protected]14d59b332012-10-05 01:40:28671}
672
[email protected]6dd17a8a2013-05-01 05:50:10673void BrowserPluginGuest::HandleKeyboardEvent(
674 WebContents* source,
675 const NativeWebKeyboardEvent& event) {
676 if (!attached())
677 return;
678
[email protected]6d5c060a2013-06-18 11:27:06679 if (UnlockMouseIfNecessary(event))
680 return;
681
[email protected]926d4f42013-07-12 23:11:17682 if (delegate_ && delegate_->HandleKeyboardEvent(event))
683 return;
684
[email protected]6dd17a8a2013-05-01 05:50:10685 // Send the unhandled keyboard events back to the embedder to reprocess them.
686 // TODO(fsamuel): This introduces the possibility of out-of-order keyboard
687 // events because the guest may be arbitrarily delayed when responding to
688 // keyboard events. In that time, the embedder may have received and processed
689 // additional key events. This needs to be fixed as soon as possible.
690 // See http://crbug.com/229882.
691 embedder_web_contents_->GetDelegate()->HandleKeyboardEvent(
692 web_contents(), event);
693}
694
[email protected]0c6d41752013-05-01 15:49:09695WebContents* BrowserPluginGuest::OpenURLFromTab(WebContents* source,
696 const OpenURLParams& params) {
697 // If the guest wishes to navigate away prior to attachment then we save the
698 // navigation to perform upon attachment. Navigation initializes a lot of
699 // state that assumes an embedder exists, such as RenderWidgetHostViewGuest.
700 // Navigation also resumes resource loading which we don't want to allow
701 // until attachment.
702 if (!attached()) {
703 PendingWindowMap::iterator it = opener()->pending_new_windows_.find(this);
704 if (it == opener()->pending_new_windows_.end())
705 return NULL;
[email protected]96584eec2013-05-07 13:25:32706 const NewWindowInfo& old_target_url = it->second;
707 NewWindowInfo new_window_info(params.url, old_target_url.name);
708 new_window_info.changed = new_window_info.url != old_target_url.url;
709 it->second = new_window_info;
[email protected]0c6d41752013-05-01 15:49:09710 return NULL;
711 }
712 // This can happen for cross-site redirects.
713 source->GetController().LoadURL(
714 params.url, params.referrer, params.transition, std::string());
715 return source;
716}
717
[email protected]c4538072013-03-18 02:17:55718void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents,
719 int64 source_frame_id,
[email protected]50de3222013-03-20 15:36:13720 const string16& frame_name,
[email protected]c4538072013-03-18 02:17:55721 const GURL& target_url,
722 WebContents* new_contents) {
723 WebContentsImpl* new_contents_impl =
724 static_cast<WebContentsImpl*>(new_contents);
725 BrowserPluginGuest* guest = new_contents_impl->GetBrowserPluginGuest();
[email protected]6dd17a8a2013-05-01 05:50:10726 guest->opener_ = AsWeakPtr();
[email protected]96584eec2013-05-07 13:25:32727 std::string guest_name = UTF16ToUTF8(frame_name);
728 guest->name_ = guest_name;
[email protected]c4538072013-03-18 02:17:55729 // Take ownership of the new guest until it is attached to the embedder's DOM
730 // tree to avoid leaking a guest if this guest is destroyed before attaching
731 // the new guest.
[email protected]96584eec2013-05-07 13:25:32732 pending_new_windows_.insert(
733 std::make_pair(guest, NewWindowInfo(target_url, guest_name)));
[email protected]c4538072013-03-18 02:17:55734}
735
[email protected]7a846df2012-09-20 19:17:39736void BrowserPluginGuest::RendererUnresponsive(WebContents* source) {
[email protected]2fae2c42012-10-03 21:20:04737 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Hung"));
[email protected]fcf5a7a2013-07-26 06:18:01738 if (!delegate_)
739 return;
740 delegate_->RendererUnresponsive();
[email protected]7a846df2012-09-20 19:17:39741}
742
[email protected]f8501b12012-12-07 04:55:43743void BrowserPluginGuest::RendererResponsive(WebContents* source) {
[email protected]f8501b12012-12-07 04:55:43744 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Responsive"));
[email protected]fcf5a7a2013-07-26 06:18:01745 if (!delegate_)
746 return;
747 delegate_->RendererResponsive();
[email protected]f8501b12012-12-07 04:55:43748}
749
[email protected]19c1c373e2012-10-17 14:12:18750void BrowserPluginGuest::RunFileChooser(WebContents* web_contents,
751 const FileChooserParams& params) {
752 embedder_web_contents_->GetDelegate()->RunFileChooser(web_contents, params);
753}
754
[email protected]6a121f22012-10-30 03:19:48755bool BrowserPluginGuest::ShouldFocusPageAfterCrash() {
756 // Rather than managing focus in WebContentsImpl::RenderViewReady, we will
757 // manage the focus ourselves.
758 return false;
759}
760
[email protected]8eb04562013-03-06 03:41:14761WebContentsImpl* BrowserPluginGuest::GetWebContents() {
762 return static_cast<WebContentsImpl*>(web_contents());
[email protected]e17b7c62012-09-21 21:05:46763}
764
[email protected]4d1afd62012-12-21 03:09:40765base::SharedMemory* BrowserPluginGuest::GetDamageBufferFromEmbedder(
[email protected]1a0c0052012-11-05 21:06:26766 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
[email protected]1a0c0052012-11-05 21:06:26767#if defined(OS_WIN)
[email protected]4d1afd62012-12-21 03:09:40768 base::ProcessHandle handle =
769 embedder_web_contents_->GetRenderProcessHost()->GetHandle();
770 scoped_ptr<base::SharedMemory> shared_buf(
771 new base::SharedMemory(params.damage_buffer_handle, false, handle));
[email protected]1a0c0052012-11-05 21:06:26772#elif defined(OS_POSIX)
[email protected]4d1afd62012-12-21 03:09:40773 scoped_ptr<base::SharedMemory> shared_buf(
774 new base::SharedMemory(params.damage_buffer_handle, false));
775#endif
776 if (!shared_buf->Map(params.damage_buffer_size)) {
[email protected]c072073402013-06-04 21:53:59777 LOG(WARNING) << "Unable to map the embedder's damage buffer.";
[email protected]4d1afd62012-12-21 03:09:40778 return NULL;
779 }
780 return shared_buf.release();
[email protected]1a0c0052012-11-05 21:06:26781}
782
[email protected]7a846df2012-09-20 19:17:39783void BrowserPluginGuest::SetDamageBuffer(
[email protected]4d1afd62012-12-21 03:09:40784 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
785 damage_buffer_.reset(GetDamageBufferFromEmbedder(params));
[email protected]7a846df2012-09-20 19:17:39786 // Sanity check: Verify that we've correctly shared the damage buffer memory
787 // between the embedder and browser processes.
[email protected]c072073402013-06-04 21:53:59788 DCHECK(!damage_buffer_ ||
789 *static_cast<unsigned int*>(damage_buffer_->memory()) == 0xdeadbeef);
[email protected]4d1afd62012-12-21 03:09:40790 damage_buffer_sequence_id_ = params.damage_buffer_sequence_id;
791 damage_buffer_size_ = params.damage_buffer_size;
[email protected]32deec62013-05-15 23:55:04792 damage_view_size_ = params.view_rect.size();
[email protected]4d1afd62012-12-21 03:09:40793 damage_buffer_scale_factor_ = params.scale_factor;
[email protected]7a846df2012-09-20 19:17:39794}
795
[email protected]ca61ce142012-11-27 21:32:57796gfx::Point BrowserPluginGuest::GetScreenCoordinates(
797 const gfx::Point& relative_position) const {
798 gfx::Point screen_pos(relative_position);
799 screen_pos += guest_window_rect_.OffsetFromOrigin();
800 return screen_pos;
801}
802
[email protected]240b5c32012-11-09 19:17:18803bool BrowserPluginGuest::InAutoSizeBounds(const gfx::Size& size) const {
804 return size.width() <= max_auto_size_.width() &&
805 size.height() <= max_auto_size_.height();
806}
807
[email protected]c4538072013-03-18 02:17:55808void BrowserPluginGuest::RequestNewWindowPermission(
809 WebContentsImpl* new_contents,
810 WindowOpenDisposition disposition,
811 const gfx::Rect& initial_bounds,
812 bool user_gesture) {
813 BrowserPluginGuest* guest = new_contents->GetBrowserPluginGuest();
814 PendingWindowMap::iterator it = pending_new_windows_.find(guest);
815 if (it == pending_new_windows_.end())
816 return;
[email protected]96584eec2013-05-07 13:25:32817 const NewWindowInfo& new_window_info = it->second;
[email protected]291dcf32013-07-28 08:02:14818
[email protected]c4538072013-03-18 02:17:55819 base::DictionaryValue request_info;
820 request_info.Set(browser_plugin::kInitialHeight,
821 base::Value::CreateIntegerValue(initial_bounds.height()));
822 request_info.Set(browser_plugin::kInitialWidth,
823 base::Value::CreateIntegerValue(initial_bounds.width()));
824 request_info.Set(browser_plugin::kTargetURL,
[email protected]96584eec2013-05-07 13:25:32825 base::Value::CreateStringValue(new_window_info.url.spec()));
826 request_info.Set(browser_plugin::kName,
827 base::Value::CreateStringValue(new_window_info.name));
[email protected]c4538072013-03-18 02:17:55828 request_info.Set(browser_plugin::kWindowID,
829 base::Value::CreateIntegerValue(guest->instance_id()));
830 request_info.Set(browser_plugin::kWindowOpenDisposition,
831 base::Value::CreateStringValue(
832 WindowOpenDispositionToString(disposition)));
[email protected]291dcf32013-07-28 08:02:14833
[email protected]af1718c2013-08-12 19:59:19834 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW,
[email protected]291dcf32013-07-28 08:02:14835 new NewWindowRequest(guest->instance_id(), this),
836 request_info);
[email protected]c4538072013-03-18 02:17:55837}
838
[email protected]6d5c060a2013-06-18 11:27:06839bool BrowserPluginGuest::UnlockMouseIfNecessary(
840 const NativeWebKeyboardEvent& event) {
841 if (!mouse_locked_)
842 return false;
843
844 embedder_web_contents()->GotResponseToLockMouseRequest(false);
845 return true;
846}
847
[email protected]a7fac9a2012-12-18 23:26:07848void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
[email protected]c4538072013-03-18 02:17:55849 if (!attached()) {
[email protected]697f16b52013-05-10 06:01:18850 // Some pages such as data URLs, javascript URLs, and about:blank
851 // do not load external resources and so they load prior to attachment.
852 // As a result, we must save all these IPCs until attachment and then
853 // forward them so that the embedder gets a chance to see and process
854 // the load events.
855 pending_messages_.push(msg);
[email protected]c4538072013-03-18 02:17:55856 return;
857 }
858 msg->set_routing_id(embedder_web_contents_->GetRoutingID());
[email protected]a7fac9a2012-12-18 23:26:07859 embedder_web_contents_->Send(msg);
860}
861
[email protected]cf200a562013-05-03 16:24:29862void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
863 int screen_x, int screen_y, WebKit::WebDragOperation operation) {
864 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
865 screen_x, screen_y, operation);
866}
867
868void BrowserPluginGuest::DragSourceMovedTo(int client_x, int client_y,
869 int screen_x, int screen_y) {
870 web_contents()->GetRenderViewHost()->DragSourceMovedTo(client_x, client_y,
871 screen_x, screen_y);
872}
873
874void BrowserPluginGuest::EndSystemDrag() {
875 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
876 GetWebContents()->GetRenderViewHost());
877 guest_rvh->DragSourceSystemDragEnded();
878 // Issue a MouseUp event to get out of a selection state.
879 WebKit::WebMouseEvent mouse_event;
880 mouse_event.type = WebKit::WebInputEvent::MouseUp;
881 mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
882 guest_rvh->ForwardMouseEvent(mouse_event);
883}
884
[email protected]4c0e8272013-07-03 23:39:22885void BrowserPluginGuest::SetDelegate(BrowserPluginGuestDelegate* delegate) {
886 DCHECK(!delegate_);
887 delegate_.reset(delegate);
888}
889
[email protected]e4a55a52013-03-09 01:32:49890void BrowserPluginGuest::AskEmbedderForGeolocationPermission(
891 int bridge_id,
892 const GURL& requesting_frame,
[email protected]c47ddb22013-03-23 23:50:31893 const GeolocationCallback& callback) {
[email protected]cf4c9e052013-05-04 04:53:44894 if (permission_request_map_.size() >= kNumMaxOutstandingPermissionRequests) {
[email protected]e4a55a52013-03-09 01:32:49895 // Deny the geolocation request.
896 callback.Run(false);
897 return;
898 }
[email protected]e4a55a52013-03-09 01:32:49899
900 base::DictionaryValue request_info;
901 request_info.Set(browser_plugin::kURL,
902 base::Value::CreateStringValue(requesting_frame.spec()));
903
[email protected]291dcf32013-07-28 08:02:14904 int request_id =
[email protected]af1718c2013-08-12 19:59:19905 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_GEOLOCATION,
[email protected]291dcf32013-07-28 08:02:14906 new GeolocationRequest(
907 callback, bridge_id, &weak_ptr_factory_),
908 request_info);
909
910 DCHECK(bridge_id_to_request_id_map_.find(bridge_id) ==
911 bridge_id_to_request_id_map_.end());
912 bridge_id_to_request_id_map_[bridge_id] = request_id;
[email protected]e4a55a52013-03-09 01:32:49913}
914
[email protected]291dcf32013-07-28 08:02:14915int BrowserPluginGuest::RemoveBridgeID(int bridge_id) {
[email protected]cf4c9e052013-05-04 04:53:44916 std::map<int, int>::iterator bridge_itr =
[email protected]40974d02013-04-09 22:11:19917 bridge_id_to_request_id_map_.find(bridge_id);
[email protected]cf4c9e052013-05-04 04:53:44918 if (bridge_itr == bridge_id_to_request_id_map_.end())
[email protected]af1718c2013-08-12 19:59:19919 return browser_plugin::kInvalidPermissionRequestID;
[email protected]40974d02013-04-09 22:11:19920
[email protected]cf4c9e052013-05-04 04:53:44921 int request_id = bridge_itr->second;
922 bridge_id_to_request_id_map_.erase(bridge_itr);
[email protected]291dcf32013-07-28 08:02:14923 return request_id;
924}
925
926void BrowserPluginGuest::CancelGeolocationRequest(int bridge_id) {
927 int request_id = RemoveBridgeID(bridge_id);
[email protected]cf4c9e052013-05-04 04:53:44928 RequestMap::iterator request_itr = permission_request_map_.find(request_id);
929 if (request_itr == permission_request_map_.end())
930 return;
[email protected]cf4c9e052013-05-04 04:53:44931 permission_request_map_.erase(request_itr);
[email protected]e4a55a52013-03-09 01:32:49932}
933
[email protected]cf4c9e052013-05-04 04:53:44934void BrowserPluginGuest::SetGeolocationPermission(GeolocationCallback callback,
935 int bridge_id,
[email protected]e4a55a52013-03-09 01:32:49936 bool allowed) {
[email protected]cf4c9e052013-05-04 04:53:44937 callback.Run(allowed);
[email protected]291dcf32013-07-28 08:02:14938 RemoveBridgeID(bridge_id);
[email protected]e4a55a52013-03-09 01:32:49939}
940
[email protected]697f16b52013-05-10 06:01:18941void BrowserPluginGuest::SendQueuedMessages() {
942 if (!attached())
943 return;
944
945 while (!pending_messages_.empty()) {
946 IPC::Message* message = pending_messages_.front();
947 pending_messages_.pop();
948 SendMessageToEmbedder(message);
949 }
950}
951
[email protected]7a846df2012-09-20 19:17:39952void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
953 int64 frame_id,
954 bool is_main_frame,
955 const GURL& url,
956 PageTransition transition_type,
957 RenderViewHost* render_view_host) {
[email protected]81289ac32012-10-11 21:50:06958 RecordAction(UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
[email protected]7a846df2012-09-20 19:17:39959}
960
[email protected]eb92f632012-10-19 00:56:12961void BrowserPluginGuest::DidStopLoading(RenderViewHost* render_view_host) {
[email protected]ec0aeea2013-07-13 04:10:24962 bool disable_dragdrop = !CommandLine::ForCurrentProcess()->HasSwitch(
963 switches::kEnableBrowserPluginDragDrop);
[email protected]cf200a562013-05-03 16:24:29964 if (disable_dragdrop) {
965 // Initiating a drag from inside a guest is currently not supported without
966 // the kEnableBrowserPluginDragDrop flag on a linux platform. So inject some
967 // JS to disable it. http://crbug.com/161112
968 const char script[] = "window.addEventListener('dragstart', function() { "
969 " window.event.preventDefault(); "
970 "});";
971 render_view_host->ExecuteJavascriptInWebFrame(string16(),
972 ASCIIToUTF16(script));
973 }
[email protected]eb92f632012-10-19 00:56:12974}
975
[email protected]c88b2a562012-10-27 03:36:56976void BrowserPluginGuest::RenderViewReady() {
977 // TODO(fsamuel): Investigate whether it's possible to update state earlier
[email protected]dba9bd22012-12-06 23:04:03978 // here (see http://crbug.com/158151).
[email protected]c084330e02013-04-27 01:08:15979 Send(new InputMsg_SetFocus(routing_id(), focused_));
[email protected]3997b1b22012-12-20 01:02:54980 UpdateVisibility();
[email protected]8eb04562013-03-06 03:41:14981 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
[email protected]25bcc8f2013-01-09 02:49:25982 if (auto_size_enabled_)
983 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
984 else
985 rvh->DisableAutoResize(damage_view_size_);
986
[email protected]8eb04562013-03-06 03:41:14987 Send(new ViewMsg_SetName(routing_id(), name_));
[email protected]bca6c2c2013-03-24 03:55:07988
989 RenderWidgetHostImpl::From(rvh)->
990 set_hung_renderer_delay_ms(guest_hang_timeout_);
[email protected]c88b2a562012-10-27 03:36:56991}
992
[email protected]58d5cfe2013-07-10 02:40:52993void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
[email protected]78d71912013-07-17 06:39:47994 SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(instance_id()));
[email protected]2fae2c42012-10-03 21:20:04995 switch (status) {
996 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
997 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Killed"));
998 break;
999 case base::TERMINATION_STATUS_PROCESS_CRASHED:
1000 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Crashed"));
1001 break;
1002 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
1003 RecordAction(UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
1004 break;
1005 default:
1006 break;
1007 }
[email protected]291dcf32013-07-28 08:02:141008 // TODO(fsamuel): Consider whether we should be clearing
1009 // |permission_request_map_| here.
[email protected]78d71912013-07-17 06:39:471010 if (delegate_)
1011 delegate_->GuestProcessGone(status);
[email protected]7a846df2012-09-20 19:17:391012}
1013
[email protected]8eb04562013-03-06 03:41:141014// static
1015void BrowserPluginGuest::AcknowledgeBufferPresent(
1016 int route_id,
1017 int gpu_host_id,
[email protected]06666c02013-03-07 19:32:301018 const std::string& mailbox_name,
[email protected]8eb04562013-03-06 03:41:141019 uint32 sync_point) {
1020 AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
1021 ack_params.mailbox_name = mailbox_name;
1022 ack_params.sync_point = sync_point;
1023 RenderWidgetHostImpl::AcknowledgeBufferPresent(route_id,
1024 gpu_host_id,
1025 ack_params);
1026}
1027
1028// static
1029bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
1030 const IPC::Message& message) {
1031 switch (message.type()) {
1032 case BrowserPluginHostMsg_BuffersSwappedACK::ID:
[email protected]f5b4b0f2013-04-02 18:16:281033 case BrowserPluginHostMsg_CompositorFrameACK::ID:
[email protected]8eb04562013-03-06 03:41:141034 case BrowserPluginHostMsg_DragStatusUpdate::ID:
[email protected]6dd17a8a2013-05-01 05:50:101035 case BrowserPluginHostMsg_ExecuteEditCommand::ID:
[email protected]8eb04562013-03-06 03:41:141036 case BrowserPluginHostMsg_HandleInputEvent::ID:
1037 case BrowserPluginHostMsg_LockMouse_ACK::ID:
1038 case BrowserPluginHostMsg_NavigateGuest::ID:
1039 case BrowserPluginHostMsg_PluginDestroyed::ID:
[email protected]8eb04562013-03-06 03:41:141040 case BrowserPluginHostMsg_ResizeGuest::ID:
[email protected]8eb04562013-03-06 03:41:141041 case BrowserPluginHostMsg_SetAutoSize::ID:
[email protected]b77fac52013-06-01 01:03:461042 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
[email protected]8eb04562013-03-06 03:41:141043 case BrowserPluginHostMsg_SetFocus::ID:
1044 case BrowserPluginHostMsg_SetName::ID:
1045 case BrowserPluginHostMsg_SetVisibility::ID:
[email protected]8eb04562013-03-06 03:41:141046 case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
[email protected]32deec62013-05-15 23:55:041047 case BrowserPluginHostMsg_UpdateGeometry::ID:
[email protected]8eb04562013-03-06 03:41:141048 case BrowserPluginHostMsg_UpdateRect_ACK::ID:
1049 return true;
1050 default:
1051 break;
1052 }
1053 return false;
1054}
1055
[email protected]a7fac9a2012-12-18 23:26:071056bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
1057 bool handled = true;
1058 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
[email protected]a7fac9a2012-12-18 23:26:071059 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
1060 OnHasTouchEventHandlers)
[email protected]861f9782013-03-05 03:29:541061 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
[email protected]a7fac9a2012-12-18 23:26:071062 IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor)
1063 #if defined(OS_MACOSX)
1064 // MacOSX creates and populates platform-specific select drop-down menus
1065 // whereas other platforms merely create a popup window that the guest
1066 // renderer process paints inside.
1067 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowPopup, OnShowPopup)
1068 #endif
1069 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
1070 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
[email protected]861f9782013-03-05 03:29:541071 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
[email protected]25bcc8f2013-01-09 02:49:251072 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFrameName, OnUpdateFrameName)
[email protected]a7fac9a2012-12-18 23:26:071073 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect)
1074 IPC_MESSAGE_UNHANDLED(handled = false)
1075 IPC_END_MESSAGE_MAP()
1076 return handled;
1077}
1078
[email protected]c4538072013-03-18 02:17:551079void BrowserPluginGuest::Attach(
1080 WebContentsImpl* embedder_web_contents,
[email protected]4b4ed582013-05-01 00:16:231081 BrowserPluginHostMsg_Attach_Params params) {
1082 if (attached())
1083 return;
1084
1085 // Clear parameters that get inherited from the opener.
1086 params.storage_partition_id.clear();
1087 params.persist_storage = false;
1088 params.src.clear();
1089
[email protected]0c6d41752013-05-01 15:49:091090 // If a RenderView has already been created for this new window, then we need
1091 // to initialize the browser-side state now so that the RenderViewHostManager
1092 // does not create a new RenderView on navigation.
1093 if (has_render_view_) {
1094 static_cast<RenderViewHostImpl*>(
1095 GetWebContents()->GetRenderViewHost())->Init();
[email protected]c4538072013-03-18 02:17:551096 WebContentsViewGuest* new_view =
1097 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
1098 new_view->CreateViewForWidget(web_contents()->GetRenderViewHost());
[email protected]c4538072013-03-18 02:17:551099 }
[email protected]0c6d41752013-05-01 15:49:091100
1101 // We need to do a navigation here if the target URL has changed between
1102 // the time the WebContents was created and the time it was attached.
1103 // We also need to do an initial navigation if a RenderView was never
1104 // created for the new window in cases where there is no referrer.
1105 PendingWindowMap::iterator it = opener()->pending_new_windows_.find(this);
1106 if (it != opener()->pending_new_windows_.end()) {
[email protected]96584eec2013-05-07 13:25:321107 const NewWindowInfo& new_window_info = it->second;
1108 if (new_window_info.changed || !has_render_view_)
[email protected]0c6d41752013-05-01 15:49:091109 params.src = it->second.url.spec();
1110 } else {
1111 NOTREACHED();
1112 }
1113
[email protected]c4538072013-03-18 02:17:551114 // Once a new guest is attached to the DOM of the embedder page, then the
1115 // lifetime of the new guest is no longer managed by the opener guest.
1116 opener()->pending_new_windows_.erase(this);
1117
[email protected]50de3222013-03-20 15:36:131118 // The guest's frame name takes precedence over the BrowserPlugin's name.
1119 // The guest's frame name is assigned in
1120 // BrowserPluginGuest::WebContentsCreated.
1121 if (!name_.empty())
1122 params.name.clear();
1123
[email protected]c4538072013-03-18 02:17:551124 Initialize(embedder_web_contents, params);
1125
[email protected]620d5de52013-04-05 23:27:561126 // Inform the embedder of the guest's information.
1127 // We pull the partition information from the site's URL, which is of the form
1128 // guest://site/{persist}?{partition_name}.
1129 const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
1130 BrowserPluginMsg_Attach_ACK_Params ack_params;
1131 ack_params.storage_partition_id = site_url.query();
1132 ack_params.persist_storage =
1133 site_url.path().find("persist") != std::string::npos;
1134 ack_params.name = name_;
1135 SendMessageToEmbedder(
1136 new BrowserPluginMsg_Attach_ACK(instance_id_, ack_params));
[email protected]697f16b52013-05-10 06:01:181137
1138 SendQueuedMessages();
[email protected]abc7d5c2013-05-15 09:19:251139
1140 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Attached"));
[email protected]c4538072013-03-18 02:17:551141}
1142
[email protected]f5b4b0f2013-04-02 18:16:281143void BrowserPluginGuest::OnCompositorFrameACK(
1144 int instance_id,
1145 int route_id,
[email protected]53b4cc12013-07-18 23:02:301146 uint32 output_surface_id,
[email protected]f5b4b0f2013-04-02 18:16:281147 int renderer_host_id,
1148 const cc::CompositorFrameAck& ack) {
1149 RenderWidgetHostImpl::SendSwapCompositorFrameAck(route_id,
[email protected]53b4cc12013-07-18 23:02:301150 output_surface_id,
[email protected]f5b4b0f2013-04-02 18:16:281151 renderer_host_id,
1152 ack);
1153}
1154
[email protected]3997b1b22012-12-20 01:02:541155void BrowserPluginGuest::OnDragStatusUpdate(int instance_id,
1156 WebKit::WebDragStatus drag_status,
[email protected]dc293a72013-07-01 11:11:221157 const DropData& drop_data,
[email protected]3997b1b22012-12-20 01:02:541158 WebKit::WebDragOperationsMask mask,
1159 const gfx::Point& location) {
[email protected]8eb04562013-03-06 03:41:141160 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
[email protected]3997b1b22012-12-20 01:02:541161 switch (drag_status) {
1162 case WebKit::WebDragStatusEnter:
[email protected]cf200a562013-05-03 16:24:291163 embedder_web_contents_->GetBrowserPluginEmbedder()->DragEnteredGuest(
1164 this);
[email protected]3997b1b22012-12-20 01:02:541165 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
1166 break;
1167 case WebKit::WebDragStatusOver:
1168 host->DragTargetDragOver(location, location, mask, 0);
1169 break;
1170 case WebKit::WebDragStatusLeave:
[email protected]cf200a562013-05-03 16:24:291171 embedder_web_contents_->GetBrowserPluginEmbedder()->DragLeftGuest(this);
[email protected]3997b1b22012-12-20 01:02:541172 host->DragTargetDragLeave();
1173 break;
1174 case WebKit::WebDragStatusDrop:
1175 host->DragTargetDrop(location, location, 0);
[email protected]cf200a562013-05-03 16:24:291176 EndSystemDrag();
[email protected]3997b1b22012-12-20 01:02:541177 break;
1178 case WebKit::WebDragStatusUnknown:
1179 NOTREACHED();
1180 }
1181}
1182
[email protected]6dd17a8a2013-05-01 05:50:101183void BrowserPluginGuest::OnExecuteEditCommand(int instance_id,
1184 const std::string& name) {
1185 Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string()));
1186}
1187
[email protected]3997b1b22012-12-20 01:02:541188void BrowserPluginGuest::OnHandleInputEvent(
1189 int instance_id,
1190 const gfx::Rect& guest_window_rect,
1191 const WebKit::WebInputEvent* event) {
1192 guest_window_rect_ = guest_window_rect;
[email protected]c6ea9212013-04-09 18:51:561193 // If the embedder's RWHV is destroyed then that means that the embedder's
1194 // window has been closed but the embedder's WebContents has not yet been
1195 // destroyed. Computing screen coordinates of a BrowserPlugin only makes sense
1196 // if there is a visible embedder.
1197 if (embedder_web_contents_->GetRenderWidgetHostView()) {
1198 guest_screen_rect_ = guest_window_rect;
1199 guest_screen_rect_.Offset(
1200 embedder_web_contents_->GetRenderWidgetHostView()->
1201 GetViewBounds().OffsetFromOrigin());
1202 }
[email protected]3997b1b22012-12-20 01:02:541203 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
[email protected]8eb04562013-03-06 03:41:141204 GetWebContents()->GetRenderViewHost());
[email protected]3997b1b22012-12-20 01:02:541205
[email protected]bca6c2c2013-03-24 03:55:071206 if (WebKit::WebInputEvent::isMouseEventType(event->type)) {
1207 guest_rvh->ForwardMouseEvent(
1208 *static_cast<const WebKit::WebMouseEvent*>(event));
1209 return;
[email protected]3997b1b22012-12-20 01:02:541210 }
1211
[email protected]bca6c2c2013-03-24 03:55:071212 if (event->type == WebKit::WebInputEvent::MouseWheel) {
1213 guest_rvh->ForwardWheelEvent(
1214 *static_cast<const WebKit::WebMouseWheelEvent*>(event));
1215 return;
1216 }
1217
1218 if (WebKit::WebInputEvent::isKeyboardEventType(event->type)) {
[email protected]6dd17a8a2013-05-01 05:50:101219 RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>(
1220 embedder_web_contents_->GetRenderViewHost());
1221 if (!embedder_rvh->GetLastKeyboardEvent())
1222 return;
1223 NativeWebKeyboardEvent keyboard_event(
1224 *embedder_rvh->GetLastKeyboardEvent());
[email protected]bca6c2c2013-03-24 03:55:071225 guest_rvh->ForwardKeyboardEvent(keyboard_event);
1226 return;
1227 }
1228
1229 if (WebKit::WebInputEvent::isTouchEventType(event->type)) {
[email protected]de860e02013-06-18 23:48:311230 guest_rvh->ForwardTouchEventWithLatencyInfo(
1231 *static_cast<const WebKit::WebTouchEvent*>(event),
1232 ui::LatencyInfo());
[email protected]bca6c2c2013-03-24 03:55:071233 return;
1234 }
1235
1236 if (WebKit::WebInputEvent::isGestureEventType(event->type)) {
1237 guest_rvh->ForwardGestureEvent(
1238 *static_cast<const WebKit::WebGestureEvent*>(event));
1239 return;
1240 }
[email protected]3997b1b22012-12-20 01:02:541241}
1242
[email protected]861f9782013-03-05 03:29:541243void BrowserPluginGuest::OnLockMouse(bool user_gesture,
1244 bool last_unlocked_by_target,
1245 bool privileged) {
[email protected]b60b88942013-07-20 05:58:421246 if (pending_lock_request_ ||
1247 (permission_request_map_.size() >=
1248 kNumMaxOutstandingPermissionRequests)) {
[email protected]a25acea72013-03-10 23:41:281249 // Immediately reject the lock because only one pointerLock may be active
1250 // at a time.
1251 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
1252 return;
1253 }
[email protected]a25acea72013-03-10 23:41:281254 pending_lock_request_ = true;
[email protected]a25acea72013-03-10 23:41:281255 base::DictionaryValue request_info;
1256 request_info.Set(browser_plugin::kUserGesture,
1257 base::Value::CreateBooleanValue(user_gesture));
1258 request_info.Set(browser_plugin::kLastUnlockedBySelf,
1259 base::Value::CreateBooleanValue(last_unlocked_by_target));
1260 request_info.Set(browser_plugin::kURL,
1261 base::Value::CreateStringValue(
1262 web_contents()->GetURL().spec()));
1263
[email protected]af1718c2013-08-12 19:59:191264 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_POINTER_LOCK,
[email protected]291dcf32013-07-28 08:02:141265 new PointerLockRequest(this),
1266 request_info);
[email protected]861f9782013-03-05 03:29:541267}
1268
1269void BrowserPluginGuest::OnLockMouseAck(int instance_id, bool succeeded) {
1270 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
[email protected]a25acea72013-03-10 23:41:281271 pending_lock_request_ = false;
[email protected]861f9782013-03-05 03:29:541272 if (succeeded)
1273 mouse_locked_ = true;
1274}
1275
[email protected]5e7967972013-01-15 22:45:331276void BrowserPluginGuest::OnNavigateGuest(
1277 int instance_id,
1278 const std::string& src) {
1279 GURL url(src);
[email protected]5e7967972013-01-15 22:45:331280 // We do not load empty urls in web_contents.
1281 // If a guest sets empty src attribute after it has navigated to some
1282 // non-empty page, the action is considered no-op. This empty src navigation
[email protected]e1eef4f2013-01-15 23:18:211283 // should never be sent to BrowserPluginGuest (browser process).
[email protected]5e7967972013-01-15 22:45:331284 DCHECK(!src.empty());
1285 if (!src.empty()) {
[email protected]e1eef4f2013-01-15 23:18:211286 // As guests do not swap processes on navigation, only navigations to
[email protected]5e7967972013-01-15 22:45:331287 // normal web URLs are supported. No protocol handlers are installed for
1288 // other schemes (e.g., WebUI or extensions), and no permissions or bindings
1289 // can be granted to the guest process.
[email protected]8eb04562013-03-06 03:41:141290 GetWebContents()->GetController().LoadURL(url, Referrer(),
[email protected]e1eef4f2013-01-15 23:18:211291 PAGE_TRANSITION_AUTO_TOPLEVEL,
1292 std::string());
[email protected]5e7967972013-01-15 22:45:331293 }
1294}
1295
[email protected]b371a5652013-02-20 11:25:511296void BrowserPluginGuest::OnPluginDestroyed(int instance_id) {
[email protected]b371a5652013-02-20 11:25:511297 Destroy();
1298}
1299
[email protected]3997b1b22012-12-20 01:02:541300void BrowserPluginGuest::OnResizeGuest(
1301 int instance_id,
1302 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
[email protected]197ce112013-07-23 01:13:291303 if (!params.size_changed)
1304 return;
[email protected]3997b1b22012-12-20 01:02:541305 // BrowserPlugin manages resize flow control itself and does not depend
1306 // on RenderWidgetHost's mechanisms for flow control, so we reset those flags
1307 // here. If we are setting the size for the first time before navigating then
1308 // BrowserPluginGuest does not yet have a RenderViewHost.
[email protected]8eb04562013-03-06 03:41:141309 if (GetWebContents()->GetRenderViewHost()) {
[email protected]3997b1b22012-12-20 01:02:541310 RenderWidgetHostImpl* render_widget_host =
[email protected]8eb04562013-03-06 03:41:141311 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
[email protected]3997b1b22012-12-20 01:02:541312 render_widget_host->ResetSizeAndRepaintPendingFlags();
[email protected]caaf2482013-05-01 20:33:321313
1314 if (guest_device_scale_factor_ != params.scale_factor) {
1315 guest_device_scale_factor_ = params.scale_factor;
1316 render_widget_host->NotifyScreenInfoChanged();
1317 }
[email protected]3997b1b22012-12-20 01:02:541318 }
[email protected]caaf2482013-05-01 20:33:321319 // Invalid damage buffer means we are in HW compositing mode,
1320 // so just resize the WebContents and repaint if needed.
[email protected]4d1afd62012-12-21 03:09:401321 if (!base::SharedMemory::IsHandleValid(params.damage_buffer_handle)) {
[email protected]32deec62013-05-15 23:55:041322 if (!params.view_rect.size().IsEmpty())
1323 GetWebContents()->GetView()->SizeContents(params.view_rect.size());
[email protected]caaf2482013-05-01 20:33:321324 if (params.repaint)
[email protected]32deec62013-05-15 23:55:041325 Send(new ViewMsg_Repaint(routing_id(), params.view_rect.size()));
[email protected]3997b1b22012-12-20 01:02:541326 return;
1327 }
[email protected]4d1afd62012-12-21 03:09:401328 SetDamageBuffer(params);
[email protected]32deec62013-05-15 23:55:041329 GetWebContents()->GetView()->SizeContents(params.view_rect.size());
[email protected]8eb04562013-03-06 03:41:141330 if (params.repaint)
[email protected]32deec62013-05-15 23:55:041331 Send(new ViewMsg_Repaint(routing_id(), params.view_rect.size()));
[email protected]3997b1b22012-12-20 01:02:541332}
1333
[email protected]423838472013-01-09 00:16:461334void BrowserPluginGuest::OnSetFocus(int instance_id, bool focused) {
1335 if (focused_ == focused)
1336 return;
1337 focused_ = focused;
[email protected]c084330e02013-04-27 01:08:151338 Send(new InputMsg_SetFocus(routing_id(), focused));
[email protected]79733a02013-04-30 15:05:351339 if (!focused && mouse_locked_)
1340 OnUnlockMouse();
[email protected]423838472013-01-09 00:16:461341}
1342
[email protected]25bcc8f2013-01-09 02:49:251343void BrowserPluginGuest::OnSetName(int instance_id, const std::string& name) {
1344 if (name == name_)
1345 return;
1346 name_ = name;
[email protected]8eb04562013-03-06 03:41:141347 Send(new ViewMsg_SetName(routing_id(), name));
[email protected]25bcc8f2013-01-09 02:49:251348}
1349
[email protected]3997b1b22012-12-20 01:02:541350void BrowserPluginGuest::OnSetSize(
1351 int instance_id,
1352 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
1353 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
1354 bool old_auto_size_enabled = auto_size_enabled_;
1355 gfx::Size old_max_size = max_auto_size_;
1356 gfx::Size old_min_size = min_auto_size_;
1357 auto_size_enabled_ = auto_size_params.enable;
1358 max_auto_size_ = auto_size_params.max_size;
1359 min_auto_size_ = auto_size_params.min_size;
1360 if (auto_size_enabled_ && (!old_auto_size_enabled ||
1361 (old_max_size != max_auto_size_) ||
1362 (old_min_size != min_auto_size_))) {
[email protected]8eb04562013-03-06 03:41:141363 GetWebContents()->GetRenderViewHost()->EnableAutoResize(
[email protected]3997b1b22012-12-20 01:02:541364 min_auto_size_, max_auto_size_);
1365 // TODO(fsamuel): If we're changing autosize parameters, then we force
1366 // the guest to completely repaint itself, because BrowserPlugin has
1367 // allocated a new damage buffer and expects a full frame of pixels.
1368 // Ideally, we shouldn't need to do this because we shouldn't need to
1369 // allocate a new damage buffer unless |max_auto_size_| has changed.
1370 // However, even in that case, layout may not change and so we may
1371 // not get a full frame worth of pixels.
[email protected]8eb04562013-03-06 03:41:141372 Send(new ViewMsg_Repaint(routing_id(), max_auto_size_));
[email protected]3997b1b22012-12-20 01:02:541373 } else if (!auto_size_enabled_ && old_auto_size_enabled) {
[email protected]8eb04562013-03-06 03:41:141374 GetWebContents()->GetRenderViewHost()->DisableAutoResize(
[email protected]32deec62013-05-15 23:55:041375 resize_guest_params.view_rect.size());
[email protected]3997b1b22012-12-20 01:02:541376 }
1377 OnResizeGuest(instance_id_, resize_guest_params);
1378}
1379
[email protected]b77fac52013-06-01 01:03:461380void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
1381 int instance_id,
1382 const std::vector<EditCommand>& edit_commands) {
1383 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
1384 edit_commands));
1385}
1386
[email protected]3997b1b22012-12-20 01:02:541387void BrowserPluginGuest::OnSetVisibility(int instance_id, bool visible) {
[email protected]93564f72013-02-15 13:26:191388 guest_visible_ = visible;
1389 if (embedder_visible_ && guest_visible_)
[email protected]8eb04562013-03-06 03:41:141390 GetWebContents()->WasShown();
[email protected]3997b1b22012-12-20 01:02:541391 else
[email protected]8eb04562013-03-06 03:41:141392 GetWebContents()->WasHidden();
[email protected]3997b1b22012-12-20 01:02:541393}
1394
[email protected]cc8ed212013-02-07 22:31:031395void BrowserPluginGuest::OnSwapBuffersACK(int instance_id,
1396 int route_id,
1397 int gpu_host_id,
[email protected]06666c02013-03-07 19:32:301398 const std::string& mailbox_name,
[email protected]cc8ed212013-02-07 22:31:031399 uint32 sync_point) {
1400 AcknowledgeBufferPresent(route_id, gpu_host_id, mailbox_name, sync_point);
1401
1402// This is only relevant on MACOSX and WIN when threaded compositing
1403// is not enabled. In threaded mode, above ACK is sufficient.
1404#if defined(OS_MACOSX) || defined(OS_WIN)
1405 RenderWidgetHostImpl* render_widget_host =
[email protected]8eb04562013-03-06 03:41:141406 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
[email protected]cc8ed212013-02-07 22:31:031407 render_widget_host->AcknowledgeSwapBuffersToRenderer();
1408#endif // defined(OS_MACOSX) || defined(OS_WIN)
1409}
1410
[email protected]861f9782013-03-05 03:29:541411void BrowserPluginGuest::OnUnlockMouse() {
[email protected]b60b88942013-07-20 05:58:421412 SendMessageToEmbedder(
1413 new BrowserPluginMsg_SetMouseLock(instance_id(), false));
[email protected]861f9782013-03-05 03:29:541414}
1415
1416void BrowserPluginGuest::OnUnlockMouseAck(int instance_id) {
1417 // mouse_locked_ could be false here if the lock attempt was cancelled due
1418 // to window focus, or for various other reasons before the guest was informed
1419 // of the lock's success.
1420 if (mouse_locked_)
1421 Send(new ViewMsg_MouseLockLost(routing_id()));
1422 mouse_locked_ = false;
1423}
1424
[email protected]3997b1b22012-12-20 01:02:541425void BrowserPluginGuest::OnUpdateRectACK(
1426 int instance_id,
[email protected]7c99b002013-08-01 23:58:211427 bool needs_ack,
[email protected]3997b1b22012-12-20 01:02:541428 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
1429 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
[email protected]7c99b002013-08-01 23:58:211430 // Only the software path expects an ACK.
1431 if (needs_ack)
1432 Send(new ViewMsg_UpdateRect_ACK(routing_id()));
[email protected]3997b1b22012-12-20 01:02:541433 OnSetSize(instance_id_, auto_size_params, resize_guest_params);
1434}
1435
[email protected]32deec62013-05-15 23:55:041436void BrowserPluginGuest::OnUpdateGeometry(int instance_id,
1437 const gfx::Rect& view_rect) {
1438 // The plugin has moved within the embedder without resizing or the
1439 // embedder/container's view rect changing.
1440 guest_window_rect_ = view_rect;
1441 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1442 GetWebContents()->GetRenderViewHost());
1443 if (rvh)
1444 rvh->SendScreenRects();
1445}
1446
[email protected]a7fac9a2012-12-18 23:26:071447void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
1448 SendMessageToEmbedder(
[email protected]d752fe62013-03-01 03:46:011449 new BrowserPluginMsg_ShouldAcceptTouchEvents(instance_id(), accept));
[email protected]a7fac9a2012-12-18 23:26:071450}
1451
1452void BrowserPluginGuest::OnSetCursor(const WebCursor& cursor) {
[email protected]d752fe62013-03-01 03:46:011453 SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(instance_id(), cursor));
[email protected]a7fac9a2012-12-18 23:26:071454}
1455
1456#if defined(OS_MACOSX)
1457void BrowserPluginGuest::OnShowPopup(
1458 const ViewHostMsg_ShowPopup_Params& params) {
1459 gfx::Rect translated_bounds(params.bounds);
1460 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
1461 BrowserPluginPopupMenuHelper popup_menu_helper(
1462 embedder_web_contents_->GetRenderViewHost(),
[email protected]8eb04562013-03-06 03:41:141463 GetWebContents()->GetRenderViewHost());
[email protected]a7fac9a2012-12-18 23:26:071464 popup_menu_helper.ShowPopupMenu(translated_bounds,
1465 params.item_height,
1466 params.item_font_size,
1467 params.selected_item,
1468 params.popup_items,
1469 params.right_aligned,
1470 params.allow_multiple_selection);
1471}
1472#endif
1473
1474void BrowserPluginGuest::OnShowWidget(int route_id,
1475 const gfx::Rect& initial_pos) {
[email protected]32deec62013-05-15 23:55:041476 GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
[email protected]a7fac9a2012-12-18 23:26:071477}
1478
1479void BrowserPluginGuest::OnTakeFocus(bool reverse) {
1480 SendMessageToEmbedder(
[email protected]d752fe62013-03-01 03:46:011481 new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse));
[email protected]a7fac9a2012-12-18 23:26:071482}
1483
[email protected]25bcc8f2013-01-09 02:49:251484void BrowserPluginGuest::OnUpdateFrameName(int frame_id,
1485 bool is_top_level,
1486 const std::string& name) {
1487 if (!is_top_level)
1488 return;
1489
1490 name_ = name;
[email protected]d752fe62013-03-01 03:46:011491 SendMessageToEmbedder(new BrowserPluginMsg_UpdatedName(instance_id_, name));
[email protected]25bcc8f2013-01-09 02:49:251492}
1493
[email protected]c006fb52013-03-01 09:36:451494void BrowserPluginGuest::RequestMediaAccessPermission(
1495 WebContents* web_contents,
[email protected]ce0e2602013-03-15 20:53:271496 const MediaStreamRequest& request,
1497 const MediaResponseCallback& callback) {
[email protected]cf4c9e052013-05-04 04:53:441498 if (permission_request_map_.size() >= kNumMaxOutstandingPermissionRequests) {
[email protected]c006fb52013-03-01 09:36:451499 // Deny the media request.
[email protected]b5f76742013-04-29 15:05:591500 callback.Run(MediaStreamDevices(), scoped_ptr<MediaStreamUI>());
[email protected]c006fb52013-03-01 09:36:451501 return;
1502 }
[email protected]c006fb52013-03-01 09:36:451503
1504 base::DictionaryValue request_info;
1505 request_info.Set(
[email protected]8eb04562013-03-06 03:41:141506 browser_plugin::kURL,
1507 base::Value::CreateStringValue(request.security_origin.spec()));
[email protected]291dcf32013-07-28 08:02:141508
[email protected]af1718c2013-08-12 19:59:191509 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_MEDIA,
[email protected]291dcf32013-07-28 08:02:141510 new MediaRequest(request, callback, this),
1511 request_info);
[email protected]c006fb52013-03-01 09:36:451512}
1513
[email protected]1c514fc2013-07-24 07:30:531514void BrowserPluginGuest::RunJavaScriptDialog(
1515 WebContents* web_contents,
1516 const GURL& origin_url,
1517 const std::string& accept_lang,
1518 JavaScriptMessageType javascript_message_type,
1519 const string16& message_text,
1520 const string16& default_prompt_text,
1521 const DialogClosedCallback& callback,
1522 bool* did_suppress_message) {
1523 if (permission_request_map_.size() >= kNumMaxOutstandingPermissionRequests) {
1524 // Cancel the dialog.
1525 callback.Run(false, string16());
1526 return;
1527 }
[email protected]1c514fc2013-07-24 07:30:531528 base::DictionaryValue request_info;
1529 request_info.Set(
1530 browser_plugin::kDefaultPromptText,
1531 base::Value::CreateStringValue(UTF16ToUTF8(default_prompt_text)));
1532 request_info.Set(
1533 browser_plugin::kMessageText,
1534 base::Value::CreateStringValue(UTF16ToUTF8(message_text)));
1535 request_info.Set(
1536 browser_plugin::kMessageType,
1537 base::Value::CreateStringValue(
1538 JavaScriptMessageTypeToString(javascript_message_type)));
1539 request_info.Set(
1540 browser_plugin::kURL,
1541 base::Value::CreateStringValue(origin_url.spec()));
[email protected]291dcf32013-07-28 08:02:141542
[email protected]af1718c2013-08-12 19:59:191543 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_JAVASCRIPT_DIALOG,
[email protected]291dcf32013-07-28 08:02:141544 new JavaScriptDialogRequest(callback),
1545 request_info);
[email protected]1c514fc2013-07-24 07:30:531546}
1547
1548void BrowserPluginGuest::RunBeforeUnloadDialog(
1549 WebContents* web_contents,
1550 const string16& message_text,
1551 bool is_reload,
1552 const DialogClosedCallback& callback) {
1553 // This is called if the guest has a beforeunload event handler.
1554 // This callback allows navigation to proceed.
1555 callback.Run(true, string16());
1556}
1557
1558bool BrowserPluginGuest::HandleJavaScriptDialog(
1559 WebContents* web_contents,
1560 bool accept,
1561 const string16* prompt_override) {
1562 return false;
1563}
1564
[email protected]4567f152013-07-31 13:20:111565void BrowserPluginGuest::CancelActiveAndPendingDialogs(
1566 WebContents* web_contents) {
1567}
1568
1569void BrowserPluginGuest::WebContentsDestroyed(WebContents* web_contents) {
[email protected]1c514fc2013-07-24 07:30:531570}
1571
[email protected]a7fac9a2012-12-18 23:26:071572void BrowserPluginGuest::OnUpdateRect(
1573 const ViewHostMsg_UpdateRect_Params& params) {
[email protected]a7fac9a2012-12-18 23:26:071574 BrowserPluginMsg_UpdateRect_Params relay_params;
1575 relay_params.view_size = params.view_size;
1576 relay_params.scale_factor = params.scale_factor;
1577 relay_params.is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack(
1578 params.flags);
[email protected]166f61a2013-01-09 23:54:491579 relay_params.needs_ack = params.needs_ack;
[email protected]a7fac9a2012-12-18 23:26:071580
1581 // HW accelerated case, acknowledge resize only
[email protected]61c555422013-01-31 19:31:061582 if (!params.needs_ack || !damage_buffer_) {
[email protected]4d1afd62012-12-21 03:09:401583 relay_params.damage_buffer_sequence_id = 0;
[email protected]d752fe62013-03-01 03:46:011584 SendMessageToEmbedder(
1585 new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
1586 return;
[email protected]a7fac9a2012-12-18 23:26:071587 }
1588
[email protected]a7fac9a2012-12-18 23:26:071589 // Only copy damage if the guest is in autosize mode and the guest's view size
1590 // is less than the maximum size or the guest's view size is equal to the
1591 // damage buffer's size and the guest's scale factor is equal to the damage
1592 // buffer's scale factor.
1593 // The scaling change can happen due to asynchronous updates of the DPI on a
1594 // resolution change.
1595 if (((auto_size_enabled_ && InAutoSizeBounds(params.view_size)) ||
[email protected]32deec62013-05-15 23:55:041596 (params.view_size == damage_view_size())) &&
[email protected]a7fac9a2012-12-18 23:26:071597 params.scale_factor == damage_buffer_scale_factor()) {
[email protected]8eb04562013-03-06 03:41:141598 TransportDIB* dib = GetWebContents()->GetRenderProcessHost()->
[email protected]a7fac9a2012-12-18 23:26:071599 GetTransportDIB(params.bitmap);
1600 if (dib) {
[email protected]4d1afd62012-12-21 03:09:401601 size_t guest_damage_buffer_size =
[email protected]a7fac9a2012-12-18 23:26:071602#if defined(OS_WIN)
[email protected]4d1afd62012-12-21 03:09:401603 params.bitmap_rect.width() *
1604 params.bitmap_rect.height() * 4;
[email protected]a7fac9a2012-12-18 23:26:071605#else
[email protected]4d1afd62012-12-21 03:09:401606 dib->size();
[email protected]a7fac9a2012-12-18 23:26:071607#endif
[email protected]4d1afd62012-12-21 03:09:401608 size_t embedder_damage_buffer_size = damage_buffer_size_;
[email protected]a7fac9a2012-12-18 23:26:071609 void* guest_memory = dib->memory();
1610 void* embedder_memory = damage_buffer_->memory();
1611 size_t size = std::min(guest_damage_buffer_size,
1612 embedder_damage_buffer_size);
1613 memcpy(embedder_memory, guest_memory, size);
1614 }
1615 }
[email protected]4d1afd62012-12-21 03:09:401616 relay_params.damage_buffer_sequence_id = damage_buffer_sequence_id_;
[email protected]a7fac9a2012-12-18 23:26:071617 relay_params.bitmap_rect = params.bitmap_rect;
1618 relay_params.scroll_delta = params.scroll_delta;
1619 relay_params.scroll_rect = params.scroll_rect;
1620 relay_params.copy_rects = params.copy_rects;
1621
[email protected]d752fe62013-03-01 03:46:011622 SendMessageToEmbedder(
1623 new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
[email protected]7a846df2012-09-20 19:17:391624}
1625
[email protected]f85f5032013-04-03 09:01:541626void BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId(
1627 const std::string& request_method,
[email protected]291dcf32013-07-28 08:02:141628 const base::Callback<void(bool)>& callback,
[email protected]f85f5032013-04-03 09:01:541629 const std::string& url) {
1630 if (url.empty()) {
[email protected]291dcf32013-07-28 08:02:141631 callback.Run(false);
[email protected]f85f5032013-04-03 09:01:541632 return;
1633 }
1634
1635 base::DictionaryValue request_info;
1636 request_info.Set(browser_plugin::kRequestMethod,
1637 base::Value::CreateStringValue(request_method));
1638 request_info.Set(browser_plugin::kURL, base::Value::CreateStringValue(url));
1639
[email protected]af1718c2013-08-12 19:59:191640 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_DOWNLOAD,
[email protected]291dcf32013-07-28 08:02:141641 new DownloadRequest(callback),
1642 request_info);
[email protected]f85f5032013-04-03 09:01:541643}
1644
[email protected]7a846df2012-09-20 19:17:391645} // namespace content