Skip to content

Commit

Permalink
Bug 1350140: stylo: Implement all the remaining state pseudo-classes.…
Browse files Browse the repository at this point in the history
… r=heycam

Also implements :link, :visited, and :any-link more efficiently, and stops
matching :-moz-read-only in everything that is not read-write, which is kind of
dumb, and probably creates some artifacts.

MozReview-Commit-ID: 6BQqi7nAWdT
Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
  • Loading branch information
emilio committed Mar 29, 2017
1 parent 299f944 commit a6277d5
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 81 deletions.
138 changes: 95 additions & 43 deletions components/style/element_state.rs
Expand Up @@ -4,64 +4,116 @@

//! States elements can be in.

#![deny(missing_docs)]

bitflags! {
#[doc = "Event-based element states."]
/// Event-based element states.
///
/// NB: Is important for this to remain in sync with Gecko's
/// dom/events/EventStates.h.
///
/// Please keep in that order in order for this to be easily auditable.
///
/// TODO(emilio): We really really want to use the NS_EVENT_STATE bindings
/// for this.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub flags ElementState: u32 {
#[doc = "The mouse is down on this element. \
https://html.spec.whatwg.org/multipage/#selector-active \
FIXME(#7333): set/unset this when appropriate"]
pub flags ElementState: u64 {
/// The mouse is down on this element.
/// https://html.spec.whatwg.org/multipage/#selector-active
/// FIXME(#7333): set/unset this when appropriate
const IN_ACTIVE_STATE = 1 << 0,
#[doc = "This element has focus. \
https://html.spec.whatwg.org/multipage/#selector-focus"]
/// This element has focus.
/// https://html.spec.whatwg.org/multipage/#selector-focus
const IN_FOCUS_STATE = 1 << 1,
#[doc = "The mouse is hovering over this element. \
https://html.spec.whatwg.org/multipage/#selector-hover"]
/// The mouse is hovering over this element.
/// https://html.spec.whatwg.org/multipage/#selector-hover
const IN_HOVER_STATE = 1 << 2,
#[doc = "Content is enabled (and can be disabled). \
http://www.whatwg.org/html/#selector-enabled"]
/// Content is enabled (and can be disabled).
/// http://www.whatwg.org/html/#selector-enabled
const IN_ENABLED_STATE = 1 << 3,
#[doc = "Content is disabled. \
http://www.whatwg.org/html/#selector-disabled"]
/// Content is disabled.
/// http://www.whatwg.org/html/#selector-disabled
const IN_DISABLED_STATE = 1 << 4,
#[doc = "Content is checked. \
https://html.spec.whatwg.org/multipage/#selector-checked"]
/// Content is checked.
/// https://html.spec.whatwg.org/multipage/#selector-checked
const IN_CHECKED_STATE = 1 << 5,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-indeterminate"]
/// https://html.spec.whatwg.org/multipage/#selector-indeterminate
const IN_INDETERMINATE_STATE = 1 << 6,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-placeholder-shown"]
/// https://html.spec.whatwg.org/multipage/#selector-placeholder-shown
const IN_PLACEHOLDER_SHOWN_STATE = 1 << 7,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-target"]
/// https://html.spec.whatwg.org/multipage/#selector-target
const IN_TARGET_STATE = 1 << 8,
#[doc = "https://fullscreen.spec.whatwg.org/#%3Afullscreen-pseudo-class"]
/// https://fullscreen.spec.whatwg.org/#%3Afullscreen-pseudo-class
const IN_FULLSCREEN_STATE = 1 << 9,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-valid"]
/// https://html.spec.whatwg.org/multipage/#selector-valid
const IN_VALID_STATE = 1 << 10,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-invalid"]
/// https://html.spec.whatwg.org/multipage/#selector-invalid
const IN_INVALID_STATE = 1 << 11,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-ui-valid"]
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-ui-valid
const IN_MOZ_UI_VALID_STATE = 1 << 12,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-broken"]
const IN_BROKEN_STATE = 1 << 13,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-user-disabled"]
const IN_USER_DISABLED_STATE = 1 << 14,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-suppressed"]
const IN_SUPPRESSED_STATE = 1 << 15,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-loading"]
const IN_LOADING_STATE = 1 << 16,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-blocked"]
const IN_HANDLER_BLOCKED_STATE = 1 << 17,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-disabled"]
const IN_HANDLER_DISABLED_STATE = 1 << 18,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-crashed"]
const IN_HANDLER_CRASHED_STATE = 1 << 19,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-required"]
const IN_REQUIRED_STATE = 1 << 20,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-optional"]
const IN_OPTIONAL_STATE = 1 << 21,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-read-write"]
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-ui-invalid
const IN_MOZ_UI_INVALID_STATE = 1 << 13,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-broken
const IN_BROKEN_STATE = 1 << 14,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-user-disabled
const IN_USER_DISABLED_STATE = 1 << 15,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-suppressed
const IN_SUPPRESSED_STATE = 1 << 16,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-loading
const IN_LOADING_STATE = 1 << 18,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-blocked
const IN_HANDLER_BLOCKED_STATE = 1 << 18,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-disabled
const IN_HANDLER_DISABLED_STATE = 1 << 19,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-crashed
const IN_HANDLER_CRASHED_STATE = 1 << 20,
/// https://html.spec.whatwg.org/multipage/#selector-required
const IN_REQUIRED_STATE = 1 << 21,
/// https://html.spec.whatwg.org/multipage/#selector-optional
const IN_OPTIONAL_STATE = 1 << 22,
/// https://html.spec.whatwg.org/multipage/#selector-read-write
const IN_READ_WRITE_STATE = 1 << 22,
/// Non-standard: Older custom-elements spec.
const IN_UNRESOLVED_STATE = 1 << 23,
/// https://html.spec.whatwg.org/multipage/#selector-visited
const IN_VISITED_STATE = 1 << 24,
/// https://html.spec.whatwg.org/multipage/#selector-link
const IN_UNVISITED_STATE = 1 << 25,
/// https://drafts.csswg.org/selectors-4/#the-any-link-pseudo
const IN_VISITED_OR_UNVISITED_STATE = IN_VISITED_STATE.bits | IN_UNVISITED_STATE.bits,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-drag-over
const IN_DRAGOVER_STATE = 1 << 26,
/// https://html.spec.whatwg.org/multipage/#selector-in-range
const IN_INRANGE_STATE = 1 << 27,
/// https://html.spec.whatwg.org/multipage/#selector-out-of-range
const IN_OUTOFRANGE_STATE = 1 << 28,
/// https://html.spec.whatwg.org/multipage/#selector-read-only
const IN_MOZ_READONLY_STATE = 1 << 29,
/// https://html.spec.whatwg.org/multipage/#selector-read-write
const IN_MOZ_READWRITE_STATE = 1 << 30,
/// https://html.spec.whatwg.org/multipage/#selector-default
const IN_DEFAULT_STATE = 1 << 31,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-submit-invalid
const IN_MOZ_SUBMITINVALID_STATE = 1 << 32,
/// Non-standard & undocumented.
const IN_OPTIMUM_STATE = 1 << 33,
/// Non-standard & undocumented.
const IN_SUB_OPTIMUM_STATE = 1 << 34,
/// Non-standard & undocumented.
const IN_SUB_SUB_OPTIMUM_STATE = 1 << 35,
/// Non-standard & undocumented.
const IN_DEVTOOLS_HIGHLIGHTED_STATE = 1 << 36,
/// Non-standard & undocumented.
const IN_STYLEEDITOR_TRANSITIONING_STATE = 1 << 37,
/// Non-standard & undocumented.
const IN_INCREMENT_SCRIPT_LEVEL_STATE = 1 << 38,
/// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-focusring
const IN_FOCUSRING_STATE = 1 << 39,
/// Non-standard & undocumented.
const IN_HANDLER_CLICK_TO_PLAY_STATE = 1 << 40,
/// Non-standard & undocumented.
const IN_HANDLER_VULNERABLE_UPDATABLE_STATE = 1 << 41,
/// Non-standard & undocumented.
const IN_HANDLER_VULNERABLE_NO_UPDATE_STATE = 1 << 42,
/// https://drafts.csswg.org/selectors-4/#the-focus-within-pseudo
const IN_FOCUS_WITHIN_STATE = 1 << 43,
}
}
84 changes: 60 additions & 24 deletions components/style/gecko/non_ts_pseudo_class_list.rs
Expand Up @@ -23,6 +23,20 @@
* The string variables will be applied to pseudoclasses that are of the form
* of a function with a string argument.
*
* Pending pseudo-classes:
*
* :-moz-is-html -> Used only in UA sheets, should be easy to support.
* :-moz-native-anonymous -> For devtools, seems easy-ish?
* :-moz-bound-element -> Seems unused, should be easy to remove.
*
* :-moz-lwtheme, :-moz-lwtheme-brighttext, :-moz-lwtheme-darktext,
* :-moz-window-inactive.
*
* :scope -> <style scoped>, pending discussion.
*
* This follows the order defined in layout/style/nsCSSPseudoClassList.h when
* possible.
*
* $gecko_type can be either "_" or an ident in Gecko's CSSPseudoClassType.
* $state can be either "_" or an expression of type ElementState.
* $flags can be either "_" or an expression of type NonTSPseudoClassFlag,
Expand All @@ -33,43 +47,65 @@ macro_rules! apply_non_ts_list {
($apply_macro:ident) => {
$apply_macro! {
bare: [
("any-link", AnyLink, anyLink, _, _),
("link", Link, link, _, _),
("visited", Visited, visited, _, _),
("unresolved", Unresolved, unresolved, IN_UNRESOLVED_STATE, _),
("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_INTERNAL),
("-moz-browser-frame", MozBrowserFrame, mozBrowserFrame, _, PSEUDO_CLASS_INTERNAL),
("link", Link, link, IN_UNVISITED_STATE, _),
("any-link", AnyLink, anyLink, IN_VISITED_OR_UNVISITED_STATE, _),
("visited", Visited, visited, IN_VISITED_STATE, _),
("active", Active, active, IN_ACTIVE_STATE, _),
("checked", Checked, checked, IN_CHECKED_STATE, _),
("disabled", Disabled, disabled, IN_DISABLED_STATE, _),
("enabled", Enabled, enabled, IN_ENABLED_STATE, _),
("focus", Focus, focus, IN_FOCUS_STATE, _),
("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, _),
("focus-within", FocusWithin, focusWithin, IN_FOCUS_WITHIN_STATE, _),
("hover", Hover, hover, IN_HOVER_STATE, _),
("enabled", Enabled, enabled, IN_ENABLED_STATE, _),
("disabled", Disabled, disabled, IN_DISABLED_STATE, _),
("checked", Checked, checked, IN_CHECKED_STATE, _),
("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _),
("placeholder-shown", PlaceholderShown, placeholderShown, IN_PLACEHOLDER_SHOWN_STATE, _),
("-moz-drag-over", MozDragOver, mozDragOver, IN_DRAGOVER_STATE, _),
("target", Target, target, IN_TARGET_STATE, _),
("valid", Valid, valid, IN_VALID_STATE, _),
("invalid", Invalid, invalid, IN_INVALID_STATE, _),
("-moz-ui-valid", MozUIValid, mozUIValid, IN_MOZ_UI_VALID_STATE, _),
("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _),
("-moz-devtools-highlighted", MozDevtoolsHighlighted, mozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, _),
("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, mozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, _),
// TODO(emilio): Needs pref check for
// full-screen-api.unprefix.enabled!
("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, _),
// TODO(emilio): This is inconsistently named (the capital R).
("-moz-focusring", MozFocusRing, mozFocusRing, IN_FOCUSRING_STATE, _),
("-moz-broken", MozBroken, mozBroken, IN_BROKEN_STATE, _),
("-moz-user-disabled", MozUserDisabled, mozUserDisabled, IN_USER_DISABLED_STATE, PSEUDO_CLASS_INTERNAL),
("-moz-suppressed", MozSuppressed, mozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_INTERNAL),
("-moz-loading", MozLoading, mozLoading, IN_LOADING_STATE, _),
("-moz-handler-blocked", MozHandlerBlocked, mozHandlerBlocked, IN_HANDLER_BLOCKED_STATE,
PSEUDO_CLASS_INTERNAL),
("-moz-handler-disabled", MozHandlerDisabled, mozHandlerDisabled, IN_HANDLER_DISABLED_STATE,
PSEUDO_CLASS_INTERNAL),
("-moz-handler-crashed", MozHandlerCrashed, mozHandlerCrashed, IN_HANDLER_CRASHED_STATE,
PSEUDO_CLASS_INTERNAL),
("-moz-suppressed", MozSuppressed, mozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_INTERNAL),

("-moz-handler-clicktoplay", MozHandlerClickToPlay, mozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_INTERNAL),
("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, mozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_INTERNAL),
("-moz-handler-vulnerable-no-update", MozHandlerVulnerableNoUpdate, mozHandlerVulnerableNoUpdate, IN_HANDLER_VULNERABLE_NO_UPDATE_STATE, PSEUDO_CLASS_INTERNAL),

("-moz-handler-disabled", MozHandlerDisabled, mozHandlerDisabled, IN_HANDLER_DISABLED_STATE, PSEUDO_CLASS_INTERNAL),
("-moz-handler-blocked", MozHandlerBlocked, mozHandlerBlocked, IN_HANDLER_BLOCKED_STATE, PSEUDO_CLASS_INTERNAL),
("-moz-handler-crashed", MozHandlerCrashed, mozHandlerCrashed, IN_HANDLER_CRASHED_STATE, PSEUDO_CLASS_INTERNAL),
("-moz-math-increment-script-level", MozMathIncrementScriptLevel, mozMathIncrementScriptLevel, IN_INCREMENT_SCRIPT_LEVEL_STATE, _),

("required", Required, required, IN_REQUIRED_STATE, _),
("optional", Optional, optional, IN_OPTIONAL_STATE, _),
("read-write", ReadWrite, _, IN_READ_WRITE_STATE, _),
("read-only", ReadOnly, _, IN_READ_WRITE_STATE, _),
("valid", Valid, valid, IN_VALID_STATE, _),
("invalid", Invalid, invalid, IN_INVALID_STATE, _),
("in-range", InRange, inRange, IN_INRANGE_STATE, _),
("out-of-range", OutOfRange, outOfRange, IN_OUTOFRANGE_STATE, _),
("default", Default, defaultPseudo, IN_DEFAULT_STATE, _),
("placeholder-shown", PlaceholderShown, placeholderShown, IN_PLACEHOLDER_SHOWN_STATE, _),
("-moz-read-only", MozReadOnly, mozReadOnly, IN_MOZ_READONLY_STATE, _),
("-moz-read-write", MozReadWrite, mozReadWrite, IN_MOZ_READWRITE_STATE, _),
("-moz-submit-invalid", MozSubmitInvalid, mozSubmitInvalid, IN_MOZ_SUBMITINVALID_STATE, _),
("-moz-ui-valid", MozUIValid, mozUIValid, IN_MOZ_UI_VALID_STATE, _),
("-moz-ui-invalid", MozUIInvalid, mozUIInvalid, IN_MOZ_UI_INVALID_STATE, _),
("-moz-meter-optimum", MozMeterOptimum, mozMeterOptimum, IN_OPTIMUM_STATE, _),
("-moz-meter-sub-optimum", MozMeterSubOptimum, mozMeterSubOptimum, IN_SUB_OPTIMUM_STATE, _),
("-moz-meter-sub-sub-optimum", MozMeterSubSubOptimum, mozMeterSubSubOptimum, IN_SUB_SUB_OPTIMUM_STATE, _),

("-moz-user-disabled", MozUserDisabled, mozUserDisabled, IN_USER_DISABLED_STATE, PSEUDO_CLASS_INTERNAL),

("-moz-first-node", MozFirstNode, firstNode, _, _),
("-moz-last-node", MozLastNode, lastNode, _, _),
("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _),

("-moz-browser-frame", MozBrowserFrame, mozBrowserFrame, _, PSEUDO_CLASS_INTERNAL),
("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_INTERNAL),
],
string: [
("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL),
Expand Down
2 changes: 1 addition & 1 deletion components/style/gecko/snapshot.rs
Expand Up @@ -138,7 +138,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
impl ElementSnapshot for GeckoElementSnapshot {
fn state(&self) -> Option<ElementState> {
if self.has_any(Flags::State) {
Some(ElementState::from_bits_truncate(unsafe { (*self.0).mState as u32 }))
Some(ElementState::from_bits_truncate(unsafe { (*self.0).mState }))
} else {
None
}
Expand Down

0 comments on commit a6277d5

Please sign in to comment.