1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "third_party/blink/renderer/core/loader/navigation_policy.h"
32
33 #include "build/build_config.h"
34 #include "third_party/blink/public/common/input/web_keyboard_event.h"
35 #include "third_party/blink/public/common/input/web_mouse_event.h"
36 #include "third_party/blink/public/web/web_navigation_policy.h"
37 #include "third_party/blink/public/web/web_window_features.h"
38 #include "third_party/blink/renderer/core/events/current_input_event.h"
39 #include "third_party/blink/renderer/core/events/gesture_event.h"
40 #include "third_party/blink/renderer/core/events/keyboard_event.h"
41 #include "third_party/blink/renderer/core/events/mouse_event.h"
42 #include "third_party/blink/renderer/core/events/ui_event_with_key_state.h"
43 #include "third_party/blink/renderer/platform/keyboard_codes.h"
44 #include "third_party/blink/renderer/platform/wtf/assertions.h"
45
46 namespace blink {
47
48 namespace {
49
NavigationPolicyFromEventModifiers(int16_t button,bool ctrl,bool shift,bool alt,bool meta)50 NavigationPolicy NavigationPolicyFromEventModifiers(int16_t button,
51 bool ctrl,
52 bool shift,
53 bool alt,
54 bool meta) {
55 #if defined(OS_MAC)
56 const bool new_tab_modifier = (button == 1) || meta;
57 #else
58 const bool new_tab_modifier = (button == 1) || ctrl;
59 #endif
60 if (!new_tab_modifier && !shift && !alt)
61 return kNavigationPolicyCurrentTab;
62
63 if (new_tab_modifier) {
64 if (shift)
65 return kNavigationPolicyNewForegroundTab;
66 else
67 return kNavigationPolicyNewBackgroundTab;
68 } else {
69 if (shift)
70 return kNavigationPolicyNewWindow;
71 else
72 return kNavigationPolicyDownload;
73 }
74 return kNavigationPolicyCurrentTab;
75 }
76
NavigationPolicyFromEventInternal(const Event * event)77 NavigationPolicy NavigationPolicyFromEventInternal(const Event* event) {
78 if (!event)
79 return kNavigationPolicyCurrentTab;
80
81 if (const auto* mouse_event = DynamicTo<MouseEvent>(event)) {
82 return NavigationPolicyFromEventModifiers(
83 mouse_event->button(), mouse_event->ctrlKey(), mouse_event->shiftKey(),
84 mouse_event->altKey(), mouse_event->metaKey());
85 } else if (const KeyboardEvent* key_event = DynamicTo<KeyboardEvent>(event)) {
86 // The click is simulated when triggering the keypress event.
87 return NavigationPolicyFromEventModifiers(
88 0, key_event->ctrlKey(), key_event->shiftKey(), key_event->altKey(),
89 key_event->metaKey());
90 } else if (const auto* gesture_event = DynamicTo<GestureEvent>(event)) {
91 // The click is simulated when triggering the gesture-tap event
92 return NavigationPolicyFromEventModifiers(
93 0, gesture_event->ctrlKey(), gesture_event->shiftKey(),
94 gesture_event->altKey(), gesture_event->metaKey());
95 }
96 return kNavigationPolicyCurrentTab;
97 }
98
NavigationPolicyFromCurrentEvent()99 NavigationPolicy NavigationPolicyFromCurrentEvent() {
100 const WebInputEvent* event = CurrentInputEvent::Get();
101 if (!event)
102 return kNavigationPolicyCurrentTab;
103
104 int16_t button = 0;
105 if (event->GetType() == WebInputEvent::Type::kMouseUp) {
106 const WebMouseEvent* mouse_event = static_cast<const WebMouseEvent*>(event);
107
108 switch (mouse_event->button) {
109 case WebMouseEvent::Button::kLeft:
110 button = 0;
111 break;
112 case WebMouseEvent::Button::kMiddle:
113 button = 1;
114 break;
115 case WebMouseEvent::Button::kRight:
116 button = 2;
117 break;
118 default:
119 return kNavigationPolicyCurrentTab;
120 }
121 } else if ((WebInputEvent::IsKeyboardEventType(event->GetType()) &&
122 static_cast<const WebKeyboardEvent*>(event)->windows_key_code ==
123 VKEY_RETURN) ||
124 WebInputEvent::IsGestureEventType(event->GetType())) {
125 // Keyboard and gesture events can simulate mouse events.
126 button = 0;
127 } else {
128 return kNavigationPolicyCurrentTab;
129 }
130
131 return NavigationPolicyFromEventModifiers(
132 button, event->GetModifiers() & WebInputEvent::kControlKey,
133 event->GetModifiers() & WebInputEvent::kShiftKey,
134 event->GetModifiers() & WebInputEvent::kAltKey,
135 event->GetModifiers() & WebInputEvent::kMetaKey);
136 }
137
138 } // namespace
139
NavigationPolicyFromEvent(const Event * event)140 NavigationPolicy NavigationPolicyFromEvent(const Event* event) {
141 NavigationPolicy event_policy = NavigationPolicyFromEventInternal(event);
142 NavigationPolicy input_policy = NavigationPolicyFromCurrentEvent();
143
144 if (event_policy == kNavigationPolicyDownload &&
145 input_policy != kNavigationPolicyDownload) {
146 // No downloads from synthesized events without user intention.
147 return kNavigationPolicyCurrentTab;
148 }
149
150 if (event_policy == kNavigationPolicyNewBackgroundTab &&
151 input_policy != kNavigationPolicyNewBackgroundTab &&
152 !UIEventWithKeyState::NewTabModifierSetFromIsolatedWorld()) {
153 // No "tab-unders" from synthesized events without user intention.
154 // Events originating from an isolated world are exempt.
155 return kNavigationPolicyNewForegroundTab;
156 }
157
158 return event_policy;
159 }
160
NavigationPolicyForCreateWindow(const WebWindowFeatures & features)161 NavigationPolicy NavigationPolicyForCreateWindow(
162 const WebWindowFeatures& features) {
163 // If our default configuration was modified by a script or wasn't
164 // created by a user gesture, then show as a popup. Else, let this
165 // new window be opened as a toplevel window.
166 bool as_popup = !features.tool_bar_visible || !features.status_bar_visible ||
167 !features.scrollbars_visible || !features.menu_bar_visible ||
168 !features.resizable;
169 NavigationPolicy app_policy =
170 as_popup ? kNavigationPolicyNewPopup : kNavigationPolicyNewForegroundTab;
171 NavigationPolicy user_policy = NavigationPolicyFromCurrentEvent();
172
173 if (user_policy == kNavigationPolicyNewWindow &&
174 app_policy == kNavigationPolicyNewPopup) {
175 // User and app agree that we want a new window; let the app override the
176 // decorations.
177 return app_policy;
178 }
179
180 if (user_policy == kNavigationPolicyCurrentTab) {
181 // User doesn't want a specific policy, use app policy instead.
182 return app_policy;
183 }
184
185 if (user_policy == kNavigationPolicyDownload) {
186 // When the input event suggests a download, but the navigation was
187 // initiated by script, we should not override it.
188 return app_policy;
189 }
190
191 return user_policy;
192 }
193
194 STATIC_ASSERT_ENUM(kWebNavigationPolicyDownload, kNavigationPolicyDownload);
195 STATIC_ASSERT_ENUM(kWebNavigationPolicyCurrentTab, kNavigationPolicyCurrentTab);
196 STATIC_ASSERT_ENUM(kWebNavigationPolicyNewBackgroundTab,
197 kNavigationPolicyNewBackgroundTab);
198 STATIC_ASSERT_ENUM(kWebNavigationPolicyNewForegroundTab,
199 kNavigationPolicyNewForegroundTab);
200 STATIC_ASSERT_ENUM(kWebNavigationPolicyNewWindow, kNavigationPolicyNewWindow);
201 STATIC_ASSERT_ENUM(kWebNavigationPolicyNewPopup, kNavigationPolicyNewPopup);
202
203 } // namespace blink
204