Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / exclusive_access / mouse_lock_controller.cc
blob84c36606344226751d0bfd035f57655a6a27039e
1 // Copyright (c) 2015 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.
5 #include "chrome/browser/ui/exclusive_access/mouse_lock_controller.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
12 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
13 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
14 #include "components/content_settings/core/browser/host_content_settings_map.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/render_widget_host_view.h"
18 #include "content/public/browser/web_contents.h"
20 using content::RenderViewHost;
21 using content::WebContents;
23 MouseLockController::MouseLockController(ExclusiveAccessManager* manager)
24 : ExclusiveAccessControllerBase(manager),
25 mouse_lock_state_(MOUSELOCK_NOT_REQUESTED) {
28 MouseLockController::~MouseLockController() {
31 bool MouseLockController::IsMouseLocked() const {
32 return mouse_lock_state_ == MOUSELOCK_ACCEPTED ||
33 mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY;
36 bool MouseLockController::IsMouseLockSilentlyAccepted() const {
37 return mouse_lock_state_ == MOUSELOCK_ACCEPTED_SILENTLY;
40 void MouseLockController::RequestToLockMouse(WebContents* web_contents,
41 bool user_gesture,
42 bool last_unlocked_by_target) {
43 DCHECK(!IsMouseLocked());
44 NotifyMouseLockChange();
46 // Must have a user gesture to prevent misbehaving sites from constantly
47 // re-locking the mouse. Exceptions are when the page has unlocked
48 // (i.e. not the user), or if we're in tab fullscreen (user gesture required
49 // for that)
50 if (!last_unlocked_by_target && !user_gesture &&
51 !exclusive_access_manager()
52 ->fullscreen_controller()
53 ->IsFullscreenForTabOrPending(web_contents)) {
54 web_contents->GotResponseToLockMouseRequest(false);
55 return;
57 SetTabWithExclusiveAccess(web_contents);
58 ExclusiveAccessBubbleType bubble_type =
59 exclusive_access_manager()->GetExclusiveAccessExitBubbleType();
61 switch (GetMouseLockSetting(web_contents->GetURL())) {
62 case CONTENT_SETTING_ALLOW:
63 // If bubble already displaying buttons we must not lock the mouse yet,
64 // or it would prevent pressing those buttons. Instead, merge the request.
65 if (!exclusive_access_manager()
66 ->fullscreen_controller()
67 ->IsPrivilegedFullscreenForTab() &&
68 exclusive_access_bubble::ShowButtonsForType(bubble_type)) {
69 mouse_lock_state_ = MOUSELOCK_REQUESTED;
70 } else {
71 // Lock mouse.
72 if (web_contents->GotResponseToLockMouseRequest(true)) {
73 if (last_unlocked_by_target) {
74 mouse_lock_state_ = MOUSELOCK_ACCEPTED_SILENTLY;
75 } else {
76 mouse_lock_state_ = MOUSELOCK_ACCEPTED;
78 } else {
79 SetTabWithExclusiveAccess(nullptr);
80 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
83 break;
84 case CONTENT_SETTING_BLOCK:
85 web_contents->GotResponseToLockMouseRequest(false);
86 SetTabWithExclusiveAccess(nullptr);
87 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
88 break;
89 case CONTENT_SETTING_ASK:
90 mouse_lock_state_ = MOUSELOCK_REQUESTED;
91 break;
92 default:
93 NOTREACHED();
95 exclusive_access_manager()->UpdateExclusiveAccessExitBubbleContent();
98 void MouseLockController::ExitExclusiveAccessIfNecessary() {
99 NotifyTabExclusiveAccessLost();
102 void MouseLockController::NotifyTabExclusiveAccessLost() {
103 WebContents* tab = exclusive_access_tab();
104 if (tab) {
105 if (IsMouseLockRequested()) {
106 tab->GotResponseToLockMouseRequest(false);
107 NotifyMouseLockChange();
108 } else {
109 UnlockMouse();
111 SetTabWithExclusiveAccess(nullptr);
112 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
113 exclusive_access_manager()->UpdateExclusiveAccessExitBubbleContent();
117 bool MouseLockController::HandleUserPressedEscape() {
118 if (IsMouseLocked() || IsMouseLockRequested()) {
119 ExitExclusiveAccessIfNecessary();
120 return true;
123 return false;
126 void MouseLockController::ExitExclusiveAccessToPreviousState() {
127 // Nothing to do for mouse lock.
130 bool MouseLockController::OnAcceptExclusiveAccessPermission() {
131 ExclusiveAccessBubbleType bubble_type =
132 exclusive_access_manager()->GetExclusiveAccessExitBubbleType();
133 bool mouse_lock = false;
134 exclusive_access_bubble::PermissionRequestedByType(bubble_type, nullptr,
135 &mouse_lock);
136 DCHECK(!(mouse_lock && IsMouseLocked()));
138 if (mouse_lock && !IsMouseLocked()) {
139 DCHECK(IsMouseLockRequested());
141 HostContentSettingsMap* settings_map =
142 HostContentSettingsMapFactory::GetForProfile(
143 exclusive_access_manager()->context()->GetProfile());
145 GURL url = GetExclusiveAccessBubbleURL();
146 ContentSettingsPattern pattern = ContentSettingsPattern::FromURL(url);
148 // TODO(markusheintz): We should allow patterns for all possible URLs here.
150 // Do not store preference on file:// URLs, they don't have a clean
151 // origin policy.
152 // TODO(estark): Revisit this when crbug.com/455882 is fixed.
153 if (!url.SchemeIsFile() && pattern.IsValid()) {
154 settings_map->SetContentSetting(pattern,
155 ContentSettingsPattern::Wildcard(),
156 CONTENT_SETTINGS_TYPE_MOUSELOCK,
157 std::string(), CONTENT_SETTING_ALLOW);
160 WebContents* tab = exclusive_access_tab();
161 if (tab && tab->GotResponseToLockMouseRequest(true)) {
162 mouse_lock_state_ = MOUSELOCK_ACCEPTED;
163 } else {
164 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
165 SetTabWithExclusiveAccess(nullptr);
167 NotifyMouseLockChange();
168 return true;
171 return false;
174 bool MouseLockController::OnDenyExclusiveAccessPermission() {
175 WebContents* tab = exclusive_access_tab();
177 if (tab && IsMouseLockRequested()) {
178 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
179 tab->GotResponseToLockMouseRequest(false);
180 SetTabWithExclusiveAccess(nullptr);
181 NotifyMouseLockChange();
182 return true;
185 return false;
188 void MouseLockController::LostMouseLock() {
189 mouse_lock_state_ = MOUSELOCK_NOT_REQUESTED;
190 SetTabWithExclusiveAccess(nullptr);
191 NotifyMouseLockChange();
192 exclusive_access_manager()->UpdateExclusiveAccessExitBubbleContent();
195 bool MouseLockController::IsMouseLockRequested() const {
196 return mouse_lock_state_ == MOUSELOCK_REQUESTED;
199 void MouseLockController::NotifyMouseLockChange() {
200 content::NotificationService::current()->Notify(
201 chrome::NOTIFICATION_MOUSE_LOCK_CHANGED,
202 content::Source<MouseLockController>(this),
203 content::NotificationService::NoDetails());
206 void MouseLockController::UnlockMouse() {
207 WebContents* tab = exclusive_access_tab();
209 if (!tab)
210 return;
212 content::RenderWidgetHostView* mouse_lock_view = nullptr;
213 FullscreenController* fullscreen_controller =
214 exclusive_access_manager()->fullscreen_controller();
215 if ((fullscreen_controller->exclusive_access_tab() == tab) &&
216 fullscreen_controller->IsPrivilegedFullscreenForTab()) {
217 mouse_lock_view =
218 exclusive_access_tab()->GetFullscreenRenderWidgetHostView();
221 if (!mouse_lock_view) {
222 RenderViewHost* const rvh = exclusive_access_tab()->GetRenderViewHost();
223 if (rvh)
224 mouse_lock_view = rvh->GetView();
227 if (mouse_lock_view)
228 mouse_lock_view->UnlockMouse();
231 ContentSetting MouseLockController::GetMouseLockSetting(const GURL& url) const {
232 // If simplified UI is enabled, never ask the user, just auto-allow. (Always
233 // return CONTENT_SETTING_ALLOW in favour of CONTENT_SETTING_ASK.)
234 bool simplified_ui =
235 ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled();
237 // Always ask on file:// URLs, since we can't meaningfully make the
238 // decision stick for a particular origin.
239 // TODO(estark): Revisit this when crbug.com/455882 is fixed.
240 if (url.SchemeIsFile() && !simplified_ui)
241 return CONTENT_SETTING_ASK;
243 if (exclusive_access_manager()
244 ->fullscreen_controller()
245 ->IsPrivilegedFullscreenForTab())
246 return CONTENT_SETTING_ALLOW;
248 HostContentSettingsMap* settings_map =
249 HostContentSettingsMapFactory::GetForProfile(
250 exclusive_access_manager()->context()->GetProfile());
251 ContentSetting setting = settings_map->GetContentSetting(
252 url, url, CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string());
254 if (simplified_ui && setting == CONTENT_SETTING_ASK)
255 return CONTENT_SETTING_ALLOW;
257 return setting;