UserActivation.cpp (5215B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/dom/UserActivation.h" 8 9 #include "mozilla/TextEvents.h" 10 #include "mozilla/dom/BrowsingContext.h" 11 #include "mozilla/dom/UserActivationBinding.h" 12 #include "mozilla/dom/WindowGlobalChild.h" 13 14 namespace mozilla::dom { 15 16 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(UserActivation, mWindow) 17 NS_IMPL_CYCLE_COLLECTING_ADDREF(UserActivation) 18 NS_IMPL_CYCLE_COLLECTING_RELEASE(UserActivation) 19 20 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UserActivation) 21 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 22 NS_INTERFACE_MAP_ENTRY(nsISupports) 23 NS_INTERFACE_MAP_END 24 25 UserActivation::UserActivation(nsPIDOMWindowInner* aWindow) 26 : mWindow(aWindow) {} 27 28 JSObject* UserActivation::WrapObject(JSContext* aCx, 29 JS::Handle<JSObject*> aGivenProto) { 30 return UserActivation_Binding::Wrap(aCx, this, aGivenProto); 31 }; 32 33 // https://html.spec.whatwg.org/multipage/interaction.html#dom-useractivation-hasbeenactive 34 bool UserActivation::HasBeenActive() const { 35 // The hasBeenActive getter steps are to return true if this's relevant global 36 // object has sticky activation, and false otherwise. 37 38 WindowContext* wc = mWindow->GetWindowContext(); 39 return wc && wc->HasBeenUserGestureActivated(); 40 } 41 42 // https://html.spec.whatwg.org/multipage/interaction.html#dom-useractivation-isactive 43 bool UserActivation::IsActive() const { 44 // The isActive getter steps are to return true if this's relevant global 45 // object has transient activation, and false otherwise. 46 47 WindowContext* wc = mWindow->GetWindowContext(); 48 return wc && wc->HasValidTransientUserGestureActivation(); 49 } 50 51 namespace { 52 53 // The current depth of user and keyboard inputs. sUserInputEventDepth 54 // is the number of any user input events, page load events and mouse over 55 // events. sUserKeyboardEventDepth is the number of keyboard input events. 56 // Incremented whenever we start handling a user input, decremented when we 57 // have finished handling a user input. This depth is *not* reset in case 58 // of nested event loops. 59 static int32_t sUserInputEventDepth = 0; 60 static int32_t sUserKeyboardEventDepth = 0; 61 62 // Time at which we began handling user input. Reset to the epoch 63 // once we have finished handling user input. 64 static TimeStamp sHandlingInputStart; 65 66 // Time at which we began handling the latest user input. Not reset 67 // at the end of the input. 68 static TimeStamp sLatestUserInputStart; 69 70 } // namespace 71 72 /* static */ 73 bool UserActivation::IsHandlingUserInput() { return sUserInputEventDepth > 0; } 74 75 /* static */ 76 bool UserActivation::IsHandlingKeyboardInput() { 77 return sUserKeyboardEventDepth > 0; 78 } 79 80 /* static */ 81 bool UserActivation::IsUserInteractionEvent(const WidgetEvent* aEvent) { 82 if (!aEvent->IsTrusted()) { 83 return false; 84 } 85 86 switch (aEvent->mMessage) { 87 // eKeyboardEventClass 88 case eKeyPress: 89 case eKeyDown: 90 case eKeyUp: 91 // Not all keyboard events are treated as user input, so that popups 92 // can't be opened, fullscreen mode can't be started, etc at 93 // unexpected time. 94 return aEvent->AsKeyboardEvent()->CanTreatAsUserInput(); 95 // eBasicEventClass 96 // eMouseEventClass 97 case eMouseDown: 98 case eMouseUp: 99 // ePointerEventClass 100 case ePointerClick: 101 case ePointerDown: 102 case ePointerUp: 103 // eTouchEventClass 104 case eTouchStart: 105 case eTouchEnd: 106 return true; 107 default: 108 return false; 109 } 110 } 111 112 /* static */ 113 void UserActivation::StartHandlingUserInput(EventMessage aMessage) { 114 ++sUserInputEventDepth; 115 if (sUserInputEventDepth == 1) { 116 sLatestUserInputStart = sHandlingInputStart = TimeStamp::Now(); 117 } 118 if (WidgetEvent::IsKeyEventMessage(aMessage)) { 119 ++sUserKeyboardEventDepth; 120 } 121 } 122 123 /* static */ 124 void UserActivation::StopHandlingUserInput(EventMessage aMessage) { 125 --sUserInputEventDepth; 126 if (sUserInputEventDepth == 0) { 127 sHandlingInputStart = TimeStamp(); 128 } 129 if (WidgetEvent::IsKeyEventMessage(aMessage)) { 130 --sUserKeyboardEventDepth; 131 } 132 } 133 134 /* static */ 135 TimeStamp UserActivation::GetHandlingInputStart() { 136 return sHandlingInputStart; 137 } 138 139 /* static */ 140 TimeStamp UserActivation::LatestUserInputStart() { 141 return sLatestUserInputStart; 142 } 143 144 //----------------------------------------------------------------------------- 145 // mozilla::dom::AutoHandlingUserInputStatePusher 146 //----------------------------------------------------------------------------- 147 148 AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher( 149 bool aIsHandlingUserInput, WidgetEvent* aEvent) 150 : mMessage(aEvent ? aEvent->mMessage : eVoidEvent), 151 mIsHandlingUserInput(aIsHandlingUserInput) { 152 if (!aIsHandlingUserInput) { 153 return; 154 } 155 UserActivation::StartHandlingUserInput(mMessage); 156 } 157 158 AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher() { 159 if (!mIsHandlingUserInput) { 160 return; 161 } 162 UserActivation::StopHandlingUserInput(mMessage); 163 } 164 165 } // namespace mozilla::dom