aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-05-15 11:40:40 -0500
committerGitHub <noreply@github.com>2017-05-15 11:40:40 -0500
commitff5f90386b88eb08b483c56004f59ac2ab3df7ca (patch)
treef5471cc29338aaa22412d3b9762ac3b8b53f44fe
parentf3c8f7e0d0fb42f32e3699d07fc0f8002bf564c8 (diff)
parentcd29916c99831d785f2a162e29e46d7a9bfc891a (diff)
downloadservo-ff5f90386b88eb08b483c56004f59ac2ab3df7ca.tar.gz
servo-ff5f90386b88eb08b483c56004f59ac2ab3df7ca.zip
Auto merge of #16873 - bzbarsky:fix-dir-matching, r=emilio
Fix dynamic updates when :dir matching changes in stylo. This is the servo part of https://bugzilla.mozilla.org/show_bug.cgi?id=1364280 <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix https://bugzilla.mozilla.org/show_bug.cgi?id=1364280 <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because Gecko has lots of tests for this and this is Gecko-only. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- 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/16873) <!-- Reviewable:end -->
-rw-r--r--components/style/element_state.rs5
-rw-r--r--components/style/restyle_hints.rs45
2 files changed, 50 insertions, 0 deletions
diff --git a/components/style/element_state.rs b/components/style/element_state.rs
index 30e67060f3f..809f01218b0 100644
--- a/components/style/element_state.rs
+++ b/components/style/element_state.rs
@@ -115,6 +115,11 @@ bitflags! {
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.
diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs
index 539ddb41561..8a2bd9c3af6 100644
--- a/components/style/restyle_hints.rs
+++ b/components/style/restyle_hints.rs
@@ -314,6 +314,22 @@ impl<'a, E> MatchAttr for ElementWrapper<'a, E>
}
}
+#[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,
{
@@ -336,6 +352,31 @@ impl<'a, E> Element for ElementWrapper<'a, E>
}
}
+ // :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,
@@ -425,6 +466,10 @@ impl<'a, E> Element for ElementWrapper<'a, E>
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(),
}