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.
#![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,
}
}

View file

@ -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,
@ -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, _),
("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, _),
("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _),
("placeholder-shown", PlaceholderShown, placeholderShown, IN_PLACEHOLDER_SHOWN_STATE, _),
("disabled", Disabled, disabled, IN_DISABLED_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, _),
("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),

View file

@ -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
}

View file

@ -27,8 +27,7 @@ use gecko::snapshot_helpers;
use gecko_bindings::bindings;
use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
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_IsUnvisitedLink, Gecko_IsVisitedLink, Gecko_Namespace};
use gecko_bindings::bindings::{Gecko_IsRootElement, Gecko_MatchesElement, Gecko_Namespace};
use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_ElementHasAnimations;
@ -465,7 +464,7 @@ impl<'le> TElement for GeckoElement<'le> {
fn get_state(&self) -> ElementState {
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::*;
match *pseudo_class {
// https://github.com/servo/servo/issues/8718
NonTSPseudoClass::AnyLink => unsafe { Gecko_IsLink(self.0) },
NonTSPseudoClass::Link => unsafe { Gecko_IsUnvisitedLink(self.0) },
NonTSPseudoClass::Visited => unsafe { Gecko_IsVisitedLink(self.0) },
NonTSPseudoClass::AnyLink |
NonTSPseudoClass::Link |
NonTSPseudoClass::Visited |
NonTSPseudoClass::Active |
NonTSPseudoClass::Focus |
NonTSPseudoClass::Hover |
NonTSPseudoClass::Enabled |
NonTSPseudoClass::Disabled |
NonTSPseudoClass::Checked |
NonTSPseudoClass::ReadWrite |
NonTSPseudoClass::Fullscreen |
NonTSPseudoClass::Indeterminate |
NonTSPseudoClass::PlaceholderShown |
@ -731,12 +728,31 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::MozHandlerDisabled |
NonTSPseudoClass::MozHandlerCrashed |
NonTSPseudoClass::Required |
NonTSPseudoClass::Optional => {
self.get_state().contains(pseudo_class.state_flag())
NonTSPseudoClass::Optional |
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 => {
flags_setter(self, HAS_EDGE_CHILD_SELECTOR);
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)
%>
<%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)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
use properties::longhands::${ident}::computed_value::T as Keyword;
@ -262,6 +262,9 @@ def set_gecko_property(ffi_name, expr):
% endfor
};
${set_gecko_property(gecko_ffi_name, "result")}
% if on_set:
self.${on_set}();
% endif
}
</%def>
@ -431,17 +434,39 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
}
</%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)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
% if round_to_pixels:
let au_per_device_px = Au(self.gecko.mTwipsPerPixel);
self.gecko.${gecko_ffi_name} = round_border_to_device_pixels(v, au_per_device_px).0;
let value = {
% if round_to_pixels:
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:
self.gecko.${gecko_ffi_name} = v.0;
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
% endif
}
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
%if need_clone:
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
@ -794,12 +819,48 @@ fn static_assert() {
skip_additionals="*">
% 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) %>
// 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_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) %>
pub fn border_${side.ident}_has_nonzero_width(&self) -> bool {
@ -1130,7 +1191,8 @@ fn static_assert() {
#[allow(non_snake_case)]
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 {
% for value in border_style_keyword.values_for('gecko'):
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")},
};
${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)]
@ -1161,8 +1228,9 @@ fn static_assert() {
}
}
<% impl_app_units("outline_width", "mActualOutlineWidth", need_clone=True,
round_to_pixels=True) %>
<% impl_app_units("outline_width", "mActualOutlineWidth",
inherit_from="mOutlineWidth",
need_clone=True, round_to_pixels=True) %>
% for corner in CORNERS:
<% 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)
.and_then(|result| {
if let Either::Second(BorderStyle::hidden) = result {
// The outline-style property accepts the same values as border-style,
// except that 'hidden' is not a legal outline style.
// The outline-style property accepts the same values as
// border-style, except that 'hidden' is not a legal outline
// style.
Err(())
} else {
Ok(result)

View file

@ -34,6 +34,8 @@ num = []
packages = []
# Files that are ignored for all tidy and lint checks.
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
"./components/style/gecko_bindings/bindings.rs",
"./components/style/gecko_bindings/structs_debug.rs",

View file

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