Auto merge of #16177 - emilio:stylo-pseudo-classes, r=heycam,jdm

Bug 1350140: stylo: Implement all the remaining state pseudo-classes.

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16177)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-03-29 08:48:12 -05:00 committed by GitHub
commit 1d98e3406a
8 changed files with 275 additions and 100 deletions

View file

@ -4,64 +4,116 @@
//! States elements can be in. //! States elements can be in.
#![deny(missing_docs)]
bitflags! { 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))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub flags ElementState: u32 { pub flags ElementState: u64 {
#[doc = "The mouse is down on this element. \ /// The mouse is down on this element.
https://html.spec.whatwg.org/multipage/#selector-active \ /// https://html.spec.whatwg.org/multipage/#selector-active
FIXME(#7333): set/unset this when appropriate"] /// FIXME(#7333): set/unset this when appropriate
const IN_ACTIVE_STATE = 1 << 0, const IN_ACTIVE_STATE = 1 << 0,
#[doc = "This element has focus. \ /// This element has focus.
https://html.spec.whatwg.org/multipage/#selector-focus"] /// https://html.spec.whatwg.org/multipage/#selector-focus
const IN_FOCUS_STATE = 1 << 1, const IN_FOCUS_STATE = 1 << 1,
#[doc = "The mouse is hovering over this element. \ /// The mouse is hovering over this element.
https://html.spec.whatwg.org/multipage/#selector-hover"] /// https://html.spec.whatwg.org/multipage/#selector-hover
const IN_HOVER_STATE = 1 << 2, const IN_HOVER_STATE = 1 << 2,
#[doc = "Content is enabled (and can be disabled). \ /// Content is enabled (and can be disabled).
http://www.whatwg.org/html/#selector-enabled"] /// http://www.whatwg.org/html/#selector-enabled
const IN_ENABLED_STATE = 1 << 3, const IN_ENABLED_STATE = 1 << 3,
#[doc = "Content is disabled. \ /// Content is disabled.
http://www.whatwg.org/html/#selector-disabled"] /// http://www.whatwg.org/html/#selector-disabled
const IN_DISABLED_STATE = 1 << 4, const IN_DISABLED_STATE = 1 << 4,
#[doc = "Content is checked. \ /// Content is checked.
https://html.spec.whatwg.org/multipage/#selector-checked"] /// https://html.spec.whatwg.org/multipage/#selector-checked
const IN_CHECKED_STATE = 1 << 5, 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, 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, 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, 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, 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, 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, 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, const IN_MOZ_UI_VALID_STATE = 1 << 12,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-broken"] /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-ui-invalid
const IN_BROKEN_STATE = 1 << 13, const IN_MOZ_UI_INVALID_STATE = 1 << 13,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-user-disabled"] /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-broken
const IN_USER_DISABLED_STATE = 1 << 14, const IN_BROKEN_STATE = 1 << 14,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-suppressed"] /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-user-disabled
const IN_SUPPRESSED_STATE = 1 << 15, const IN_USER_DISABLED_STATE = 1 << 15,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-loading"] /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-suppressed
const IN_LOADING_STATE = 1 << 16, const IN_SUPPRESSED_STATE = 1 << 16,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-blocked"] /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-loading
const IN_HANDLER_BLOCKED_STATE = 1 << 17, const IN_LOADING_STATE = 1 << 18,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-disabled"] /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-blocked
const IN_HANDLER_DISABLED_STATE = 1 << 18, const IN_HANDLER_BLOCKED_STATE = 1 << 18,
#[doc = "Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-crashed"] /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-disabled
const IN_HANDLER_CRASHED_STATE = 1 << 19, const IN_HANDLER_DISABLED_STATE = 1 << 19,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-required"] /// Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-handler-crashed
const IN_REQUIRED_STATE = 1 << 20, const IN_HANDLER_CRASHED_STATE = 1 << 20,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-optional"] /// https://html.spec.whatwg.org/multipage/#selector-required
const IN_OPTIONAL_STATE = 1 << 21, const IN_REQUIRED_STATE = 1 << 21,
#[doc = "https://html.spec.whatwg.org/multipage/#selector-read-write"] /// 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, 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,
} }
} }

View file

