aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/wrapper.rs206
-rw-r--r--components/style/README.md2
-rw-r--r--components/style/dom.rs10
-rw-r--r--components/style/matching.rs2
-rw-r--r--components/style/media_queries.rs10
-rw-r--r--components/style/selector_impl.rs90
-rw-r--r--components/style/selector_matching.rs83
-rw-r--r--docs/components/style.md158
-rw-r--r--docs/glossary.md2
-rw-r--r--ports/geckolib/bindings.rs12
-rw-r--r--ports/geckolib/glue.rs67
-rw-r--r--ports/geckolib/selector_impl.rs161
-rw-r--r--ports/geckolib/wrapper.rs17
13 files changed, 642 insertions, 178 deletions
diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs
index e9215f8717f..35353a85cf1 100644
--- a/components/layout/wrapper.rs
+++ b/components/layout/wrapper.rs
@@ -66,12 +66,12 @@ use std::sync::Arc;
use string_cache::{Atom, Namespace};
use style::computed_values::content::ContentItem;
use style::computed_values::{content, display};
-use style::dom::{TDocument, TElement, TNode, UnsafeNode};
+use style::dom::{PresentationalHintsSynthetizer, TDocument, TElement, TNode, UnsafeNode};
use style::element_state::*;
use style::properties::{ComputedValues, ServoComputedValues};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
use style::restyle_hints::ElementSnapshot;
-use style::selector_impl::{NonTSPseudoClass, PseudoElement, ServoSelectorImpl};
+use style::selector_impl::{NonTSPseudoClass, PseudoElement, PseudoElementCascadeType, ServoSelectorImpl};
use style::servo::{PrivateStyleData, SharedStyleContext};
use url::Url;
use util::str::is_whitespace;
@@ -81,7 +81,7 @@ pub type NonOpaqueStyleAndLayoutData = *mut RefCell<PrivateLayoutData>;
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
/// only ever see these and must never see instances of `LayoutJS`.
-pub trait LayoutNode : TNode {
+pub trait LayoutNode: TNode {
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode;
fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode;
@@ -401,6 +401,16 @@ pub struct ServoLayoutElement<'le> {
chain: PhantomData<&'le ()>,
}
+impl<'le> PresentationalHintsSynthetizer for ServoLayoutElement<'le> {
+ fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
+ where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
+ {
+ unsafe {
+ self.element.synthesize_presentational_hints_for_legacy_attributes(hints);
+ }
+ }
+}
+
impl<'le> TElement for ServoLayoutElement<'le> {
type ConcreteNode = ServoLayoutNode<'le>;
type ConcreteDocument = ServoLayoutDocument<'le>;
@@ -419,14 +429,6 @@ impl<'le> TElement for ServoLayoutElement<'le> {
self.element.get_state_for_layout()
}
- fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
- where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
- {
- unsafe {
- self.element.synthesize_presentational_hints_for_legacy_attributes(hints);
- }
- }
-
#[inline]
fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str> {
unsafe {
@@ -665,8 +667,10 @@ impl<T> PseudoElementType<T> {
/// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout
/// node does not allow any parents or siblings of nodes to be accessed, to avoid races.
-pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
- type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>;
+pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq {
+ type ConcreteThreadSafeLayoutElement:
+ ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>
+ + ::selectors::Element<Impl=ServoSelectorImpl>;
type ChildrenIterator: Iterator<Item = Self> + Sized;
/// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode`
@@ -680,6 +684,18 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
/// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
fn type_id(&self) -> Option<NodeTypeId>;
+ /// Returns the type ID of this node, without discarding pseudo-elements as
+ /// `type_id` does.
+ fn type_id_without_excluding_pseudo_elements(&self) -> NodeTypeId;
+
+ #[inline]
+ fn is_element_or_elements_pseudo(&self) -> bool {
+ match self.type_id_without_excluding_pseudo_elements() {
+ NodeTypeId::Element(..) => true,
+ _ => false,
+ }
+ }
+
fn debug_id(self) -> usize;
fn flow_debug_id(self) -> usize;
@@ -774,13 +790,38 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
// Precompute non-eagerly-cascaded pseudo-element styles if not
// cached before.
let style_pseudo = other.style_pseudo_element();
- if !style_pseudo.is_eagerly_cascaded() &&
- !self.borrow_layout_data().unwrap().style_data.per_pseudo.contains_key(&style_pseudo) {
- let mut data = self.mutate_layout_data().unwrap();
- let new_style = context.stylist
- .computed_values_for_pseudo(&style_pseudo,
- data.style_data.style.as_ref());
- data.style_data.per_pseudo.insert(style_pseudo.clone(), new_style.unwrap());
+ match style_pseudo.cascade_type() {
+ // Already computed during the cascade.
+ PseudoElementCascadeType::Eager => {},
+ PseudoElementCascadeType::Precomputed => {
+ if !self.borrow_layout_data()
+ .unwrap().style_data
+ .per_pseudo.contains_key(&style_pseudo) {
+ let mut data = self.mutate_layout_data().unwrap();
+ let new_style =
+ context.stylist
+ .precomputed_values_for_pseudo(&style_pseudo,
+ data.style_data.style.as_ref());
+ data.style_data.per_pseudo
+ .insert(style_pseudo.clone(), new_style.unwrap());
+ }
+ }
+ PseudoElementCascadeType::Lazy => {
+ debug_assert!(self.is_element_or_elements_pseudo());
+ if !self.borrow_layout_data()
+ .unwrap().style_data
+ .per_pseudo.contains_key(&style_pseudo) {
+ let mut data = self.mutate_layout_data().unwrap();
+ let new_style =
+ context.stylist
+ .lazily_compute_pseudo_element_style(
+ &self.as_element(),
+ &style_pseudo,
+ data.style_data.style.as_ref().unwrap());
+ data.style_data.per_pseudo
+ .insert(style_pseudo.clone(), new_style.unwrap());
+ }
+ }
}
Ref::map(self.borrow_layout_data().unwrap(), |data| {
@@ -904,12 +945,14 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq {
// This trait is only public so that it can be implemented by the gecko wrapper.
// It can be used to violate thread-safety, so don't use it elsewhere in layout!
-pub trait DangerousThreadSafeLayoutNode : ThreadSafeLayoutNode {
+pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode {
unsafe fn dangerous_first_child(&self) -> Option<Self>;
unsafe fn dangerous_next_sibling(&self) -> Option<Self>;
}
-pub trait ThreadSafeLayoutElement: Clone + Copy + Sized {
+pub trait ThreadSafeLayoutElement: Clone + Copy + Sized +
+ ::selectors::Element<Impl=ServoSelectorImpl> +
+ PresentationalHintsSynthetizer {
type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>;
#[inline]
@@ -999,6 +1042,11 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
Some(self.node.type_id())
}
+ #[inline]
+ fn type_id_without_excluding_pseudo_elements(&self) -> NodeTypeId {
+ self.node.type_id()
+ }
+
fn debug_id(self) -> usize {
self.node.debug_id()
}
@@ -1252,8 +1300,8 @@ impl<ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<ConcreteNod
}
}
-/// A wrapper around elements that ensures layout can only ever access safe properties and cannot
-/// race on elements.
+/// A wrapper around elements that ensures layout can only
+/// ever access safe properties and cannot race on elements.
#[derive(Copy, Clone)]
pub struct ServoThreadSafeLayoutElement<'le> {
element: &'le Element,
@@ -1292,3 +1340,113 @@ impl TextContent {
}
}
}
+
+/// This implementation of `::selectors::Element` is used for implementing lazy
+/// pseudo-elements.
+///
+/// Lazy pseudo-elements in Servo only allows selectors using safe properties,
+/// i.e., local_name, attributes, so they can only be used for **private**
+/// pseudo-elements (like `::-servo-details-content`).
+///
+/// Probably a few more of this functions can be implemented (like `has_class`,
+/// `each_class`, etc), but they have no use right now.
+///
+/// Note that the element implementation is needed only for selector matching,
+/// not for inheritance (styles are inherited appropiately).
+impl <'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
+ type Impl = ServoSelectorImpl;
+
+ fn parent_element(&self) -> Option<Self> {
+ warn!("ServoThreadSafeLayoutElement::parent_element called");
+ None
+ }
+
+ fn first_child_element(&self) -> Option<Self> {
+ warn!("ServoThreadSafeLayoutElement::first_child_element called");
+ None
+ }
+
+ // Skips non-element nodes
+ fn last_child_element(&self) -> Option<Self> {
+ warn!("ServoThreadSafeLayoutElement::last_child_element called");
+ None
+ }
+
+ // Skips non-element nodes
+ fn prev_sibling_element(&self) -> Option<Self> {
+ warn!("ServoThreadSafeLayoutElement::prev_sibling_element called");
+ None
+ }
+
+ // Skips non-element nodes
+ fn next_sibling_element(&self) -> Option<Self> {
+ warn!("ServoThreadSafeLayoutElement::next_sibling_element called");
+ None
+ }
+
+ fn is_html_element_in_html_document(&self) -> bool {
+ debug!("ServoThreadSafeLayoutElement::is_html_element_in_html_document called");
+ true
+ }
+
+ #[inline]
+ fn get_local_name(&self) -> &Atom {
+ ThreadSafeLayoutElement::get_local_name(self)
+ }
+
+ #[inline]
+ fn get_namespace(&self) -> &Namespace {
+ ThreadSafeLayoutElement::get_namespace(self)
+ }
+
+ fn match_non_ts_pseudo_class(&self, _: NonTSPseudoClass) -> bool {
+ // NB: This could maybe be implemented
+ warn!("ServoThreadSafeLayoutElement::match_non_ts_pseudo_class called");
+ false
+ }
+
+ fn get_id(&self) -> Option<Atom> {
+ debug!("ServoThreadSafeLayoutElement::get_id called");
+ None
+ }
+
+ fn has_class(&self, _name: &Atom) -> bool {
+ debug!("ServoThreadSafeLayoutElement::has_class called");
+ false
+ }
+
+ fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool
+ where F: Fn(&str) -> bool {
+ match attr.namespace {
+ NamespaceConstraint::Specific(ref ns) => {
+ self.get_attr(ns, &attr.name).map_or(false, |attr| test(attr))
+ },
+ NamespaceConstraint::Any => {
+ unsafe {
+ self.element.get_attr_vals_for_layout(&attr.name).iter()
+ .any(|attr| test(*attr))
+ }
+ }
+ }
+ }
+
+ fn is_empty(&self) -> bool {
+ warn!("ServoThreadSafeLayoutElement::is_empty called");
+ false
+ }
+
+ fn is_root(&self) -> bool {
+ warn!("ServoThreadSafeLayoutElement::is_root called");
+ false
+ }
+
+ fn each_class<F>(&self, _callback: F)
+ where F: FnMut(&Atom) {
+ warn!("ServoThreadSafeLayoutElement::each_class called");
+ }
+}
+
+impl<'le> PresentationalHintsSynthetizer for ServoThreadSafeLayoutElement<'le> {
+ fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V)
+ where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> {}
+}
diff --git a/components/style/README.md b/components/style/README.md
index e2a1a1664e8..70670a5f96b 100644
--- a/components/style/README.md
+++ b/components/style/README.md
@@ -2,3 +2,5 @@ servo-style
===========
Style system for Servo, using [rust-cssparser](https://github.com/mozilla-servo/rust-cssparser) for parsing.
+
+ * [Documentation](https://github.com/servo/servo/blob/master/docs/components/style.md).
diff --git a/components/style/dom.rs b/components/style/dom.rs
index fed1597c627..badd4f31065 100644
--- a/components/style/dom.rs
+++ b/components/style/dom.rs
@@ -195,7 +195,12 @@ pub trait TDocument : Sized + Copy + Clone {
fn drain_modified_elements(&self) -> Vec<(Self::ConcreteElement, ElementSnapshot)>;
}
-pub trait TElement : Sized + Copy + Clone + ElementExt {
+pub trait PresentationalHintsSynthetizer {
+ fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
+ where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
+}
+
+pub trait TElement : Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
type ConcreteNode: TNode<ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>;
type ConcreteDocument: TDocument<ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>;
@@ -205,9 +210,6 @@ pub trait TElement : Sized + Copy + Clone + ElementExt {
fn get_state(&self) -> ElementState;
- fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V)
- where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>;
-
fn get_attr<'a>(&'a self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>;
fn get_attrs<'a>(&'a self, attr: &Atom) -> Vec<&'a str>;
diff --git a/components/style/matching.rs b/components/style/matching.rs
index 84189fde404..11fa2915081 100644
--- a/components/style/matching.rs
+++ b/components/style/matching.rs
@@ -540,7 +540,7 @@ pub trait ElementMatchMethods : TElement
stylist.push_applicable_declarations(self,
parent_bf,
None,
- Some(pseudo.clone()),
+ Some(&pseudo.clone()),
applicable_declarations.per_pseudo.entry(pseudo).or_insert(vec![]));
});
diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs
index b19b4d81c7e..2af3ee833ee 100644
--- a/components/style/media_queries.rs
+++ b/components/style/media_queries.rs
@@ -117,6 +117,13 @@ impl Device {
viewport_size: viewport_size,
}
}
+
+ #[inline]
+ pub fn au_viewport_size(&self) -> Size2D<Au> {
+ Size2D::new(Au::from_f32_px(self.viewport_size.width.get()),
+ Au::from_f32_px(self.viewport_size.height.get()))
+ }
+
}
impl Expression {
@@ -203,8 +210,7 @@ pub fn parse_media_query_list(input: &mut Parser) -> MediaQueryList {
impl MediaQueryList {
pub fn evaluate(&self, device: &Device) -> bool {
- let viewport_size = Size2D::new(Au::from_f32_px(device.viewport_size.width.get()),
- Au::from_f32_px(device.viewport_size.height.get()));
+ let viewport_size = device.au_viewport_size();
// Check if any queries match (OR condition)
self.media_queries.iter().any(|mq| {
diff --git a/components/style/selector_impl.rs b/components/style/selector_impl.rs
index b7faff4c028..925ccb816ef 100644
--- a/components/style/selector_impl.rs
+++ b/components/style/selector_impl.rs
@@ -8,6 +8,53 @@ use selectors::Element;
use selectors::parser::{ParserContext, SelectorImpl};
use stylesheets::Stylesheet;
+/// This function determines if a pseudo-element is eagerly cascaded or not.
+///
+/// Eagerly cascaded pseudo-elements are "normal" pseudo-elements (i.e.
+/// `::before` and `::after`). They inherit styles normally as another
+/// selector would do, and they're part of the cascade.
+///
+/// Lazy pseudo-elements are affected by selector matching, but they're only
+/// computed when needed, and not before. They're useful for general
+/// pseudo-elements that are not very common.
+///
+/// Note that in Servo lazy pseudo-elements are restricted to a subset of
+/// selectors, so you can't use it for public pseudo-elements. This is not the
+/// case with Gecko though.
+///
+/// Precomputed ones skip the cascade process entirely, mostly as an
+/// optimisation since they are private pseudo-elements (like
+/// `::-servo-details-content`).
+///
+/// This pseudo-elements are resolved on the fly using *only* global rules
+/// (rules of the form `*|*`), and applying them to the parent style.
+///
+/// If you're implementing a public selector that the end-user might customize,
+/// then you probably need to make it eager.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum PseudoElementCascadeType {
+ Eager,
+ Lazy,
+ Precomputed,
+}
+
+impl PseudoElementCascadeType {
+ #[inline]
+ pub fn is_eager(&self) -> bool {
+ *self == PseudoElementCascadeType::Eager
+ }
+
+ #[inline]
+ pub fn is_lazy(&self) -> bool {
+ *self == PseudoElementCascadeType::Lazy
+ }
+
+ #[inline]
+ pub fn is_precomputed(&self) -> bool {
+ *self == PseudoElementCascadeType::Precomputed
+ }
+}
+
pub trait ElementExt: Element {
fn is_link(&self) -> bool;
}
@@ -15,49 +62,32 @@ pub trait ElementExt: Element {
pub trait SelectorImplExt : SelectorImpl + Sized {
type ComputedValues: properties::ComputedValues;
+ fn pseudo_element_cascade_type(pseudo: &Self::PseudoElement) -> PseudoElementCascadeType;
+
fn each_pseudo_element<F>(mut fun: F)
- where F: FnMut(<Self as SelectorImpl>::PseudoElement);
-
- /// This function determines if a pseudo-element is eagerly cascaded or not.
- ///
- /// Eagerly cascaded pseudo-elements are "normal" pseudo-elements (i.e.
- /// `::before` and `::after`). They inherit styles normally as another
- /// selector would do.
- ///
- /// Non-eagerly cascaded ones skip the cascade process entirely, mostly as
- /// an optimisation since they are private pseudo-elements (like
- /// `::-servo-details-content`). This pseudo-elements are resolved on the
- /// fly using global rules (rules of the form `*|*`), and applying them to
- /// the parent style.
- ///
- /// If you're implementing a public selector that the end-user might
- /// customize, then you probably need doing the whole cascading process and
- /// return true in this function for that pseudo.
- ///
- /// But if you are implementing a private pseudo-element, please consider if
- /// it might be possible to skip the cascade for it.
- fn is_eagerly_cascaded_pseudo_element(pseudo: &<Self as SelectorImpl>::PseudoElement) -> bool;
+ where F: FnMut(Self::PseudoElement);
#[inline]
fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F)
where F: FnMut(<Self as SelectorImpl>::PseudoElement) {
Self::each_pseudo_element(|pseudo| {
- if Self::is_eagerly_cascaded_pseudo_element(&pseudo) {
+ if Self::pseudo_element_cascade_type(&pseudo).is_eager() {
fun(pseudo)
}
})
}
#[inline]
- fn each_non_eagerly_cascaded_pseudo_element<F>(mut fun: F)
+ fn each_precomputed_pseudo_element<F>(mut fun: F)
where F: FnMut(<Self as SelectorImpl>::PseudoElement) {
Self::each_pseudo_element(|pseudo| {
- if !Self::is_eagerly_cascaded_pseudo_element(&pseudo) {
+ if Self::pseudo_element_cascade_type(&pseudo).is_precomputed() {
fun(pseudo)
}
})
}
+
fn pseudo_class_state_flag(pc: &Self::NonTSPseudoClass) -> ElementState;
fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet<Self>];
@@ -76,13 +106,13 @@ pub enum PseudoElement {
impl PseudoElement {
#[inline]
- pub fn is_eagerly_cascaded(&self) -> bool {
+ pub fn cascade_type(&self) -> PseudoElementCascadeType {
match *self {
PseudoElement::Before |
PseudoElement::After |
- PseudoElement::Selection |
- PseudoElement::DetailsSummary => true,
- PseudoElement::DetailsContent => false,
+ PseudoElement::Selection => PseudoElementCascadeType::Eager,
+ PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy,
+ PseudoElement::DetailsContent => PseudoElementCascadeType::Precomputed,
}
}
}
@@ -191,8 +221,8 @@ impl SelectorImplExt for ServoSelectorImpl {
type ComputedValues = ServoComputedValues;
#[inline]
- fn is_eagerly_cascaded_pseudo_element(pseudo: &PseudoElement) -> bool {
- pseudo.is_eagerly_cascaded()
+ fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
+ pseudo.cascade_type()
}
#[inline]
diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs
index 72fdec38e43..4faf9aa0eb4 100644
--- a/components/style/selector_matching.rs
+++ b/components/style/selector_matching.rs
@@ -5,10 +5,9 @@
// For lazy_static
#![allow(unsafe_code)]
-use dom::TElement;
+use dom::PresentationalHintsSynthetizer;
use element_state::*;
use error_reporting::{ParseErrorReporter, StdoutErrorReporter};
-use euclid::Size2D;
use media_queries::{Device, MediaType};
use properties::{self, ComputedValues, PropertyDeclaration, PropertyDeclarationBlock};
use restyle_hints::{ElementSnapshot, RestyleHint, DependencySet};
@@ -127,9 +126,9 @@ pub struct Stylist<Impl: SelectorImplExt> {
/// Applicable declarations for a given non-eagerly cascaded pseudo-element.
/// These are eagerly computed once, and then used to resolve the new
/// computed values on the fly on layout.
- non_eagerly_cascaded_pseudo_element_decls: HashMap<Impl::PseudoElement,
- Vec<DeclarationBlock>,
- BuildHasherDefault<::fnv::FnvHasher>>,
+ precomputed_pseudo_element_decls: HashMap<Impl::PseudoElement,
+ Vec<DeclarationBlock>,
+ BuildHasherDefault<::fnv::FnvHasher>>,
rules_source_order: usize,
@@ -148,7 +147,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
element_map: PerPseudoElementSelectorMap::new(),
pseudos_map: HashMap::with_hasher(Default::default()),
- non_eagerly_cascaded_pseudo_element_decls: HashMap::with_hasher(Default::default()),
+ precomputed_pseudo_element_decls: HashMap::with_hasher(Default::default()),
rules_source_order: 0,
state_deps: DependencySet::new(),
};
@@ -175,7 +174,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
self.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new());
});
- self.non_eagerly_cascaded_pseudo_element_decls = HashMap::with_hasher(Default::default());
+ self.precomputed_pseudo_element_decls = HashMap::with_hasher(Default::default());
self.rules_source_order = 0;
self.state_deps.clear();
@@ -242,39 +241,71 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
self.rules_source_order = rules_source_order;
- Impl::each_non_eagerly_cascaded_pseudo_element(|pseudo| {
- // TODO: Don't precompute this, compute it on demand instead and
- // cache it.
- //
- // This is actually kind of hard, because the stylist is shared
- // between threads.
+ Impl::each_precomputed_pseudo_element(|pseudo| {
+ // TODO: Consider not doing this and just getting the rules on the
+ // fly. It should be a bit slower, but we'd take rid of the
+ // extra field, and avoid this precomputation entirely.
if let Some(map) = self.pseudos_map.remove(&pseudo) {
let mut declarations = vec![];
map.user_agent.normal.get_universal_rules(&mut declarations);
map.user_agent.important.get_universal_rules(&mut declarations);
- self.non_eagerly_cascaded_pseudo_element_decls.insert(pseudo, declarations);
+ self.precomputed_pseudo_element_decls.insert(pseudo, declarations);
}
})
}
- pub fn computed_values_for_pseudo(&self,
- pseudo: &Impl::PseudoElement,
- parent: Option<&Arc<Impl::ComputedValues>>) -> Option<Arc<Impl::ComputedValues>> {
- debug_assert!(!Impl::is_eagerly_cascaded_pseudo_element(pseudo));
- if let Some(declarations) = self.non_eagerly_cascaded_pseudo_element_decls.get(pseudo) {
+ /// Computes the style for a given "precomputed" pseudo-element, taking the
+ /// universal rules and applying them.
+ pub fn precomputed_values_for_pseudo(&self,
+ pseudo: &Impl::PseudoElement,
+ parent: Option<&Arc<Impl::ComputedValues>>)
+ -> Option<Arc<Impl::ComputedValues>> {
+ debug_assert!(Impl::pseudo_element_cascade_type(pseudo).is_precomputed());
+ if let Some(declarations) = self.precomputed_pseudo_element_decls.get(pseudo) {
+
let (computed, _) =
- properties::cascade::<Impl::ComputedValues>(Size2D::zero(),
- &declarations, false,
- parent.map(|p| &**p), None,
- box StdoutErrorReporter);
+ properties::cascade(self.device.au_viewport_size(),
+ &declarations, false,
+ parent.map(|p| &**p), None,
+ box StdoutErrorReporter);
Some(Arc::new(computed))
} else {
parent.map(|p| p.clone())
}
}
+ pub fn lazily_compute_pseudo_element_style<E>(&self,
+ element: &E,
+ pseudo: &Impl::PseudoElement,
+ parent: &Arc<Impl::ComputedValues>)
+ -> Option<Arc<Impl::ComputedValues>>
+ where E: Element<Impl=Impl> +
+ PresentationalHintsSynthetizer {
+ debug_assert!(Impl::pseudo_element_cascade_type(pseudo).is_lazy());
+ if self.pseudos_map.get(pseudo).is_none() {
+ return None;
+ }
+
+ let mut declarations = vec![];
+
+ // NB: This being cached could be worth it, maybe allow an optional
+ // ApplicableDeclarationsCache?.
+ self.push_applicable_declarations(element,
+ None,
+ None,
+ Some(pseudo),
+ &mut declarations);
+
+ let (computed, _) =
+ properties::cascade(self.device.au_viewport_size(),
+ &declarations, false,
+ Some(&**parent), None,
+ box StdoutErrorReporter);
+ Some(Arc::new(computed))
+ }
+
pub fn compute_restyle_hint<E>(&self, element: &E,
snapshot: &ElementSnapshot,
// NB: We need to pass current_state as an argument because
@@ -325,16 +356,16 @@ impl<Impl: SelectorImplExt> Stylist<Impl> {
element: &E,
parent_bf: Option<&BloomFilter>,
style_attribute: Option<&PropertyDeclarationBlock>,
- pseudo_element: Option<Impl::PseudoElement>,
+ pseudo_element: Option<&Impl::PseudoElement>,
applicable_declarations: &mut V)
-> bool
- where E: Element<Impl=Impl> + TElement,
+ where E: Element<Impl=Impl> + PresentationalHintsSynthetizer,
V: VecLike<DeclarationBlock> {
assert!(!self.is_device_dirty);
assert!(style_attribute.is_none() || pseudo_element.is_none(),
"Style attributes do not apply to pseudo-elements");
debug_assert!(pseudo_element.is_none() ||
- Impl::is_eagerly_cascaded_pseudo_element(pseudo_element.as_ref().unwrap()));
+ !Impl::pseudo_element_cascade_type(pseudo_element.as_ref().unwrap()).is_precomputed());
let map = match pseudo_element {
Some(ref pseudo) => self.pseudos_map.get(pseudo).unwrap(),
diff --git a/docs/components/style.md b/docs/components/style.md
new file mode 100644
index 00000000000..a3d657e53e0
--- /dev/null
+++ b/docs/components/style.md
@@ -0,0 +1,158 @@
+# Servo's style system overview
+
+This needs to be filled more extensively. Meanwhile, you can also take a look to
+the [style doc comments][style-doc], or the [Styling
+Overview][wiki-styling-overview] in the wiki, which is a conversation between
+Boris Zbarsky and Patrick Walton about how style sharing works.
+
+<a name="selector-impl"></a>
+## Selector Implementation
+
+The style system is generic over quite a few things, in order to be shareable
+with Servo's layout system, and with [Stylo][stylo], an ambitious project that
+aims to integrate Servo's style system into Gecko.
+
+The main generic trait is [selectors' SelectorImpl][selector-impl], that has all
+the logic related to parsing pseudo-elements and other pseudo-classes appart
+from [tree-structural ones][tree-structural-pseudo-classes].
+
+Servo [extends][selector-impl-ext] that trait in order to allow a few more
+things to be shared between Stylo and Servo.
+
+The main Servo implementation (the one that is used in regular builds) is
+[ServoSelectorImpl][servo-selector-impl].
+
+<a name="dom-glue"></a>
+## DOM glue
+
+In order to keep DOM, layout and style in different modules, there are a few
+traits involved.
+
+Style's [`dom` traits][style-dom-traits] (`TDocument`, `TElement`, `TNode`,
+`TRestyleDamage`) are the main "wall" between layout and style.
+
+Layout's [`wrapper`][layout-wrapper] module is the one that makes sure that
+layout traits have the required traits implemented.
+
+<a name="stylist"></a>
+## The Stylist
+
+The [`stylist`][stylist] structure is the one that holds all the selectors and
+device characteristics for a given document.
+
+The stylesheets' CSS rules are converted into [`Rule`][selectors-rules]s, and
+introduced in a [`SelectorMap`][selectors-selectormap] depending on the
+pseudo-element (see [`PerPseudoElementSelectorMap`][per-pseudo-selectormap]),
+stylesheet origin (see [`PerOriginSelectorMap`][per-origin-selectormap]), and
+priority (see the `normal` and `important` fields in
+[`PerOriginSelectorMap`][per-origin-selectormap]).
+
+This structure is effectively created once per [pipeline][docs-pipeline], in the
+LayoutThread corresponding to that pipeline.
+
+<a name="properties"></a>
+## The `properties` module
+
+The [properties module][properties-module] is a mako template where all the
+properties, computed value computation and cascading logic resides.
+
+It's a complex template with a **lot** of code, but the main function it exposes
+is the [`cascade` function][properties-cascade-fn], which performs all the
+computation.
+
+<a name="pseudo-elements"></a>
+## Pseudo-Element resolution
+
+Pseudo-elements are a tricky section of the style system. Not all
+pseudo-elements are very common, and so some of them might want to skip the
+cascade.
+
+Servo has, as of right now, five [pseudo-elements][servo-pseudo-elements]:
+
+ * [`::before`][mdn-pseudo-before] and [`::after`][mdn-pseudo-after].
+ * [`::selection`][mdn-pseudo-selection]: This one is only partially
+ implemented, and only works for text inputs and textareas as of right now.
+ * `::-servo-details-summary`: This pseudo-element represents the `<summary>` of
+ a `<details>` element.
+ * `::-servo-details-content`: This pseudo-element represents the contents of
+ a `<details>` element.
+
+Both `::-servo-details-*` pseudo-elements are private (i.e. they are only parsed
+from User-Agent stylesheets).
+
+Servo has three different ways of cascading a pseudo-element, which are defined
+in [`PseudoElementCascadeType`][pseudo-cascade-type]:
+
+<a name="pe-cascading-eager"></a>
+### "Eager" cascading
+
+This mode computes the computed values of a given node's pseudo-element over the
+first pass of the style system.
+
+This is used for all public pseudo-elements, and is, as of right now, **the only
+way a public pseudo-element should be cascaded** (the explanation for this is
+below).
+
+<a name="pe-cascading-precomputed"></a>
+### "Precomputed" cascading
+
+Or, better said, no cascading at all. A pseudo-element marked as such is not
+cascaded.
+
+The only rules that apply to the styles of that pseudo-element are universal
+rules (rules with a `*|*` selector), and they are applied directly over the
+element's style if present.
+
+`::-servo-details-content` is an example of this kind of pseudo-element, all the
+rules in the UA stylesheet with the selector `*|*::-servo-details-content` (and
+only those) are evaluated over the element's style (except the `display` value,
+that is overwritten by layout).
+
+This should be the **preferred type for private pseudo-elements** (although some
+of them might need selectors, see below).
+
+<a name="pe-cascading-lazy"></a>
+### "Lazy" cascading
+
+Lazy cascading allows to compute pseudo-element styles lazily, that is, just
+when needed.
+
+Currently (for Servo, not that much for stylo), **selectors supported for this
+kind of pseudo-elements are only a subset of selectors that can be matched on
+the layout tree, which does not hold all data from the DOM tree**.
+
+This subset includes tags and attribute selectors, enough for making
+`::-servo-details-summary` a lazy pseudo-element (that only needs to know
+if it is in an `open` details element or not).
+
+Since no other selectors would apply to it, **this is (at least for now) not an
+acceptable type for public pseudo-elements, but should be considered for private
+pseudo-elements**.
+
+#### Not found what you were looking for?
+
+Feel free to ping @SimonSapin, @mbrubeck or @emilio on irc, and please mention
+that you didn't find it here so it can be added :)
+
+[style-doc]: http://doc.servo.org/style/index.html
+[wiki-styling-overview]: https://github.com/servo/servo/wiki/Styling-overview
+[stylo]: https://public.etherpad-mozilla.org/p/stylo
+[selector-impl]: http://doc.servo.org/selectors/parser/trait.SelectorImpl.html
+[selector-impl-ext]: http://doc.servo.org/style/selector_impl/trait.SelectorImplExt.html
+[servo-selector-impl]: http://doc.servo.org/style/selector_impl/struct.ServoSelectorImpl.html
+[tree-structural-pseudo-classes]: https://www.w3.org/TR/selectors4/#structural-pseudos
+[style-dom-traits]: http://doc.servo.org/style/dom/index.html
+[layout-wrapper]: http://doc.servo.org/layout/wrapper/index.html
+[pseudo-cascade-type]: http://doc.servo.org/style/selector_impl/enum.PseudoElementCascadeType.html
+[servo-pseudo-elements]: http://doc.servo.org/style/selector_impl/enum.PseudoElement.html
+[mdn-pseudo-before]: https://developer.mozilla.org/en/docs/Web/CSS/::before
+[mdn-pseudo-after]: https://developer.mozilla.org/en/docs/Web/CSS/::after
+[mdn-pseudo-selection]: https://developer.mozilla.org/en/docs/Web/CSS/::selection
+[stylist]: http://doc.servo.org/style/selector_matching/struct.Stylist.html
+[selectors-selectormap]: http://doc.servo.org/selectors/matching/struct.SelectorMap.html
+[selectors-rule]: http://doc.servo.org/selectors/matching/struct.Rule.html
+[per-pseudo-selectormap]: http://doc.servo.org/style/selector_matching/struct.PerPseudoElementSelectorMap.html
+[per-origin-selectormap]: http://doc.servo.org/style/selector_matching/struct.PerOriginSelectorMap.html
+[docs-pipeline]: https://github.com/servo/servo/blob/master/docs/glossary.md#pipeline
+[properties-module]: http://doc.servo.org/style/properties/index.html
+[properties-cascade-fn]: http://doc.servo.org/style/properties/fn.cascade.html
diff --git a/docs/glossary.md b/docs/glossary.md
index 32e907823d0..7328db28528 100644
--- a/docs/glossary.md
+++ b/docs/glossary.md
@@ -7,7 +7,7 @@ If there is a word or phrase used in Servo's code, issue tracker, mailing list,
# Glossary
### Compositor ###
-
+
The thread that receives input events from the operating system and forwards them to the constellation. It is also in charge of compositing complete renders of web content and displaying them on the screen as fast as possible.
### Constellation ###
diff --git a/ports/geckolib/bindings.rs b/ports/geckolib/bindings.rs
index 16724678a80..234f309378d 100644
--- a/ports/geckolib/bindings.rs
+++ b/ports/geckolib/bindings.rs
@@ -78,11 +78,11 @@ extern "C" {
set: *mut RawServoStyleSet);
pub fn Servo_PrependStyleSheet(sheet: *mut RawServoStyleSheet,
set: *mut RawServoStyleSet);
+ pub fn Servo_RemoveStyleSheet(sheet: *mut RawServoStyleSheet,
+ set: *mut RawServoStyleSet);
pub fn Servo_InsertStyleSheetBefore(sheet: *mut RawServoStyleSheet,
reference: *mut RawServoStyleSheet,
set: *mut RawServoStyleSet);
- pub fn Servo_RemoveStyleSheet(sheet: *mut RawServoStyleSheet,
- set: *mut RawServoStyleSet);
pub fn Servo_StyleSheetHasRules(sheet: *mut RawServoStyleSheet) -> bool;
pub fn Servo_InitStyleSet() -> *mut RawServoStyleSet;
pub fn Servo_DropStyleSet(set: *mut RawServoStyleSet);
@@ -93,6 +93,14 @@ extern "C" {
pseudoTag: *mut nsIAtom,
set: *mut RawServoStyleSet)
-> *mut ServoComputedValues;
+ pub fn Servo_GetComputedValuesForPseudoElement(parent_style:
+ *mut ServoComputedValues,
+ match_element:
+ *mut RawGeckoElement,
+ pseudo_tag: *mut nsIAtom,
+ set: *mut RawServoStyleSet,
+ is_probe: bool)
+ -> *mut ServoComputedValues;
pub fn Servo_AddRefComputedValues(arg1: *mut ServoComputedValues);
pub fn Servo_ReleaseComputedValues(arg1: *mut ServoComputedValues);
pub fn Gecko_GetAttrAsUTF8(element: *mut RawGeckoElement, ns: *const u8,
diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs
index 27edf4ed357..96939a3f76f 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -5,7 +5,7 @@
#![allow(unsafe_code)]
use app_units::Au;
-use bindings::{RawGeckoDocument, RawGeckoNode};
+use bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode};
use bindings::{RawServoStyleSet, RawServoStyleSheet, ServoComputedValues, ServoNodeData};
use bindings::{nsIAtom};
use data::PerDocumentStyleData;
@@ -20,15 +20,16 @@ use std::slice;
use std::str::from_utf8_unchecked;
use std::sync::{Arc, Mutex};
use style::context::{ReflowGoal};
-use style::dom::{TDocument, TNode};
+use style::dom::{TDocument, TElement, TNode};
use style::error_reporting::StdoutErrorReporter;
use style::parallel;
use style::properties::ComputedValues;
+use style::selector_impl::{SelectorImplExt, PseudoElementCascadeType};
use style::stylesheets::Origin;
use traversal::RecalcStyleOnly;
use url::Url;
use util::arc_ptr_eq;
-use wrapper::{GeckoDocument, GeckoNode, NonOpaqueStyleData};
+use wrapper::{GeckoDocument, GeckoElement, GeckoNode, NonOpaqueStyleData};
// TODO: This is ugly and should go away once we get an atom back-end.
pub fn pseudo_element_from_atom(pseudo: *mut nsIAtom,
@@ -256,7 +257,7 @@ pub extern "C" fn Servo_GetComputedValuesForAnonymousBox(parent_style_or_null: *
-> *mut ServoComputedValues {
let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data);
- let pseudo = match pseudo_element_from_atom(pseudo_tag, true) {
+ let pseudo = match pseudo_element_from_atom(pseudo_tag, /* ua_stylesheet = */ true) {
Ok(pseudo) => pseudo,
Err(pseudo) => {
warn!("stylo: Unable to parse anonymous-box pseudo-element: {}", pseudo);
@@ -267,12 +268,68 @@ pub extern "C" fn Servo_GetComputedValuesForAnonymousBox(parent_style_or_null: *
type Helpers = ArcHelpers<ServoComputedValues, GeckoComputedValues>;
Helpers::maybe_with(parent_style_or_null, |maybe_parent| {
- let new_computed = data.stylist.computed_values_for_pseudo(&pseudo, maybe_parent);
+ let new_computed = data.stylist.precomputed_values_for_pseudo(&pseudo, maybe_parent);
new_computed.map_or(ptr::null_mut(), |c| Helpers::from(c))
})
}
#[no_mangle]
+pub extern "C" fn Servo_GetComputedValuesForPseudoElement(parent_style: *mut ServoComputedValues,
+ match_element: *mut RawGeckoElement,
+ pseudo_tag: *mut nsIAtom,
+ raw_data: *mut RawServoStyleSet,
+ is_probe: bool)
+ -> *mut ServoComputedValues {
+ debug_assert!(!match_element.is_null());
+
+ let parent_or_null = || {
+ if is_probe {
+ ptr::null_mut()
+ } else {
+ Servo_AddRefComputedValues(parent_style);
+ parent_style
+ }
+ };
+
+ let pseudo = match pseudo_element_from_atom(pseudo_tag, /* ua_stylesheet = */ true) {
+ Ok(pseudo) => pseudo,
+ Err(pseudo) => {
+ warn!("stylo: Unable to parse anonymous-box pseudo-element: {}", pseudo);
+ return parent_or_null();
+ }
+ };
+
+
+ let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data);
+
+ let element = unsafe { GeckoElement::from_raw(match_element) };
+
+ type Helpers = ArcHelpers<ServoComputedValues, GeckoComputedValues>;
+
+ match GeckoSelectorImpl::pseudo_element_cascade_type(&pseudo) {
+ PseudoElementCascadeType::Eager => {
+ let node = element.as_node();
+ let maybe_computed = node.borrow_data()
+ .and_then(|data| {
+ data.per_pseudo.get(&pseudo).map(|c| c.clone())
+ });
+ maybe_computed.map_or_else(parent_or_null, Helpers::from)
+ }
+ PseudoElementCascadeType::Lazy => {
+ Helpers::with(parent_style, |parent| {
+ data.stylist
+ .lazily_compute_pseudo_element_style(&element, &pseudo, parent)
+ .map_or_else(parent_or_null, Helpers::from)
+ })
+ }
+ PseudoElementCascadeType::Precomputed => {
+ unreachable!("Anonymous pseudo found in \
+ Servo_GetComputedValuesForPseudoElement");
+ }
+ }
+}
+
+#[no_mangle]
pub extern "C" fn Servo_AddRefComputedValues(ptr: *mut ServoComputedValues) -> () {
type Helpers = ArcHelpers<ServoComputedValues, GeckoComputedValues>;
unsafe { Helpers::addref(ptr) };
diff --git a/ports/geckolib/selector_impl.rs b/ports/geckolib/selector_impl.rs
index 03803563443..ddc26f6c541 100644
--- a/ports/geckolib/selector_impl.rs
+++ b/ports/geckolib/selector_impl.rs
@@ -6,7 +6,7 @@ use properties::GeckoComputedValues;
use selectors::parser::{ParserContext, SelectorImpl};
use style;
use style::element_state::ElementState;
-use style::selector_impl::SelectorImplExt;
+use style::selector_impl::{PseudoElementCascadeType, SelectorImplExt};
pub type Stylist = style::selector_matching::Stylist<GeckoSelectorImpl>;
pub type Stylesheet = style::stylesheets::Stylesheet<GeckoSelectorImpl>;
@@ -22,7 +22,12 @@ pub enum PseudoElement {
FirstLine,
// TODO: Probably a few more are missing here
- // https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h
+ AnonBox(AnonBoxPseudoElement),
+}
+
+// https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h
+#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
+pub enum AnonBoxPseudoElement {
MozNonElement,
MozAnonymousBlock,
MozAnonymousPositionedBlock,
@@ -153,6 +158,7 @@ impl SelectorImpl for GeckoSelectorImpl {
fn parse_pseudo_element(context: &ParserContext,
name: &str) -> Result<PseudoElement, ()> {
+ use self::AnonBoxPseudoElement::*;
use self::PseudoElement::*;
// The braces here are unfortunate, but they're needed for
@@ -168,7 +174,7 @@ impl SelectorImpl for GeckoSelectorImpl {
return Err(())
}
- Ok(match_ignore_ascii_case! { name,
+ Ok(AnonBox(match_ignore_ascii_case! { name,
"-moz-non-element" => MozNonElement,
"-moz-anonymous-block" => MozAnonymousBlock,
@@ -235,7 +241,7 @@ impl SelectorImpl for GeckoSelectorImpl {
"-moz-svg-text" => MozSVGText,
_ => return Err(())
- })
+ }))
}
}
@@ -243,86 +249,89 @@ impl SelectorImplExt for GeckoSelectorImpl {
type ComputedValues = GeckoComputedValues;
#[inline]
- fn is_eagerly_cascaded_pseudo_element(pseudo: &PseudoElement) -> bool {
+ fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
match *pseudo {
PseudoElement::Before |
- PseudoElement::After |
- PseudoElement::FirstLine => true,
- _ => false,
+ PseudoElement::After => PseudoElementCascadeType::Eager,
+ PseudoElement::AnonBox(_) => PseudoElementCascadeType::Precomputed,
+ _ => PseudoElementCascadeType::Lazy,
}
}
#[inline]
fn each_pseudo_element<F>(mut fun: F)
where F: FnMut(PseudoElement) {
- fun(PseudoElement::Before);
- fun(PseudoElement::After);
- fun(PseudoElement::FirstLine);
-
- fun(PseudoElement::MozNonElement);
- fun(PseudoElement::MozAnonymousBlock);
- fun(PseudoElement::MozAnonymousPositionedBlock);
- fun(PseudoElement::MozMathMLAnonymousBlock);
- fun(PseudoElement::MozXULAnonymousBlock);
-
- fun(PseudoElement::MozHorizontalFramesetBorder);
- fun(PseudoElement::MozVerticalFramesetBorder);
- fun(PseudoElement::MozLineFrame);
- fun(PseudoElement::MozButtonContent);
- fun(PseudoElement::MozButtonLabel);
- fun(PseudoElement::MozCellContent);
- fun(PseudoElement::MozDropdownList);
- fun(PseudoElement::MozFieldsetContent);
- fun(PseudoElement::MozFramesetBlank);
- fun(PseudoElement::MozDisplayComboboxControlFrame);
-
- fun(PseudoElement::MozHTMLCanvasContent);
- fun(PseudoElement::MozInlineTable);
- fun(PseudoElement::MozTable);
- fun(PseudoElement::MozTableCell);
- fun(PseudoElement::MozTableColumnGroup);
- fun(PseudoElement::MozTableColumn);
- fun(PseudoElement::MozTableOuter);
- fun(PseudoElement::MozTableRowGroup);
- fun(PseudoElement::MozTableRow);
-
- fun(PseudoElement::MozCanvas);
- fun(PseudoElement::MozPageBreak);
- fun(PseudoElement::MozPage);
- fun(PseudoElement::MozPageContent);
- fun(PseudoElement::MozPageSequence);
- fun(PseudoElement::MozScrolledContent);
- fun(PseudoElement::MozScrolledCanvas);
- fun(PseudoElement::MozScrolledPageSequence);
- fun(PseudoElement::MozColumnContent);
- fun(PseudoElement::MozViewport);
- fun(PseudoElement::MozViewportScroll);
- fun(PseudoElement::MozAnonymousFlexItem);
- fun(PseudoElement::MozAnonymousGridItem);
-
- fun(PseudoElement::MozRuby);
- fun(PseudoElement::MozRubyBase);
- fun(PseudoElement::MozRubyBaseContainer);
- fun(PseudoElement::MozRubyText);
- fun(PseudoElement::MozRubyTextContainer);
-
- fun(PseudoElement::MozTreeColumn);
- fun(PseudoElement::MozTreeRow);
- fun(PseudoElement::MozTreeSeparator);
- fun(PseudoElement::MozTreeCell);
- fun(PseudoElement::MozTreeIndentation);
- fun(PseudoElement::MozTreeLine);
- fun(PseudoElement::MozTreeTwisty);
- fun(PseudoElement::MozTreeImage);
- fun(PseudoElement::MozTreeCellText);
- fun(PseudoElement::MozTreeCheckbox);
- fun(PseudoElement::MozTreeProgressMeter);
- fun(PseudoElement::MozTreeDropFeedback);
-
- fun(PseudoElement::MozSVGMarkerAnonChild);
- fun(PseudoElement::MozSVGOuterSVGAnonChild);
- fun(PseudoElement::MozSVGForeignContent);
- fun(PseudoElement::MozSVGText);
+ use self::AnonBoxPseudoElement::*;
+ use self::PseudoElement::*;
+
+ fun(Before);
+ fun(After);
+ fun(FirstLine);
+
+ fun(AnonBox(MozNonElement));
+ fun(AnonBox(MozAnonymousBlock));
+ fun(AnonBox(MozAnonymousPositionedBlock));
+ fun(AnonBox(MozMathMLAnonymousBlock));
+ fun(AnonBox(MozXULAnonymousBlock));
+
+ fun(AnonBox(MozHorizontalFramesetBorder));
+ fun(AnonBox(MozVerticalFramesetBorder));
+ fun(AnonBox(MozLineFrame));
+ fun(AnonBox(MozButtonContent));
+ fun(AnonBox(MozButtonLabel));
+ fun(AnonBox(MozCellContent));
+ fun(AnonBox(MozDropdownList));
+ fun(AnonBox(MozFieldsetContent));
+ fun(AnonBox(MozFramesetBlank));
+ fun(AnonBox(MozDisplayComboboxControlFrame));
+
+ fun(AnonBox(MozHTMLCanvasContent));
+ fun(AnonBox(MozInlineTable));
+ fun(AnonBox(MozTable));
+ fun(AnonBox(MozTableCell));
+ fun(AnonBox(MozTableColumnGroup));
+ fun(AnonBox(MozTableColumn));
+ fun(AnonBox(MozTableOuter));
+ fun(AnonBox(MozTableRowGroup));
+ fun(AnonBox(MozTableRow));
+
+ fun(AnonBox(MozCanvas));
+ fun(AnonBox(MozPageBreak));
+ fun(AnonBox(MozPage));
+ fun(AnonBox(MozPageContent));
+ fun(AnonBox(MozPageSequence));
+ fun(AnonBox(MozScrolledContent));
+ fun(AnonBox(MozScrolledCanvas));
+ fun(AnonBox(MozScrolledPageSequence));
+ fun(AnonBox(MozColumnContent));
+ fun(AnonBox(MozViewport));
+ fun(AnonBox(MozViewportScroll));
+ fun(AnonBox(MozAnonymousFlexItem));
+ fun(AnonBox(MozAnonymousGridItem));
+
+ fun(AnonBox(MozRuby));
+ fun(AnonBox(MozRubyBase));
+ fun(AnonBox(MozRubyBaseContainer));
+ fun(AnonBox(MozRubyText));
+ fun(AnonBox(MozRubyTextContainer));
+
+ fun(AnonBox(MozTreeColumn));
+ fun(AnonBox(MozTreeRow));
+ fun(AnonBox(MozTreeSeparator));
+ fun(AnonBox(MozTreeCell));
+ fun(AnonBox(MozTreeIndentation));
+ fun(AnonBox(MozTreeLine));
+ fun(AnonBox(MozTreeTwisty));
+ fun(AnonBox(MozTreeImage));
+ fun(AnonBox(MozTreeCellText));
+ fun(AnonBox(MozTreeCheckbox));
+ fun(AnonBox(MozTreeProgressMeter));
+ fun(AnonBox(MozTreeDropFeedback));
+
+ fun(AnonBox(MozSVGMarkerAnonChild));
+ fun(AnonBox(MozSVGOuterSVGAnonChild));
+ fun(AnonBox(MozSVGForeignContent));
+ fun(AnonBox(MozSVGText));
}
#[inline]
diff --git a/ports/geckolib/wrapper.rs b/ports/geckolib/wrapper.rs
index edf007a0016..f27cf770bf0 100644
--- a/ports/geckolib/wrapper.rs
+++ b/ports/geckolib/wrapper.rs
@@ -32,7 +32,8 @@ use std::slice;
use std::str::from_utf8_unchecked;
use std::sync::Arc;
use string_cache::{Atom, Namespace};
-use style::dom::{OpaqueNode, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
+use style::dom::{OpaqueNode, PresentationalHintsSynthetizer};
+use style::dom::{TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
use style::element_state::ElementState;
#[allow(unused_imports)] // Used in commented-out code.
use style::error_reporting::StdoutErrorReporter;
@@ -339,12 +340,6 @@ impl<'le> TElement for GeckoElement<'le> {
}
}
- fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V)
- where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
- {
- // FIXME(bholley) - Need to implement this.
- }
-
#[inline]
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> {
unsafe {
@@ -360,6 +355,14 @@ impl<'le> TElement for GeckoElement<'le> {
}
}
+impl<'le> PresentationalHintsSynthetizer for GeckoElement<'le> {
+ fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V)
+ where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
+ {
+ // FIXME(bholley) - Need to implement this.
+ }
+}
+
impl<'le> ::selectors::Element for GeckoElement<'le> {
type Impl = GeckoSelectorImpl;