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 #ifndef mozilla_EventStates_h_ 8 #define mozilla_EventStates_h_ 9 10 #include "mozilla/Attributes.h" 11 #include "nsDebug.h" 12 13 namespace mozilla { 14 15 /** 16 * EventStates is the class used to represent the event states of nsIContent 17 * instances. These states are calculated by IntrinsicState() and 18 * ContentStatesChanged() has to be called when one of them changes thus 19 * informing the layout/style engine of the change. 20 * Event states are associated with pseudo-classes. 21 */ 22 class EventStates { 23 public: 24 typedef uint64_t InternalType; 25 typedef uint64_t ServoType; 26 EventStates()27 constexpr EventStates() : mStates(0) {} 28 29 // NOTE: the ideal scenario would be to have the default constructor public 30 // setting mStates to 0 and this constructor (without = 0) private. 31 // In that case, we could be sure that only macros at the end were creating 32 // EventStates instances with mStates set to something else than 0. 33 // Unfortunately, this constructor is needed at at least two places now. EventStates(InternalType aStates)34 explicit constexpr EventStates(InternalType aStates) : mStates(aStates) {} 35 36 EventStates constexpr operator|(const EventStates& aEventStates) const { 37 return EventStates(mStates | aEventStates.mStates); 38 } 39 40 EventStates& operator|=(const EventStates& aEventStates) { 41 mStates |= aEventStates.mStates; 42 return *this; 43 } 44 45 // NOTE: calling if (eventStates1 & eventStates2) will not build. 46 // This might work correctly if operator bool() is defined 47 // but using HasState, HasAllStates or HasAtLeastOneOfStates is recommended. 48 EventStates constexpr operator&(const EventStates& aEventStates) const { 49 return EventStates(mStates & aEventStates.mStates); 50 } 51 52 EventStates& operator&=(const EventStates& aEventStates) { 53 mStates &= aEventStates.mStates; 54 return *this; 55 } 56 57 bool operator==(const EventStates& aEventStates) const { 58 return mStates == aEventStates.mStates; 59 } 60 61 bool operator!=(const EventStates& aEventStates) const { 62 return mStates != aEventStates.mStates; 63 } 64 65 EventStates operator~() const { return EventStates(~mStates); } 66 67 EventStates operator^(const EventStates& aEventStates) const { 68 return EventStates(mStates ^ aEventStates.mStates); 69 } 70 71 EventStates& operator^=(const EventStates& aEventStates) { 72 mStates ^= aEventStates.mStates; 73 return *this; 74 } 75 76 /** 77 * Returns true if the EventStates instance is empty. 78 * A EventStates instance is empty if it contains no state. 79 * 80 * @return Whether if the object is empty. 81 */ IsEmpty()82 bool IsEmpty() const { return mStates == 0; } 83 84 /** 85 * Returns true if the EventStates instance contains the state 86 * contained in aEventStates. 87 * @note aEventStates should contain only one state. 88 * 89 * @param aEventStates The state to check. 90 * 91 * @return Whether the object has the state from aEventStates 92 */ HasState(EventStates aEventStates)93 bool HasState(EventStates aEventStates) const { 94 #ifdef DEBUG 95 // If aEventStates.mStates is a power of two, it contains only one state 96 // (or none, but we don't really care). 97 if ((aEventStates.mStates & (aEventStates.mStates - 1))) { 98 NS_ERROR( 99 "When calling HasState, " 100 "EventStates object has to contain only one state!"); 101 } 102 #endif // DEBUG 103 return mStates & aEventStates.mStates; 104 } 105 106 /** 107 * Returns true if the EventStates instance contains one of the states 108 * contained in aEventStates. 109 * 110 * @param aEventStates The states to check. 111 * 112 * @return Whether the object has at least one state from aEventStates 113 */ HasAtLeastOneOfStates(EventStates aEventStates)114 bool HasAtLeastOneOfStates(EventStates aEventStates) const { 115 return mStates & aEventStates.mStates; 116 } 117 118 /** 119 * Returns true if the EventStates instance contains all states 120 * contained in aEventStates. 121 * 122 * @param aEventStates The states to check. 123 * 124 * @return Whether the object has all states from aEventStates 125 */ HasAllStates(EventStates aEventStates)126 bool HasAllStates(EventStates aEventStates) const { 127 return (mStates & aEventStates.mStates) == aEventStates.mStates; 128 } 129 130 // We only need that method for InspectorUtils::GetContentState. 131 // If InspectorUtils::GetContentState is removed, this method should 132 // be removed. GetInternalValue()133 InternalType GetInternalValue() const { return mStates; } 134 135 /** 136 * Method used to get the appropriate state representation for Servo. 137 */ ServoValue()138 ServoType ServoValue() const { return mStates; } 139 140 private: 141 InternalType mStates; 142 }; 143 144 } // namespace mozilla 145 146 /** 147 * The following macros are creating EventStates instance with different 148 * values depending of their meaning. 149 * Ideally, EventStates instance with values different than 0 should only be 150 * created that way. 151 */ 152 153 // Helper to define a new EventStates macro. 154 #define NS_DEFINE_EVENT_STATE_MACRO(_val) \ 155 (mozilla::EventStates(mozilla::EventStates::InternalType(1) << _val)) 156 157 /* 158 * In order to efficiently convert Gecko EventState values into Servo 159 * ElementState values [1], we maintain the invariant that the low bits of 160 * EventState can be masked off to form an ElementState (this works so 161 * long as Servo never supports a state that Gecko doesn't). 162 * 163 * This is unfortunately rather fragile for now, but we should soon have 164 * the infrastructure to statically-assert that these match up. If you 165 * need to change these, please notify somebody involved with Stylo. 166 * 167 * [1] 168 * https://github.com/servo/servo/blob/master/components/style/element_state.rs 169 */ 170 171 // Mouse is down on content. 172 #define NS_EVENT_STATE_ACTIVE NS_DEFINE_EVENT_STATE_MACRO(0) 173 // Content has focus. 174 #define NS_EVENT_STATE_FOCUS NS_DEFINE_EVENT_STATE_MACRO(1) 175 // Mouse is hovering over content. 176 #define NS_EVENT_STATE_HOVER NS_DEFINE_EVENT_STATE_MACRO(2) 177 // Content is enabled (and can be disabled). 178 #define NS_EVENT_STATE_ENABLED NS_DEFINE_EVENT_STATE_MACRO(3) 179 // Content is disabled. 180 #define NS_EVENT_STATE_DISABLED NS_DEFINE_EVENT_STATE_MACRO(4) 181 // Content is checked. 182 #define NS_EVENT_STATE_CHECKED NS_DEFINE_EVENT_STATE_MACRO(5) 183 // Content is in the indeterminate state. 184 #define NS_EVENT_STATE_INDETERMINATE NS_DEFINE_EVENT_STATE_MACRO(6) 185 // Content shows its placeholder 186 #define NS_EVENT_STATE_PLACEHOLDERSHOWN NS_DEFINE_EVENT_STATE_MACRO(7) 187 // Content is URL's target (ref). 188 #define NS_EVENT_STATE_URLTARGET NS_DEFINE_EVENT_STATE_MACRO(8) 189 // Content is the full screen element, or a frame containing the 190 // current fullscreen element. 191 #define NS_EVENT_STATE_FULLSCREEN NS_DEFINE_EVENT_STATE_MACRO(9) 192 // Content is valid (and can be invalid). 193 #define NS_EVENT_STATE_VALID NS_DEFINE_EVENT_STATE_MACRO(10) 194 // Content is invalid. 195 #define NS_EVENT_STATE_INVALID NS_DEFINE_EVENT_STATE_MACRO(11) 196 // UI friendly version of :valid pseudo-class. 197 #define NS_EVENT_STATE_MOZ_UI_VALID NS_DEFINE_EVENT_STATE_MACRO(12) 198 // UI friendly version of :invalid pseudo-class. 199 #define NS_EVENT_STATE_MOZ_UI_INVALID NS_DEFINE_EVENT_STATE_MACRO(13) 200 // Content could not be rendered (image/object/etc). 201 #define NS_EVENT_STATE_BROKEN NS_DEFINE_EVENT_STATE_MACRO(14) 202 // Content is still loading such that there is nothing to show the 203 // user (eg an image which hasn't started coming in yet). 204 #define NS_EVENT_STATE_LOADING NS_DEFINE_EVENT_STATE_MACRO(15) 205 // Content is required. 206 #define NS_EVENT_STATE_REQUIRED NS_DEFINE_EVENT_STATE_MACRO(16) 207 // Content is optional (and can be required). 208 #define NS_EVENT_STATE_OPTIONAL NS_DEFINE_EVENT_STATE_MACRO(17) 209 // Element is either a defined custom element or uncustomized element. 210 #define NS_EVENT_STATE_DEFINED NS_DEFINE_EVENT_STATE_MACRO(18) 211 // Link has been visited. 212 #define NS_EVENT_STATE_VISITED NS_DEFINE_EVENT_STATE_MACRO(19) 213 // Link hasn't been visited. 214 #define NS_EVENT_STATE_UNVISITED NS_DEFINE_EVENT_STATE_MACRO(20) 215 // Drag is hovering over content. 216 #define NS_EVENT_STATE_DRAGOVER NS_DEFINE_EVENT_STATE_MACRO(21) 217 // Content value is in-range (and can be out-of-range). 218 #define NS_EVENT_STATE_INRANGE NS_DEFINE_EVENT_STATE_MACRO(22) 219 // Content value is out-of-range. 220 #define NS_EVENT_STATE_OUTOFRANGE NS_DEFINE_EVENT_STATE_MACRO(23) 221 // Content is read-only. 222 // TODO(emilio): This is always the inverse of READWRITE. With some style system 223 // work we could remove one of the two bits. 224 #define NS_EVENT_STATE_READONLY NS_DEFINE_EVENT_STATE_MACRO(24) 225 // Content is editable. 226 #define NS_EVENT_STATE_READWRITE NS_DEFINE_EVENT_STATE_MACRO(25) 227 // Content is the default one (meaning depends of the context). 228 #define NS_EVENT_STATE_DEFAULT NS_DEFINE_EVENT_STATE_MACRO(26) 229 // Content is a submit control and the form isn't valid. 230 #define NS_EVENT_STATE_MOZ_SUBMITINVALID NS_DEFINE_EVENT_STATE_MACRO(27) 231 // Content is in the optimum region. 232 #define NS_EVENT_STATE_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(28) 233 // Content is in the suboptimal region. 234 #define NS_EVENT_STATE_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(29) 235 // Content is in the sub-suboptimal region. 236 #define NS_EVENT_STATE_SUB_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(30) 237 #define NS_EVENT_STATE_INCREMENT_SCRIPT_LEVEL NS_DEFINE_EVENT_STATE_MACRO(31) 238 // Content has focus and should show a ring. 239 #define NS_EVENT_STATE_FOCUSRING NS_DEFINE_EVENT_STATE_MACRO(32) 240 // Element has focus-within. 241 #define NS_EVENT_STATE_FOCUS_WITHIN NS_DEFINE_EVENT_STATE_MACRO(33) 242 // Element is ltr (for :dir pseudo-class) 243 #define NS_EVENT_STATE_LTR NS_DEFINE_EVENT_STATE_MACRO(34) 244 // Element is rtl (for :dir pseudo-class) 245 #define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(35) 246 // States for tracking the state of the "dir" attribute for HTML elements. We 247 // use these to avoid having to get "dir" attributes all the time during 248 // selector matching for some parts of the UA stylesheet. 249 // 250 // These states are externally managed, because we also don't want to keep 251 // getting "dir" attributes in IntrinsicState. 252 // 253 // Element is HTML and has a "dir" attibute. This state might go away depending 254 // on how https://github.com/whatwg/html/issues/2769 gets resolved. The value 255 // could be anything. 256 #define NS_EVENT_STATE_HAS_DIR_ATTR NS_DEFINE_EVENT_STATE_MACRO(36) 257 // Element is HTML, has a "dir" attribute, and the attribute's value is 258 // case-insensitively equal to "ltr". 259 #define NS_EVENT_STATE_DIR_ATTR_LTR NS_DEFINE_EVENT_STATE_MACRO(37) 260 // Element is HTML, has a "dir" attribute, and the attribute's value is 261 // case-insensitively equal to "rtl". 262 #define NS_EVENT_STATE_DIR_ATTR_RTL NS_DEFINE_EVENT_STATE_MACRO(38) 263 // Element is HTML, and is either a <bdi> element with no valid-valued "dir" 264 // attribute or any HTML element which has a "dir" attribute whose value is 265 // "auto". 266 #define NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO NS_DEFINE_EVENT_STATE_MACRO(39) 267 // Element is filled by Autofill feature. 268 #define NS_EVENT_STATE_AUTOFILL NS_DEFINE_EVENT_STATE_MACRO(40) 269 // Element is filled with preview data by Autofill feature. 270 #define NS_EVENT_STATE_AUTOFILL_PREVIEW NS_DEFINE_EVENT_STATE_MACRO(41) 271 // Modal <dialog> element 272 #define NS_EVENT_STATE_MODAL_DIALOG NS_DEFINE_EVENT_STATE_MACRO(42) 273 // Inert subtrees 274 #define NS_EVENT_STATE_MOZINERT NS_DEFINE_EVENT_STATE_MACRO(43) 275 // Topmost Modal <dialog> element in top layer 276 #define NS_EVENT_STATE_TOPMOST_MODAL_DIALOG NS_DEFINE_EVENT_STATE_MACRO(44) 277 // Devtools highlighter (but it's used for something else atm). 278 #define NS_EVENT_STATE_DEVTOOLS_HIGHLIGHTED NS_DEFINE_EVENT_STATE_MACRO(45) 279 // Devtools style inspector stuff. 280 #define NS_EVENT_STATE_STYLEEDITOR_TRANSITIONING NS_DEFINE_EVENT_STATE_MACRO(46) 281 /** 282 * NOTE: do not go over 63 without updating EventStates::InternalType! 283 */ 284 285 #define DIRECTION_STATES (NS_EVENT_STATE_LTR | NS_EVENT_STATE_RTL) 286 287 #define DIR_ATTR_STATES \ 288 (NS_EVENT_STATE_HAS_DIR_ATTR | NS_EVENT_STATE_DIR_ATTR_LTR | \ 289 NS_EVENT_STATE_DIR_ATTR_RTL | NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO) 290 291 #define DISABLED_STATES (NS_EVENT_STATE_DISABLED | NS_EVENT_STATE_ENABLED) 292 293 #define REQUIRED_STATES (NS_EVENT_STATE_REQUIRED | NS_EVENT_STATE_OPTIONAL) 294 295 // Event states that can be added and removed through 296 // Element::{Add,Remove}ManuallyManagedStates. 297 // 298 // Take care when manually managing state bits. You are responsible for 299 // setting or clearing the bit when an Element is added or removed from a 300 // document (e.g. in BindToTree and UnbindFromTree), if that is an 301 // appropriate thing to do for your state bit. 302 #define MANUALLY_MANAGED_STATES \ 303 (NS_EVENT_STATE_AUTOFILL | NS_EVENT_STATE_AUTOFILL_PREVIEW) 304 305 // Event states that are managed externally to an element (by the 306 // EventStateManager, or by other code). As opposed to those in 307 // INTRINSIC_STATES, which are are computed by the element itself 308 // and returned from Element::IntrinsicState. 309 #define EXTERNALLY_MANAGED_STATES \ 310 (MANUALLY_MANAGED_STATES | DIR_ATTR_STATES | DISABLED_STATES | \ 311 REQUIRED_STATES | NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_DEFINED | \ 312 NS_EVENT_STATE_DRAGOVER | NS_EVENT_STATE_FOCUS | NS_EVENT_STATE_FOCUSRING | \ 313 NS_EVENT_STATE_FOCUS_WITHIN | NS_EVENT_STATE_FULLSCREEN | \ 314 NS_EVENT_STATE_HOVER | NS_EVENT_STATE_URLTARGET | \ 315 NS_EVENT_STATE_MODAL_DIALOG | NS_EVENT_STATE_MOZINERT | \ 316 NS_EVENT_STATE_TOPMOST_MODAL_DIALOG) 317 318 #define INTRINSIC_STATES (~EXTERNALLY_MANAGED_STATES) 319 320 #endif // mozilla_EventStates_h_ 321