@ -23,6 +23,20 @@
* The string variables will be applied to pseudoclasses that are of the form * The string variables will be applied to pseudoclasses that are of the form
* of a function with a string argument. * 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. * $gecko_type can be either "_" or an ident in Gecko's CSSPseudoClassType.
* $state can be either "_" or an expression of type ElementState. * $state can be either "_" or an expression of type ElementState.
* $flags can be either "_" or an expression of type NonTSPseudoClassFlag, * $flags can be either "_" or an expression of type NonTSPseudoClassFlag,
@ -33,43 +47,65 @@ macro_rules! apply_non_ts_list {
($apply_macro:ident) => { ($apply_macro:ident) => {
$apply_macro! { $apply_macro! {
bare: [ bare: [
("any-link", AnyLink, anyLink, _, _), ("unresolved", Unresolved, unresolved, IN_UNRESOLVED_STATE, _),
("link", Link, link, _, _), ("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_INTERNAL),
("visited", Visited, visited, _, _), ("-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, _), ("active", Active, active, IN_ACTIVE_STATE, _),
("focus", Focus, focus, IN_FOCUS_STATE, _),
("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_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, _), ("checked", Checked, checked, IN_CHECKED_STATE, _),
("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _), ("disabled", Disabled, disabled, IN_DISABLED_STATE, _),
("placeholder-shown", PlaceholderShown, placeholderShown, IN_PLACEHOLDER_SHOWN_STATE, _), ("enabled", Enabled, enabled, IN_ENABLED_STATE, _),
("focus", Focus, focus, IN_FOCUS_STATE, _),
("focus-within", FocusWithin, focusWithin, IN_FOCUS_WITHIN_STATE, _),
("hover", Hover, hover, IN_HOVER_STATE, _),
("-moz-drag-over", MozDragOver, mozDragOver, IN_DRAGOVER_STATE, _),
("target", Target, target, IN_TARGET_STATE, _), ("target", Target, target, IN_TARGET_STATE, _),
("valid", Valid, valid, IN_VALID_STATE, _), ("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _),
("invalid", Invalid, invalid, IN_INVALID_STATE, _), ("-moz-devtools-highlighted", MozDevtoolsHighlighted, mozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, _),
("-moz-ui-valid", MozUIValid, mozUIValid, IN_MOZ_UI_VALID_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-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-loading", MozLoading, mozLoading, IN_LOADING_STATE, _),
("-moz-handler-blocked", MozHandlerBlocked, mozHandlerBlocked, IN_HANDLER_BLOCKED_STATE, ("-moz-suppressed", MozSuppressed, mozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_INTERNAL),
PSEUDO_CLASS_INTERNAL),
("-moz-handler-disabled", MozHandlerDisabled, mozHandlerDisabled, IN_HANDLER_DISABLED_STATE, ("-moz-handler-clicktoplay", MozHandlerClickToPlay, mozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_INTERNAL),
PSEUDO_CLASS_INTERNAL), ("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, mozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_INTERNAL),
("-moz-handler-crashed", MozHandlerCrashed, mozHandlerCrashed, IN_HANDLER_CRASHED_STATE, ("-moz-handler-vulnerable-no-update", MozHandlerVulnerableNoUpdate, mozHandlerVulnerableNoUpdate, IN_HANDLER_VULNERABLE_NO_UPDATE_STATE, PSEUDO_CLASS_INTERNAL),
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, _), ("required", Required, required, IN_REQUIRED_STATE, _),
("optional", Optional, optional, IN_OPTIONAL_STATE, _), ("optional", Optional, optional, IN_OPTIONAL_STATE, _),
("read-write", ReadWrite, _, IN_READ_WRITE_STATE, _), ("valid", Valid, valid, IN_VALID_STATE, _),
("read-only", ReadOnly, _, IN_READ_WRITE_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-first-node", MozFirstNode, firstNode, _, _),
("-moz-last-node", MozLastNode, lastNode, _, _), ("-moz-last-node", MozLastNode, lastNode, _, _),
("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _), ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _),
("-moz-browser-frame", MozBrowserFrame, mozBrowserFrame, _, PSEUDO_CLASS_INTERNAL),
("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_INTERNAL),
], ],
string: [ string: [
("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL), ("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL),

View file

@ -138,7 +138,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
impl ElementSnapshot for GeckoElementSnapshot { impl ElementSnapshot for GeckoElementSnapshot {
fn state(&self) -> Option<ElementState> { fn state(&self) -> Option<ElementState> {
if self.has_any(Flags::State) { 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 { } else {
None None
} }

View file

@ -27,8 +27,7 @@ use gecko::snapshot_helpers;
use gecko_bindings::bindings; use gecko_bindings::bindings;
use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator}; use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetLastChild, Gecko_GetNextStyleChild}; use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetLastChild, Gecko_GetNextStyleChild};
use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement, Gecko_MatchesElement}; use gecko_bindings::bindings::{Gecko_IsRootElement, Gecko_MatchesElement, Gecko_Namespace};
use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink, Gecko_Namespace};
use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags}; use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use gecko_bindings::bindings::Gecko_ClassOrClassList; use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_ElementHasAnimations; use gecko_bindings::bindings::Gecko_ElementHasAnimations;
@ -465,7 +464,7 @@ impl<'le> TElement for GeckoElement<'le> {
fn get_state(&self) -> ElementState { fn get_state(&self) -> ElementState {
unsafe { unsafe {
ElementState::from_bits_truncate(Gecko_ElementState(self.0) as u32) ElementState::from_bits_truncate(Gecko_ElementState(self.0))
} }
} }
@ -705,17 +704,15 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
{ {
use selectors::matching::*; use selectors::matching::*;
match *pseudo_class { match *pseudo_class {
// https://github.com/servo/servo/issues/8718 NonTSPseudoClass::AnyLink |
NonTSPseudoClass::AnyLink => unsafe { Gecko_IsLink(self.0) }, NonTSPseudoClass::Link |
NonTSPseudoClass::Link => unsafe { Gecko_IsUnvisitedLink(self.0) }, NonTSPseudoClass::Visited |
NonTSPseudoClass::Visited => unsafe { Gecko_IsVisitedLink(self.0) },
NonTSPseudoClass::Active | NonTSPseudoClass::Active |
NonTSPseudoClass::Focus | NonTSPseudoClass::Focus |
NonTSPseudoClass::Hover | NonTSPseudoClass::Hover |
NonTSPseudoClass::Enabled | NonTSPseudoClass::Enabled |
NonTSPseudoClass::Disabled | NonTSPseudoClass::Disabled |
NonTSPseudoClass::Checked | NonTSPseudoClass::Checked |
NonTSPseudoClass::ReadWrite |
NonTSPseudoClass::Fullscreen | NonTSPseudoClass::Fullscreen |
NonTSPseudoClass::Indeterminate | NonTSPseudoClass::Indeterminate |
NonTSPseudoClass::PlaceholderShown | NonTSPseudoClass::PlaceholderShown |
@ -731,12 +728,31 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::MozHandlerDisabled | NonTSPseudoClass::MozHandlerDisabled |
NonTSPseudoClass::MozHandlerCrashed | NonTSPseudoClass::MozHandlerCrashed |
NonTSPseudoClass::Required | NonTSPseudoClass::Required |
NonTSPseudoClass::Optional => { NonTSPseudoClass::Optional |
self.get_state().contains(pseudo_class.state_flag()) NonTSPseudoClass::MozReadOnly |
NonTSPseudoClass::MozReadWrite |
NonTSPseudoClass::Unresolved |
NonTSPseudoClass::FocusWithin |
NonTSPseudoClass::MozDragOver |
NonTSPseudoClass::MozDevtoolsHighlighted |
NonTSPseudoClass::MozStyleeditorTransitioning |
NonTSPseudoClass::MozFocusRing |
NonTSPseudoClass::MozHandlerClickToPlay |
NonTSPseudoClass::MozHandlerVulnerableUpdatable |
NonTSPseudoClass::MozHandlerVulnerableNoUpdate |
NonTSPseudoClass::MozMathIncrementScriptLevel |
NonTSPseudoClass::InRange |
NonTSPseudoClass::OutOfRange |
NonTSPseudoClass::Default |
NonTSPseudoClass::MozSubmitInvalid |
NonTSPseudoClass::MozUIInvalid |
NonTSPseudoClass::MozMeterOptimum |
NonTSPseudoClass::MozMeterSubOptimum |
NonTSPseudoClass::MozMeterSubSubOptimum => {
// NB: It's important to use `intersect` instead of `contains`
// here, to handle `:any-link` correctly.
self.get_state().intersects(pseudo_class.state_flag())
}, },
NonTSPseudoClass::ReadOnly => {
!self.get_state().contains(pseudo_class.state_flag())
}
NonTSPseudoClass::MozFirstNode => { NonTSPseudoClass::MozFirstNode => {
flags_setter(self, HAS_EDGE_CHILD_SELECTOR); flags_setter(self, HAS_EDGE_CHILD_SELECTOR);
let mut elem = self.as_node(); let mut elem = self.as_node();

View file

@ -250,7 +250,7 @@ def set_gecko_property(ffi_name, expr):
return "self.gecko.%s = %s;" % (ffi_name, expr) return "self.gecko.%s = %s;" % (ffi_name, expr)
%> %>
<%def name="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type='u8')"> <%def name="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type='u8', on_set=None)">
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
use properties::longhands::${ident}::computed_value::T as Keyword; use properties::longhands::${ident}::computed_value::T as Keyword;
@ -262,6 +262,9 @@ def set_gecko_property(ffi_name, expr):
% endfor % endfor
}; };
${set_gecko_property(gecko_ffi_name, "result")} ${set_gecko_property(gecko_ffi_name, "result")}
% if on_set:
self.${on_set}();
% endif
} }
</%def> </%def>
@ -431,17 +434,39 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
} }
</%def> </%def>
<%def name="impl_app_units(ident, gecko_ffi_name, need_clone, round_to_pixels=False)"> <%def name="impl_app_units(ident, gecko_ffi_name, need_clone, inherit_from=None, round_to_pixels=False)">
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
% if round_to_pixels: let value = {
let au_per_device_px = Au(self.gecko.mTwipsPerPixel); % if round_to_pixels:
self.gecko.${gecko_ffi_name} = round_border_to_device_pixels(v, au_per_device_px).0; let au_per_device_px = Au(self.gecko.mTwipsPerPixel);
round_border_to_device_pixels(v, au_per_device_px).0
% else:
v.0
% endif
};
% if inherit_from:
self.gecko.${inherit_from} = value;
% endif
self.gecko.${gecko_ffi_name} = value;
}
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
% if inherit_from:
self.gecko.${inherit_from} = other.gecko.${inherit_from};
// NOTE: This is needed to easily handle the `unset` and `initial`
// keywords, which are implemented calling this function.
//
// In practice, this means that we may have an incorrect value here, but
// we'll adjust that properly in the style fixup phase.
self.gecko.${gecko_ffi_name} = other.gecko.${inherit_from};
% else: % else:
self.gecko.${gecko_ffi_name} = v.0; self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
% endif % endif
} }
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
%if need_clone: %if need_clone:
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
@ -794,12 +819,48 @@ fn static_assert() {
skip_additionals="*"> skip_additionals="*">
% for side in SIDES: % for side in SIDES:
<% impl_keyword("border_%s_style" % side.ident, "mBorderStyle[%s]" % side.index, border_style_keyword, <% impl_keyword("border_%s_style" % side.ident,
"mBorderStyle[%s]" % side.index,
border_style_keyword,
on_set="update_border_%s" % side.ident,
need_clone=True) %> need_clone=True) %>
// This is needed because the initial mComputedBorder value is set to zero.
//
// In order to compute stuff, we start from the initial struct, and keep
// going down the tree applying properties.
//
// That means, effectively, that when we set border-style to something
// non-hidden, we should use the initial border instead.
//
// Servo stores the initial border-width in the initial struct, and then
// adjusts as needed in the fixup phase. This means that the initial struct
// is technically not valid without fixups, and that you lose pretty much
// any sharing of the initial struct, which is kind of unfortunate.
//
// Gecko has two fields for this, one that stores the "specified" border,
// and other that stores the actual computed one. That means that when we
// set border-style, border-width may change and we need to sync back to the
// specified one. This is what this function does.
//
// Note that this doesn't impose any dependency in the order of computation
// of the properties. This is only relevant if border-style is specified,
// but border-width isn't. If border-width is specified at some point, the
// two mBorder and mComputedBorder fields would be the same already.
//
// Once we're here, we know that we'll run style fixups, so it's fine to
// just copy the specified border here, we'll adjust it if it's incorrect
// later.
fn update_border_${side.ident}(&mut self) {
self.gecko.mComputedBorder.${side.ident} = self.gecko.mBorder.${side.ident};
}
<% impl_color("border_%s_color" % side.ident, "(mBorderColor)[%s]" % side.index, need_clone=True) %> <% impl_color("border_%s_color" % side.ident, "(mBorderColor)[%s]" % side.index, need_clone=True) %>
<% impl_app_units("border_%s_width" % side.ident, "mComputedBorder.%s" % side.ident, need_clone=True, <% impl_app_units("border_%s_width" % side.ident,
"mComputedBorder.%s" % side.ident,
inherit_from="mBorder.%s" % side.ident,
need_clone=True,
round_to_pixels=True) %> round_to_pixels=True) %>
pub fn border_${side.ident}_has_nonzero_width(&self) -> bool { pub fn border_${side.ident}_has_nonzero_width(&self) -> bool {
@ -1130,7 +1191,8 @@ fn static_assert() {
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn set_outline_style(&mut self, v: longhands::outline_style::computed_value::T) { pub fn set_outline_style(&mut self, v: longhands::outline_style::computed_value::T) {
// FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts // FIXME(bholley): Align binary representations and ditch |match| for
// cast + static_asserts
let result = match v { let result = match v {
% for value in border_style_keyword.values_for('gecko'): % for value in border_style_keyword.values_for('gecko'):
Either::Second(border_style::T::${to_rust_ident(value)}) => Either::Second(border_style::T::${to_rust_ident(value)}) =>
@ -1140,6 +1202,11 @@ fn static_assert() {
structs::${border_style_keyword.gecko_constant('auto')} ${border_style_keyword.maybe_cast("u8")}, structs::${border_style_keyword.gecko_constant('auto')} ${border_style_keyword.maybe_cast("u8")},
}; };
${set_gecko_property("mOutlineStyle", "result")} ${set_gecko_property("mOutlineStyle", "result")}
// NB: This is needed to correctly handling the initial value of
// outline-width when outline-style changes, see the
// update_border_${side} comment for more details.
self.gecko.mActualOutlineWidth = self.gecko.mOutlineWidth;
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@ -1161,8 +1228,9 @@ fn static_assert() {
} }
} }
<% impl_app_units("outline_width", "mActualOutlineWidth", need_clone=True, <% impl_app_units("outline_width", "mActualOutlineWidth",
round_to_pixels=True) %> inherit_from="mOutlineWidth",
need_clone=True, round_to_pixels=True) %>
% for corner in CORNERS: % for corner in CORNERS:
<% impl_corner_style_coord("_moz_outline_radius_%s" % corner.ident.replace("_", ""), <% impl_corner_style_coord("_moz_outline_radius_%s" % corner.ident.replace("_", ""),

View file

@ -53,8 +53,9 @@ ${helpers.predefined_type("outline-color", "CSSColor", "computed::CSSColor::Curr
SpecifiedValue::parse(context, input) SpecifiedValue::parse(context, input)
.and_then(|result| { .and_then(|result| {
if let Either::Second(BorderStyle::hidden) = result { if let Either::Second(BorderStyle::hidden) = result {
// The outline-style property accepts the same values as border-style, // The outline-style property accepts the same values as
// except that 'hidden' is not a legal outline style. // border-style, except that 'hidden' is not a legal outline
// style.
Err(()) Err(())
} else { } else {
Ok(result) Ok(result)

View file

@ -34,6 +34,8 @@ num = []
packages = [] packages = []
# Files that are ignored for all tidy and lint checks. # Files that are ignored for all tidy and lint checks.
files = [ files = [
# Helper macro where actually a pseudo-element per line makes sense.
"./components/style/gecko/non_ts_pseudo_class_list.rs",
# Generated and upstream code combined with our own. Could use cleanup # Generated and upstream code combined with our own. Could use cleanup
"./components/style/gecko_bindings/bindings.rs", "./components/style/gecko_bindings/bindings.rs",
"./components/style/gecko_bindings/structs_debug.rs", "./components/style/gecko_bindings/structs_debug.rs",

View file

@ -31,10 +31,10 @@ macro_rules! sizeof_checker (
// Update the sizes here // Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 40); sizeof_checker!(size_event_target, EventTarget, 40);
sizeof_checker!(size_node, Node, 152); sizeof_checker!(size_node, Node, 152);
sizeof_checker!(size_element, Element, 312); sizeof_checker!(size_element, Element, 320);
sizeof_checker!(size_htmlelement, HTMLElement, 328); sizeof_checker!(size_htmlelement, HTMLElement, 336);
sizeof_checker!(size_div, HTMLDivElement, 328); sizeof_checker!(size_div, HTMLDivElement, 336);
sizeof_checker!(size_span, HTMLSpanElement, 328); sizeof_checker!(size_span, HTMLSpanElement, 336);
sizeof_checker!(size_text, Text, 184); sizeof_checker!(size_text, Text, 184);
sizeof_checker!(size_characterdata, CharacterData, 184); sizeof_checker!(size_characterdata, CharacterData, 184);
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16); sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);