/* * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "third_party/blink/renderer/core/loader/navigation_policy.h" #include "build/build_config.h" #include "third_party/blink/public/platform/web_keyboard_event.h" #include "third_party/blink/public/platform/web_mouse_event.h" #include "third_party/blink/public/web/web_navigation_policy.h" #include "third_party/blink/public/web/web_window_features.h" #include "third_party/blink/renderer/core/events/current_input_event.h" #include "third_party/blink/renderer/core/events/gesture_event.h" #include "third_party/blink/renderer/core/events/keyboard_event.h" #include "third_party/blink/renderer/core/events/mouse_event.h" #include "third_party/blink/renderer/core/events/ui_event_with_key_state.h" #include "third_party/blink/renderer/platform/keyboard_codes.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" namespace blink { namespace { NavigationPolicy NavigationPolicyFromEventModifiers(unsigned short button, bool ctrl, bool shift, bool alt, bool meta) { #if defined(OS_MACOSX) const bool new_tab_modifier = (button == 1) || meta; #else const bool new_tab_modifier = (button == 1) || ctrl; #endif if (!new_tab_modifier && !shift && !alt) return kNavigationPolicyCurrentTab; if (new_tab_modifier) { if (shift) return kNavigationPolicyNewForegroundTab; else return kNavigationPolicyNewBackgroundTab; } else { if (shift) return kNavigationPolicyNewWindow; else return kNavigationPolicyDownload; } return kNavigationPolicyCurrentTab; } NavigationPolicy NavigationPolicyFromEventInternal(Event* event) { if (!event) return kNavigationPolicyCurrentTab; if (event->IsMouseEvent()) { MouseEvent* mouse_event = ToMouseEvent(event); return NavigationPolicyFromEventModifiers( mouse_event->button(), mouse_event->ctrlKey(), mouse_event->shiftKey(), mouse_event->altKey(), mouse_event->metaKey()); } else if (event->IsKeyboardEvent()) { // The click is simulated when triggering the keypress event. KeyboardEvent* key_event = ToKeyboardEvent(event); return NavigationPolicyFromEventModifiers( 0, key_event->ctrlKey(), key_event->shiftKey(), key_event->altKey(), key_event->metaKey()); } else if (event->IsGestureEvent()) { // The click is simulated when triggering the gesture-tap event GestureEvent* gesture_event = ToGestureEvent(event); return NavigationPolicyFromEventModifiers( 0, gesture_event->ctrlKey(), gesture_event->shiftKey(), gesture_event->altKey(), gesture_event->metaKey()); } return kNavigationPolicyCurrentTab; } NavigationPolicy NavigationPolicyFromCurrentEvent() { const WebInputEvent* event = CurrentInputEvent::Get(); if (!event) return kNavigationPolicyCurrentTab; unsigned short button = 0; if (event->GetType() == WebInputEvent::kMouseUp) { const WebMouseEvent* mouse_event = static_cast(event); switch (mouse_event->button) { case WebMouseEvent::Button::kLeft: button = 0; break; case WebMouseEvent::Button::kMiddle: button = 1; break; case WebMouseEvent::Button::kRight: button = 2; break; default: return kNavigationPolicyCurrentTab; } } else if ((WebInputEvent::IsKeyboardEventType(event->GetType()) && static_cast(event)->windows_key_code == VKEY_RETURN) || WebInputEvent::IsGestureEventType(event->GetType())) { // Keyboard and gesture events can simulate mouse events. button = 0; } else { return kNavigationPolicyCurrentTab; } return NavigationPolicyFromEventModifiers( button, event->GetModifiers() & WebInputEvent::kControlKey, event->GetModifiers() & WebInputEvent::kShiftKey, event->GetModifiers() & WebInputEvent::kAltKey, event->GetModifiers() & WebInputEvent::kMetaKey); } } // namespace NavigationPolicy NavigationPolicyFromEvent(Event* event) { NavigationPolicy event_policy = NavigationPolicyFromEventInternal(event); NavigationPolicy input_policy = NavigationPolicyFromCurrentEvent(); if (event_policy == kNavigationPolicyDownload && input_policy != kNavigationPolicyDownload) { // No downloads from synthesized events without user intention. return kNavigationPolicyCurrentTab; } if (event_policy == kNavigationPolicyNewBackgroundTab && input_policy != kNavigationPolicyNewBackgroundTab && !UIEventWithKeyState::NewTabModifierSetFromIsolatedWorld()) { // No "tab-unders" from synthesized events without user intention. // Events originating from an isolated world are exempt. return kNavigationPolicyNewForegroundTab; } return event_policy; } NavigationPolicy NavigationPolicyForCreateWindow( const WebWindowFeatures& features) { // If our default configuration was modified by a script or wasn't // created by a user gesture, then show as a popup. Else, let this // new window be opened as a toplevel window. bool as_popup = !features.tool_bar_visible || !features.status_bar_visible || !features.scrollbars_visible || !features.menu_bar_visible || !features.resizable; NavigationPolicy app_policy = as_popup ? kNavigationPolicyNewPopup : kNavigationPolicyNewForegroundTab; NavigationPolicy user_policy = NavigationPolicyFromCurrentEvent(); if (user_policy == kNavigationPolicyNewWindow && app_policy == kNavigationPolicyNewPopup) { // User and app agree that we want a new window; let the app override the // decorations. return app_policy; } if (user_policy == kNavigationPolicyCurrentTab) { // User doesn't want a specific policy, use app policy instead. return app_policy; } if (user_policy == kNavigationPolicyDownload) { // When the input event suggests a download, but the navigation was // initiated by script, we should not override it. return app_policy; } return user_policy; } STATIC_ASSERT_ENUM(kWebNavigationPolicyDownload, kNavigationPolicyDownload); STATIC_ASSERT_ENUM(kWebNavigationPolicyCurrentTab, kNavigationPolicyCurrentTab); STATIC_ASSERT_ENUM(kWebNavigationPolicyNewBackgroundTab, kNavigationPolicyNewBackgroundTab); STATIC_ASSERT_ENUM(kWebNavigationPolicyNewForegroundTab, kNavigationPolicyNewForegroundTab); STATIC_ASSERT_ENUM(kWebNavigationPolicyNewWindow, kNavigationPolicyNewWindow); STATIC_ASSERT_ENUM(kWebNavigationPolicyNewPopup, kNavigationPolicyNewPopup); } // namespace blink