aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/restyle_hints.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/style/restyle_hints.rs')
-rw-r--r--components/style/restyle_hints.rs117
1 files changed, 69 insertions, 48 deletions
diff --git a/components/style/restyle_hints.rs b/components/style/restyle_hints.rs
index c517a6f1a7b..cd9957322e4 100644
--- a/components/style/restyle_hints.rs
+++ b/components/style/restyle_hints.rs
@@ -7,9 +7,9 @@
use attr::{AttrIdentifier, AttrValue};
use element_state::*;
use selector_impl::SelectorImplExt;
-use selectors::Element;
use selectors::matching::matches_compound_selector;
use selectors::parser::{AttrSelector, Combinator, CompoundSelector, SelectorImpl, SimpleSelector};
+use selectors::{Element, MatchAttrGeneric};
use std::clone::Clone;
use std::sync::Arc;
use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
@@ -81,15 +81,21 @@ impl ElementSnapshot {
static EMPTY_SNAPSHOT: ElementSnapshot = ElementSnapshot { state: None, attrs: None };
+// FIXME(bholley): This implementation isn't going to work for geckolib, because
+// it's fundamentally based on get_attr/match_attr, which we don't want to support
+// that configuration due to the overhead of converting between UTF-16 and UTF-8.
+// We'll need to figure something out when we start using restyle hints with
+// geckolib, but in the mean time we can just use the trait parameters to
+// specialize it to the Servo configuration.
struct ElementWrapper<'a, E>
- where E: Element,
+ where E: Element<AttrString=String>,
E::Impl: SelectorImplExt {
element: E,
snapshot: &'a ElementSnapshot,
}
impl<'a, E> ElementWrapper<'a, E>
- where E: Element,
+ where E: Element<AttrString=String>,
E::Impl: SelectorImplExt {
pub fn new(el: E) -> ElementWrapper<'a, E> {
ElementWrapper { element: el, snapshot: &EMPTY_SNAPSHOT }
@@ -100,8 +106,42 @@ impl<'a, E> ElementWrapper<'a, E>
}
}
+#[cfg(not(feature = "gecko"))]
+impl<'a, E> MatchAttrGeneric for ElementWrapper<'a, E>
+ where E: Element<AttrString=String>,
+ E: MatchAttrGeneric,
+ E::Impl: SelectorImplExt {
+ fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
+ where F: Fn(&str) -> bool {
+ use selectors::parser::NamespaceConstraint;
+ match self.snapshot.attrs {
+ Some(_) => {
+ let html = self.is_html_element_in_html_document();
+ let local_name = if html { &attr.lower_name } else { &attr.name };
+ match attr.namespace {
+ NamespaceConstraint::Specific(ref ns) => self.snapshot.get_attr(ns, local_name),
+ NamespaceConstraint::Any => self.snapshot.get_attr_ignore_ns(local_name),
+ }.map_or(false, |v| test(v))
+ },
+ None => self.element.match_attr(attr, test)
+ }
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl<'a, E> MatchAttrGeneric for ElementWrapper<'a, E>
+ where E: Element<AttrString=String>,
+ E: MatchAttrGeneric,
+ E::Impl: SelectorImplExt {
+ fn match_attr<F>(&self, _: &AttrSelector, _: F) -> bool
+ where F: Fn(&str) -> bool {
+ panic!("Not implemented for Gecko - this system will need to be redesigned");
+ }
+}
+
impl<'a, E> Element for ElementWrapper<'a, E>
- where E: Element,
+ where E: Element<AttrString=String>,
+ E: MatchAttrGeneric,
E::Impl: SelectorImplExt {
type Impl = E::Impl;
@@ -155,27 +195,6 @@ impl<'a, E> Element for ElementWrapper<'a, E>
None => self.element.has_class(name),
}
}
- #[cfg(feature = "gecko")]
- fn match_attr<F>(&self, _: &AttrSelector, _: F) -> bool
- where F: Fn(&str) -> bool {
- panic!("Gecko can't borrow atoms as UTF-8.");
- }
- #[cfg(not(feature = "gecko"))]
- fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
- where F: Fn(&str) -> bool {
- use selectors::parser::NamespaceConstraint;
- match self.snapshot.attrs {
- Some(_) => {
- let html = self.is_html_element_in_html_document();
- let local_name = if html { &attr.lower_name } else { &attr.name };
- match attr.namespace {
- NamespaceConstraint::Specific(ref ns) => self.snapshot.get_attr(ns, local_name),
- NamespaceConstraint::Any => self.snapshot.get_attr_ignore_ns(local_name),
- }.map_or(false, |v| test(v))
- },
- None => self.element.match_attr(attr, test)
- }
- }
fn is_empty(&self) -> bool {
self.element.is_empty()
}
@@ -208,7 +227,7 @@ fn is_attr_selector<Impl: SelectorImpl>(sel: &SimpleSelector<Impl>) -> bool {
SimpleSelector::AttrExists(_) |
SimpleSelector::AttrEqual(_, _, _) |
SimpleSelector::AttrIncludes(_, _) |
- SimpleSelector::AttrDashMatch(_, _, _) |
+ SimpleSelector::AttrDashMatch(_, _) |
SimpleSelector::AttrPrefixMatch(_, _) |
SimpleSelector::AttrSubstringMatch(_, _) |
SimpleSelector::AttrSuffixMatch(_, _) => true,
@@ -285,28 +304,6 @@ impl<Impl: SelectorImplExt> DependencySet<Impl> {
DependencySet { deps: Vec::new() }
}
- pub fn compute_hint<E>(&self, el: &E, snapshot: &ElementSnapshot, current_state: ElementState)
- -> RestyleHint
- where E: Element<Impl=Impl> + Clone {
- let state_changes = snapshot.state.map_or(ElementState::empty(), |old_state| current_state ^ old_state);
- let attrs_changed = snapshot.attrs.is_some();
- let mut hint = RestyleHint::empty();
- for dep in &self.deps {
- if state_changes.intersects(dep.sensitivities.states) || (attrs_changed && dep.sensitivities.attrs) {
- let old_el: ElementWrapper<E> = ElementWrapper::new_with_snapshot(el.clone(), snapshot);
- let matched_then = matches_compound_selector(&*dep.selector, &old_el, None, &mut false);
- let matches_now = matches_compound_selector(&*dep.selector, el, None, &mut false);
- if matched_then != matches_now {
- hint.insert(combinator_to_restyle_hint(dep.combinator));
- if hint.is_all() {
- break
- }
- }
- }
- }
- hint
- }
-
pub fn note_selector(&mut self, selector: Arc<CompoundSelector<Impl>>) {
let mut cur = selector;
let mut combinator: Option<Combinator> = None;
@@ -340,3 +337,27 @@ impl<Impl: SelectorImplExt> DependencySet<Impl> {
self.deps.clear();
}
}
+
+impl<Impl: SelectorImplExt<AttrString=String>> DependencySet<Impl> {
+ pub fn compute_hint<E>(&self, el: &E, snapshot: &ElementSnapshot, current_state: ElementState)
+ -> RestyleHint
+ where E: Element<Impl=Impl, AttrString=Impl::AttrString> + Clone + MatchAttrGeneric {
+ let state_changes = snapshot.state.map_or(ElementState::empty(), |old_state| current_state ^ old_state);
+ let attrs_changed = snapshot.attrs.is_some();
+ let mut hint = RestyleHint::empty();
+ for dep in &self.deps {
+ if state_changes.intersects(dep.sensitivities.states) || (attrs_changed && dep.sensitivities.attrs) {
+ let old_el: ElementWrapper<E> = ElementWrapper::new_with_snapshot(el.clone(), snapshot);
+ let matched_then = matches_compound_selector(&*dep.selector, &old_el, None, &mut false);
+ let matches_now = matches_compound_selector(&*dep.selector, el, None, &mut false);
+ if matched_then != matches_now {
+ hint.insert(combinator_to_restyle_hint(dep.combinator));
+ if hint.is_all() {
+ break
+ }
+ }
+ }
+ }
+ hint
+ }
+}