author | Boris Zbarsky <bzbarsky@mit.edu> |
Mon, 15 May 2017 11:40:40 -0500 | |
changeset 358476 | b733db3d681b1f9dd3e72773188ec565d0beaeb8 |
parent 358475 | ddd4f6f93fabc7f90771a53f93f9444acc7534f3 |
child 358477 | 78c489199cd822bab5764654db7a6585af4bde3b |
push id | 31827 |
push user | cbook@mozilla.com |
push date | Tue, 16 May 2017 10:34:19 +0000 |
treeherder | mozilla-central@49365d675cbb [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | emilio |
milestone | 55.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
servo/components/style/element_state.rs | file | annotate | diff | comparison | revisions | |
servo/components/style/restyle_hints.rs | file | annotate | diff | comparison | revisions |
--- a/servo/components/style/element_state.rs +++ b/servo/components/style/element_state.rs @@ -110,14 +110,19 @@ bitflags! { /// 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, + /// :dir matching; the states are used for dynamic change detection. + /// State that elements that match :dir(ltr) are in. + const IN_LTR_STATE = 1 << 44, + /// State that elements that match :dir(rtl) are in. + const IN_RTL_STATE = 1 << 45, /// Non-standard & undocumented. const IN_AUTOFILL_STATE = 1 << 50, /// Non-standard & undocumented. const IN_AUTOFILL_PREVIEW_STATE = 1 << 51, } }
--- a/servo/components/style/restyle_hints.rs +++ b/servo/components/style/restyle_hints.rs @@ -309,16 +309,32 @@ impl<'a, E> MatchAttr for ElementWrapper match self.snapshot() { Some(snapshot) if snapshot.has_attrs() => snapshot.match_attr_suffix(attr, value), _ => self.element.match_attr_suffix(attr, value) } } } +#[cfg(feature = "gecko")] +fn dir_selector_to_state(s: &[u16]) -> ElementState { + // Jump through some hoops to deal with our Box<[u16]> thing. + const LTR: [u16; 4] = [b'l' as u16, b't' as u16, b'r' as u16, 0]; + const RTL: [u16; 4] = [b'r' as u16, b't' as u16, b'l' as u16, 0]; + if LTR == *s { + IN_LTR_STATE + } else if RTL == *s { + IN_RTL_STATE + } else { + // :dir(something-random) is a valid selector, but shouldn't + // match anything. + ElementState::empty() + } +} + impl<'a, E> Element for ElementWrapper<'a, E> where E: TElement, { fn match_non_ts_pseudo_class<F>(&self, pseudo_class: &NonTSPseudoClass, relations: &mut StyleRelations, _setter: &mut F) -> bool @@ -331,16 +347,41 @@ impl<'a, E> Element for ElementWrapper<' use selectors::matching::matches_complex_selector; if let NonTSPseudoClass::MozAny(ref selectors) = *pseudo_class { return selectors.iter().any(|s| { matches_complex_selector(s, self, relations, _setter) }) } } + // :dir needs special handling. It's implemented in terms of state + // flags, but which state flag it maps to depends on the argument to + // :dir. That means we can't just add its state flags to the + // NonTSPseudoClass, because if we added all of them there, and tested + // via intersects() here, we'd get incorrect behavior for :not(:dir()) + // cases. + // + // FIXME(bz): How can I set this up so once Servo adds :dir() support we + // don't forget to update this code? + #[cfg(feature = "gecko")] + { + if let NonTSPseudoClass::Dir(ref s) = *pseudo_class { + let selector_flag = dir_selector_to_state(s); + if selector_flag.is_empty() { + // :dir() with some random argument; does not match. + return false; + } + let state = match self.snapshot().and_then(|s| s.state()) { + Some(snapshot_state) => snapshot_state, + None => self.element.get_state(), + }; + return state.contains(selector_flag); + } + } + let flag = pseudo_class.state_flag(); if flag.is_empty() { return self.element.match_non_ts_pseudo_class(pseudo_class, relations, &mut |_, _| {}) } match self.snapshot().and_then(|s| s.state()) { Some(snapshot_state) => snapshot_state.intersects(flag), @@ -420,16 +461,20 @@ impl<'a, E> Element for ElementWrapper<' => snapshot.each_class(callback), _ => self.element.each_class(callback) } } } fn selector_to_state(sel: &Component<SelectorImpl>) -> ElementState { match *sel { + // FIXME(bz): How can I set this up so once Servo adds :dir() support we + // don't forget to update this code? + #[cfg(feature = "gecko")] + Component::NonTSPseudoClass(NonTSPseudoClass::Dir(ref s)) => dir_selector_to_state(s), Component::NonTSPseudoClass(ref pc) => pc.state_flag(), _ => ElementState::empty(), } } fn is_attr_selector(sel: &Component<SelectorImpl>) -> bool { match *sel { Component::ID(_) |