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