diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 0a9e6c3ad6fe..67af2022dbc8 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -457,6 +457,15 @@ void WebContents::RequestMediaAccessPermission( permission_helper->RequestMediaAccessPermission(request, callback); } +void WebContents::RequestToLockMouse( + content::WebContents* web_contents, + bool user_gesture, + bool last_unlocked_by_target) { + auto permission_helper = + WebContentsPermissionHelper::FromWebContents(web_contents); + permission_helper->RequestPointerLockPermission(user_gesture); +} + void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) { // Do nothing, we override this method just to avoid compilation error since // there are two virtual functions named BeforeUnloadFired. diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 6587759efb9f..cd6d0e7b6083 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -199,6 +199,10 @@ class WebContents : public mate::TrackableObject, content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) override; + void RequestToLockMouse( + content::WebContents* web_contents, + bool user_gesture, + bool last_unlocked_by_target) override; // content::WebContentsObserver: void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; diff --git a/atom/browser/atom_permission_manager.cc b/atom/browser/atom_permission_manager.cc index c245a278c3b2..e7fdaaffea71 100644 --- a/atom/browser/atom_permission_manager.cc +++ b/atom/browser/atom_permission_manager.cc @@ -8,10 +8,28 @@ #include "content/public/browser/permission_type.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" namespace atom { +namespace { + +// Must be kept in sync with atom_browser_client.cc +int kDefaultRoutingID = 2; + +bool WebContentsDestroyed(int process_id) { + auto rvh = content::RenderViewHost::FromID(process_id, kDefaultRoutingID); + if (rvh) { + auto contents = content::WebContents::FromRenderViewHost(rvh); + return contents->IsBeingDestroyed(); + } + + return true; +} + +} // namespace + AtomPermissionManager::AtomPermissionManager() : request_id_(0) { } @@ -22,8 +40,10 @@ AtomPermissionManager::~AtomPermissionManager() { void AtomPermissionManager::SetPermissionRequestHandler( const RequestHandler& handler) { if (handler.is_null() && !pending_requests_.empty()) { - for (const auto& request : pending_requests_) - request.second.Run(content::PERMISSION_STATUS_DENIED); + for (const auto& request : pending_requests_) { + if (!WebContentsDestroyed(request.second.render_process_id)) + request.second.callback.Run(content::PERMISSION_STATUS_DENIED); + } pending_requests_.clear(); } request_handler_ = handler; @@ -35,9 +55,11 @@ int AtomPermissionManager::RequestPermission( const GURL& requesting_origin, bool user_gesture, const ResponseCallback& response_callback) { + int process_id = render_frame_host->GetProcess()->GetID(); + if (permission == content::PermissionType::MIDI_SYSEX) { content::ChildProcessSecurityPolicy::GetInstance()-> - GrantSendMidiSysExMessage(render_frame_host->GetProcess()->GetID()); + GrantSendMidiSysExMessage(process_id); } if (!request_handler_.is_null()) { @@ -49,7 +71,7 @@ int AtomPermissionManager::RequestPermission( request_id_, requesting_origin, response_callback); - pending_requests_[request_id_] = callback; + pending_requests_[request_id_] = { process_id, callback }; request_handler_.Run(web_contents, permission, callback); return request_id_; } @@ -63,14 +85,19 @@ void AtomPermissionManager::OnPermissionResponse( const GURL& origin, const ResponseCallback& callback, content::PermissionStatus status) { - callback.Run(status); - pending_requests_.erase(request_id); + auto request = pending_requests_.find(request_id); + if (request != pending_requests_.end()) { + if (!WebContentsDestroyed(request->second.render_process_id)) + callback.Run(status); + pending_requests_.erase(request); + } } void AtomPermissionManager::CancelPermissionRequest(int request_id) { auto request = pending_requests_.find(request_id); if (request != pending_requests_.end()) { - request->second.Run(content::PERMISSION_STATUS_DENIED); + if (!WebContentsDestroyed(request->second.render_process_id)) + request->second.callback.Run(content::PERMISSION_STATUS_DENIED); pending_requests_.erase(request); } } diff --git a/atom/browser/atom_permission_manager.h b/atom/browser/atom_permission_manager.h index 8d8729acc66f..4bebbbc84f29 100644 --- a/atom/browser/atom_permission_manager.h +++ b/atom/browser/atom_permission_manager.h @@ -65,9 +65,14 @@ class AtomPermissionManager : public content::PermissionManager { void UnsubscribePermissionStatusChange(int subscription_id) override; private: + struct RequestInfo { + int render_process_id; + ResponseCallback callback; + }; + RequestHandler request_handler_; - std::map pending_requests_; + std::map pending_requests_; int request_id_; diff --git a/atom/browser/web_contents_permission_helper.cc b/atom/browser/web_contents_permission_helper.cc index da2ad57ad979..6b017aa1342e 100644 --- a/atom/browser/web_contents_permission_helper.cc +++ b/atom/browser/web_contents_permission_helper.cc @@ -66,6 +66,11 @@ void MediaAccessAllowed( callback.Run(devices, result, scoped_ptr()); } +void OnPointerLockResponse(content::WebContents* web_contents, bool allowed) { + if (web_contents) + web_contents->GotResponseToLockMouseRequest(allowed); +} + void OnPermissionResponse(const base::Callback& callback, content::PermissionStatus status) { if (status == content::PERMISSION_STATUS_GRANTED) @@ -86,12 +91,12 @@ WebContentsPermissionHelper::~WebContentsPermissionHelper() { void WebContentsPermissionHelper::RequestPermission( content::PermissionType permission, - const base::Callback& callback) { + const base::Callback& callback, + bool user_gesture) { auto rfh = web_contents_->GetMainFrame(); auto permission_manager = static_cast( web_contents_->GetBrowserContext()->GetPermissionManager()); auto origin = web_contents_->GetLastCommittedURL(); - bool user_gesture = false; permission_manager->RequestPermission( permission, rfh, origin, user_gesture, base::Bind(&OnPermissionResponse, callback)); @@ -111,4 +116,11 @@ void WebContentsPermissionHelper::RequestWebNotificationPermission( RequestPermission(content::PermissionType::NOTIFICATIONS, callback); } +void WebContentsPermissionHelper::RequestPointerLockPermission( + bool user_gesture) { + RequestPermission((content::PermissionType)(PermissionType::POINTER_LOCK), + base::Bind(&OnPointerLockResponse, web_contents_), + user_gesture); +} + } // namespace atom diff --git a/atom/browser/web_contents_permission_helper.h b/atom/browser/web_contents_permission_helper.h index 6bd2bb2559e5..68682340ceb6 100644 --- a/atom/browser/web_contents_permission_helper.h +++ b/atom/browser/web_contents_permission_helper.h @@ -17,11 +17,17 @@ class WebContentsPermissionHelper public: ~WebContentsPermissionHelper() override; + enum class PermissionType { + POINTER_LOCK = static_cast(content::PermissionType::NUM) + 1, + FULLSCREEN + }; + void RequestMediaAccessPermission( const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback); void RequestWebNotificationPermission( const base::Callback& callback); + void RequestPointerLockPermission(bool user_gesture); private: explicit WebContentsPermissionHelper(content::WebContents* web_contents); @@ -29,7 +35,8 @@ class WebContentsPermissionHelper void RequestPermission( content::PermissionType permission, - const base::Callback& callback); + const base::Callback& callback, + bool user_gesture = false); content::WebContents* web_contents_; diff --git a/atom/common/native_mate_converters/content_converter.cc b/atom/common/native_mate_converters/content_converter.cc index 15066085af09..699f101d0e4b 100644 --- a/atom/common/native_mate_converters/content_converter.cc +++ b/atom/common/native_mate_converters/content_converter.cc @@ -8,6 +8,7 @@ #include #include "atom/browser/api/atom_api_web_contents.h" +#include "atom/browser/web_contents_permission_helper.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "content/public/browser/web_contents.h" @@ -104,16 +105,14 @@ bool Converter::FromV8( v8::Isolate* isolate, v8::Local val, content::PermissionStatus* out) { - std::string status; - if (!ConvertFromV8(isolate, val, &status)) + bool result; + if (!ConvertFromV8(isolate, val, &result)) return false; - if (status == "granted") + if (result) *out = content::PERMISSION_STATUS_GRANTED; - else if (status == "denied" || status.empty()) - *out = content::PERMISSION_STATUS_DENIED; else - return false; + *out = content::PERMISSION_STATUS_DENIED; return true; } @@ -121,6 +120,7 @@ bool Converter::FromV8( // static v8::Local Converter::ToV8( v8::Isolate* isolate, const content::PermissionType& val) { + using PermissionType = atom::WebContentsPermissionHelper::PermissionType; switch (val) { case content::PermissionType::MIDI_SYSEX: return StringToV8(isolate, "midiSysex"); @@ -137,10 +137,16 @@ v8::Local Converter::ToV8( return StringToV8(isolate, "mediaKeySystem"); case content::PermissionType::MIDI: return StringToV8(isolate, "midi"); - case content::PermissionType::DURABLE_STORAGE: default: - return StringToV8(isolate, "unknown"); + break; } + + if (val == (content::PermissionType)(PermissionType::POINTER_LOCK)) + return StringToV8(isolate, "pointerLock"); + else if (val == (content::PermissionType)(PermissionType::FULLSCREEN)) + return StringToV8(isolate, "fullscreen"); + + return StringToV8(isolate, "unknown"); } // static