servo/components/style/gecko/pseudo_element_definition.mako.rs
Emilio Cobos Álvarez 6c5cf5e2ec
style: Move nsStyleContext::mParent to GeckoStyleContext.
Unfortunately this means that we lose the NS_STYLE_INHERIT_BIT optimization to
avoid posting changes if we had not requested the struct. In practice, I'm not
sure this optimization matters much, though, and we already compare all the
structs anyway.

We _could_ keep a weak parent pointer from the text style if needed, given we're
going to keep alive the text style at least until the parent style context goes
away, so should be safe, but I don't think the extra churn is worth it, to be
honest. Happy to do so as part of bug 1368290 if you think it's worth it.

Bug: 1385896
Reviewed-by: heycam
MozReview-Commit-ID: ka6tNwf4Ke
2017-08-03 12:46:51 +02:00

233 lines
8.1 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/// Gecko's pseudo-element definition.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum PseudoElement {
% for pseudo in PSEUDOS:
/// ${pseudo.value}
% if pseudo.is_tree_pseudo_element():
${pseudo.capitalized()}(Box<[String]>),
% else:
${pseudo.capitalized()},
% endif
% endfor
}
<% EAGER_PSEUDOS = ["Before", "After", "FirstLine", "FirstLetter"] %>
/// The number of eager pseudo-elements.
pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};
/// The list of eager pseudos.
pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
% for eager_pseudo_name in EAGER_PSEUDOS:
PseudoElement::${eager_pseudo_name},
% endfor
];
<% TREE_PSEUDOS = [pseudo for pseudo in PSEUDOS if pseudo.is_tree_pseudo_element()] %>
<% SIMPLE_PSEUDOS = [pseudo for pseudo in PSEUDOS if not pseudo.is_tree_pseudo_element()] %>
<%def name="pseudo_element_variant(pseudo, tree_arg='..')">\
PseudoElement::${pseudo.capitalized()}${"({})".format(tree_arg) if pseudo.is_tree_pseudo_element() else ""}\
</%def>
impl PseudoElement {
/// Executes a closure with each simple (not functional)
/// pseudo-element as an argument.
pub fn each_simple<F>(mut fun: F)
where F: FnMut(Self),
{
% for pseudo in SIMPLE_PSEUDOS:
fun(${pseudo_element_variant(pseudo)});
% endfor
}
/// Get the pseudo-element as an atom.
#[inline]
pub fn atom(&self) -> Atom {
match *self {
% for pseudo in PSEUDOS:
${pseudo_element_variant(pseudo)} => atom!("${pseudo.value}"),
% endfor
}
}
/// Whether this pseudo-element is an anonymous box.
#[inline]
pub fn is_anon_box(&self) -> bool {
match *self {
% for pseudo in PSEUDOS:
% if pseudo.is_anon_box():
${pseudo_element_variant(pseudo)} => true,
% endif
% endfor
_ => false,
}
}
/// Whether this pseudo-element is eagerly-cascaded.
#[inline]
pub fn is_eager(&self) -> bool {
matches!(*self,
${" | ".join(map(lambda name: "PseudoElement::{}".format(name), EAGER_PSEUDOS))})
}
/// Gets the flags associated to this pseudo-element, or 0 if it's an
/// anonymous box.
pub fn flags(&self) -> u32 {
match *self {
% for pseudo in PSEUDOS:
${pseudo_element_variant(pseudo)} =>
% if pseudo.is_tree_pseudo_element():
0,
% elif pseudo.is_anon_box():
structs::CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY,
% else:
structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_${pseudo.original_ident},
% endif
% endfor
}
}
/// Construct a pseudo-element from a `CSSPseudoElementType`.
#[inline]
pub fn from_pseudo_type(type_: CSSPseudoElementType) -> Option<Self> {
match type_ {
% for pseudo in PSEUDOS:
% if not pseudo.is_anon_box():
CSSPseudoElementType::${pseudo.original_ident} => {
Some(${pseudo_element_variant(pseudo)})
},
% endif
% endfor
_ => None,
}
}
/// Construct a `CSSPseudoElementType` from a pseudo-element
#[inline]
pub fn pseudo_type(&self) -> CSSPseudoElementType {
use gecko_bindings::structs::CSSPseudoElementType_InheritingAnonBox;
match *self {
% for pseudo in PSEUDOS:
% if not pseudo.is_anon_box():
PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::${pseudo.original_ident},
% elif pseudo.is_tree_pseudo_element():
PseudoElement::${pseudo.capitalized()}(..) => CSSPseudoElementType_InheritingAnonBox,
% elif pseudo.is_inheriting_anon_box():
PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType_InheritingAnonBox,
% else:
PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::NonInheritingAnonBox,
% endif
% endfor
}
}
/// Get a PseudoInfo for a pseudo
pub fn pseudo_info(&self) -> (*mut structs::nsIAtom, CSSPseudoElementType) {
(self.atom().as_ptr(), self.pseudo_type())
}
/// Construct a pseudo-element from an `Atom`.
#[inline]
pub fn from_atom(atom: &Atom) -> Option<Self> {
% for pseudo in PSEUDOS:
% if pseudo.is_tree_pseudo_element():
// We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
% else:
if atom == &atom!("${pseudo.value}") {
return Some(${pseudo_element_variant(pseudo)});
}
% endif
% endfor
None
}
/// Construct a pseudo-element from an anonymous box `Atom`.
#[inline]
pub fn from_anon_box_atom(atom: &Atom) -> Option<Self> {
% for pseudo in PSEUDOS:
% if pseudo.is_tree_pseudo_element():
// We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
% elif pseudo.is_anon_box():
if atom == &atom!("${pseudo.value}") {
return Some(${pseudo_element_variant(pseudo)});
}
% endif
% endfor
None
}
/// Constructs an atom from a string of text, and whether we're in a
/// user-agent stylesheet.
///
/// If we're not in a user-agent stylesheet, we will never parse anonymous
/// box pseudo-elements.
///
/// Returns `None` if the pseudo-element is not recognised.
#[inline]
pub fn from_slice(s: &str, in_ua_stylesheet: bool) -> Option<Self> {
use std::ascii::AsciiExt;
// We don't need to support tree pseudos because functional
// pseudo-elements needs arguments, and thus should be created
// via other methods.
% for pseudo in SIMPLE_PSEUDOS:
if in_ua_stylesheet || ${pseudo_element_variant(pseudo)}.exposed_in_non_ua_sheets() {
if s.eq_ignore_ascii_case("${pseudo.value[1:]}") {
return Some(${pseudo_element_variant(pseudo)});
}
}
% endfor
None
}
/// Constructs a tree pseudo-element from the given name and arguments.
/// "name" must start with "-moz-tree-".
///
/// Returns `None` if the pseudo-element is not recognized.
#[inline]
pub fn tree_pseudo_element(name: &str, args: Box<[String]>) -> Option<Self> {
use std::ascii::AsciiExt;
debug_assert!(name.starts_with("-moz-tree-"));
let tree_part = &name[10..];
% for pseudo in TREE_PSEUDOS:
if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") {
return Some(${pseudo_element_variant(pseudo, "args")});
}
% endfor
None
}
}
impl ToCss for PseudoElement {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_char(':')?;
match *self {
% for pseudo in PSEUDOS:
${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?,
% endfor
}
match *self {
${" |\n ".join("PseudoElement::{}(ref args)".format(pseudo.capitalized())
for pseudo in TREE_PSEUDOS)} => {
dest.write_char('(')?;
let mut iter = args.iter();
if let Some(first) = iter.next() {
serialize_identifier(first, dest)?;
for item in iter {
dest.write_str(", ")?;
serialize_identifier(item, dest)?;
}
}
dest.write_char(')')
}
_ => Ok(()),
}
}
}