servo: Merge #17999 - style: Use an enumerated array for per-pseudo maps (from emilio:pseudo-enumerated-array); r=heycam

Source-Repo: https://github.com/servo/servo
Source-Revision: b6d46789f8d56dc90d6c6d44f857fc31afd23e51

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : c34dfb952023358beeff79dd1d69e364b15d4e81
This commit is contained in:
Emilio Cobos Álvarez 2017-08-08 06:32:12 -05:00
parent 199acfadce
commit ebc13231a0
6 changed files with 294 additions and 155 deletions

View File

@ -175,9 +175,14 @@ pub enum PseudoElement {
/// The number of eager pseudo-elements.
pub const EAGER_PSEUDO_COUNT: usize = 4;
/// The number of non-functional pseudo-elements.
pub const SIMPLE_PSEUDO_COUNT: usize = 71;
/// The list of eager pseudos.
pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
PseudoElement::Before,
@ -188,88 +193,7 @@ pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
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),
{
fun(PseudoElement::After);
fun(PseudoElement::Before);
fun(PseudoElement::Backdrop);
fun(PseudoElement::Cue);
fun(PseudoElement::FirstLetter);
fun(PseudoElement::FirstLine);
fun(PseudoElement::MozSelection);
fun(PseudoElement::MozFocusInner);
fun(PseudoElement::MozFocusOuter);
fun(PseudoElement::MozListBullet);
fun(PseudoElement::MozListNumber);
fun(PseudoElement::MozMathAnonymous);
fun(PseudoElement::MozNumberWrapper);
fun(PseudoElement::MozNumberText);
fun(PseudoElement::MozNumberSpinBox);
fun(PseudoElement::MozNumberSpinUp);
fun(PseudoElement::MozNumberSpinDown);
fun(PseudoElement::MozProgressBar);
fun(PseudoElement::MozRangeTrack);
fun(PseudoElement::MozRangeProgress);
fun(PseudoElement::MozRangeThumb);
fun(PseudoElement::MozMeterBar);
fun(PseudoElement::MozPlaceholder);
fun(PseudoElement::Placeholder);
fun(PseudoElement::MozColorSwatch);
fun(PseudoElement::MozText);
fun(PseudoElement::OofPlaceholder);
fun(PseudoElement::FirstLetterContinuation);
fun(PseudoElement::MozBlockInsideInlineWrapper);
fun(PseudoElement::MozMathMLAnonymousBlock);
fun(PseudoElement::MozXULAnonymousBlock);
fun(PseudoElement::HorizontalFramesetBorder);
fun(PseudoElement::VerticalFramesetBorder);
fun(PseudoElement::MozLineFrame);
fun(PseudoElement::ButtonContent);
fun(PseudoElement::CellContent);
fun(PseudoElement::DropDownList);
fun(PseudoElement::FieldsetContent);
fun(PseudoElement::FramesetBlank);
fun(PseudoElement::MozDisplayComboboxControlFrame);
fun(PseudoElement::HtmlCanvasContent);
fun(PseudoElement::InlineTable);
fun(PseudoElement::Table);
fun(PseudoElement::TableCell);
fun(PseudoElement::TableColGroup);
fun(PseudoElement::TableCol);
fun(PseudoElement::TableWrapper);
fun(PseudoElement::TableRowGroup);
fun(PseudoElement::TableRow);
fun(PseudoElement::Canvas);
fun(PseudoElement::PageBreak);
fun(PseudoElement::Page);
fun(PseudoElement::PageContent);
fun(PseudoElement::PageSequence);
fun(PseudoElement::ScrolledContent);
fun(PseudoElement::ScrolledCanvas);
fun(PseudoElement::ScrolledPageSequence);
fun(PseudoElement::ColumnContent);
fun(PseudoElement::Viewport);
fun(PseudoElement::ViewportScroll);
fun(PseudoElement::AnonymousFlexItem);
fun(PseudoElement::AnonymousGridItem);
fun(PseudoElement::Ruby);
fun(PseudoElement::RubyBase);
fun(PseudoElement::RubyBaseContainer);
fun(PseudoElement::RubyText);
fun(PseudoElement::RubyTextContainer);
fun(PseudoElement::MozSVGMarkerAnonChild);
fun(PseudoElement::MozSVGOuterSVGAnonChild);
fun(PseudoElement::MozSVGForeignContent);
fun(PseudoElement::MozSVGText);
}
/// Get the pseudo-element as an atom.
#[inline]
pub fn atom(&self) -> Atom {
@ -360,6 +284,165 @@ impl PseudoElement {
}
}
/// Returns an index if the pseudo-element is a simple (non-functional)
/// pseudo.
#[inline]
pub fn simple_index(&self) -> Option<usize> {
match *self {
PseudoElement::After => Some(0),
PseudoElement::Before => Some(1),
PseudoElement::Backdrop => Some(2),
PseudoElement::Cue => Some(3),
PseudoElement::FirstLetter => Some(4),
PseudoElement::FirstLine => Some(5),
PseudoElement::MozSelection => Some(6),
PseudoElement::MozFocusInner => Some(7),
PseudoElement::MozFocusOuter => Some(8),
PseudoElement::MozListBullet => Some(9),
PseudoElement::MozListNumber => Some(10),
PseudoElement::MozMathAnonymous => Some(11),
PseudoElement::MozNumberWrapper => Some(12),
PseudoElement::MozNumberText => Some(13),
PseudoElement::MozNumberSpinBox => Some(14),
PseudoElement::MozNumberSpinUp => Some(15),
PseudoElement::MozNumberSpinDown => Some(16),
PseudoElement::MozProgressBar => Some(17),
PseudoElement::MozRangeTrack => Some(18),
PseudoElement::MozRangeProgress => Some(19),
PseudoElement::MozRangeThumb => Some(20),
PseudoElement::MozMeterBar => Some(21),
PseudoElement::MozPlaceholder => Some(22),
PseudoElement::Placeholder => Some(23),
PseudoElement::MozColorSwatch => Some(24),
PseudoElement::MozText => Some(25),
PseudoElement::OofPlaceholder => Some(26),
PseudoElement::FirstLetterContinuation => Some(27),
PseudoElement::MozBlockInsideInlineWrapper => Some(28),
PseudoElement::MozMathMLAnonymousBlock => Some(29),
PseudoElement::MozXULAnonymousBlock => Some(30),
PseudoElement::HorizontalFramesetBorder => Some(31),
PseudoElement::VerticalFramesetBorder => Some(32),
PseudoElement::MozLineFrame => Some(33),
PseudoElement::ButtonContent => Some(34),
PseudoElement::CellContent => Some(35),
PseudoElement::DropDownList => Some(36),
PseudoElement::FieldsetContent => Some(37),
PseudoElement::FramesetBlank => Some(38),
PseudoElement::MozDisplayComboboxControlFrame => Some(39),
PseudoElement::HtmlCanvasContent => Some(40),
PseudoElement::InlineTable => Some(41),
PseudoElement::Table => Some(42),
PseudoElement::TableCell => Some(43),
PseudoElement::TableColGroup => Some(44),
PseudoElement::TableCol => Some(45),
PseudoElement::TableWrapper => Some(46),
PseudoElement::TableRowGroup => Some(47),
PseudoElement::TableRow => Some(48),
PseudoElement::Canvas => Some(49),
PseudoElement::PageBreak => Some(50),
PseudoElement::Page => Some(51),
PseudoElement::PageContent => Some(52),
PseudoElement::PageSequence => Some(53),
PseudoElement::ScrolledContent => Some(54),
PseudoElement::ScrolledCanvas => Some(55),
PseudoElement::ScrolledPageSequence => Some(56),
PseudoElement::ColumnContent => Some(57),
PseudoElement::Viewport => Some(58),
PseudoElement::ViewportScroll => Some(59),
PseudoElement::AnonymousFlexItem => Some(60),
PseudoElement::AnonymousGridItem => Some(61),
PseudoElement::Ruby => Some(62),
PseudoElement::RubyBase => Some(63),
PseudoElement::RubyBaseContainer => Some(64),
PseudoElement::RubyText => Some(65),
PseudoElement::RubyTextContainer => Some(66),
PseudoElement::MozSVGMarkerAnonChild => Some(67),
PseudoElement::MozSVGOuterSVGAnonChild => Some(68),
PseudoElement::MozSVGForeignContent => Some(69),
PseudoElement::MozSVGText => Some(70),
_ => None,
}
}
/// Returns an array of `None` values.
///
/// FIXME(emilio): Integer generics can't come soon enough.
pub fn simple_pseudo_none_array<T>() -> [Option<T>; SIMPLE_PSEUDO_COUNT] {
[
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None
]
}
/// Whether this pseudo-element is an anonymous box.
#[inline]
pub fn is_anon_box(&self) -> bool {

View File

@ -16,10 +16,15 @@ pub enum PseudoElement {
}
<% EAGER_PSEUDOS = ["Before", "After", "FirstLine", "FirstLetter"] %>
<% 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()] %>
/// The number of eager pseudo-elements.
pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};
/// The number of non-functional pseudo-elements.
pub const SIMPLE_PSEUDO_COUNT: usize = ${len(SIMPLE_PSEUDOS)};
/// The list of eager pseudos.
pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
% for eager_pseudo_name in EAGER_PSEUDOS:
@ -27,24 +32,11 @@ pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
% 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 {
@ -55,6 +47,27 @@ impl PseudoElement {
}
}
/// Returns an index if the pseudo-element is a simple (non-functional)
/// pseudo.
#[inline]
pub fn simple_index(&self) -> Option<usize> {
match *self {
% for i, pseudo in enumerate(SIMPLE_PSEUDOS):
${pseudo_element_variant(pseudo)} => Some(${i}),
% endfor
_ => None,
}
}
/// Returns an array of `None` values.
///
/// FIXME(emilio): Integer generics can't come soon enough.
pub fn simple_pseudo_none_array<T>() -> [Option<T>; SIMPLE_PSEUDO_COUNT] {
[
${",\n".join(["None" for pseudo in SIMPLE_PSEUDOS])}
]
}
/// Whether this pseudo-element is an anonymous box.
#[inline]
pub fn is_anon_box(&self) -> bool {

View File

@ -14,7 +14,7 @@ use std::fmt;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use style_traits::{ParseError, StyleParseError};
pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT};
pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, SIMPLE_PSEUDO_COUNT};
pub use gecko::snapshot::SnapshotMap;
bitflags! {
@ -413,15 +413,6 @@ impl SelectorImpl {
}
#[inline]
/// Executes a function for each simple (not functional) pseudo-element.
pub fn each_simple_pseudo_element<F>(fun: F)
where F: FnMut(PseudoElement),
{
PseudoElement::each_simple(fun)
}
#[inline]
/// Returns the relevant state flag for a given non-tree-structural
/// pseudo-class.
pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {

View File

@ -9,7 +9,7 @@
use cssparser::{Parser as CssParser, ParserInput};
use selectors::Element;
use selectors::parser::SelectorList;
use std::fmt::Debug;
use std::fmt::{self, Debug};
use style_traits::ParseError;
use stylesheets::{Origin, Namespaces, UrlExtraData};
@ -121,20 +121,81 @@ pub trait ElementExt: Element<Impl=SelectorImpl> + Debug {
fn matches_user_and_author_rules(&self) -> bool;
}
impl SelectorImpl {
/// A helper to traverse each precomputed pseudo-element, executing `fun` on
/// it.
///
/// The optimization comment in `each_eagerly_cascaded_pseudo_element` also
/// applies here.
#[inline]
pub fn each_precomputed_pseudo_element<F>(mut fun: F)
where F: FnMut(PseudoElement),
{
Self::each_simple_pseudo_element(|pseudo| {
if pseudo.is_precomputed() {
fun(pseudo)
}
})
/// A per-functional-pseudo map, from a given pseudo to a `T`.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct PerPseudoElementMap<T> {
entries: [Option<T>; SIMPLE_PSEUDO_COUNT],
}
impl<T> Default for PerPseudoElementMap<T> {
fn default() -> Self {
Self {
entries: PseudoElement::simple_pseudo_none_array(),
}
}
}
impl<T> Debug for PerPseudoElementMap<T>
where
T: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("[")?;
let mut first = true;
for entry in self.entries.iter() {
if !first {
f.write_str(", ")?;
}
first = false;
entry.fmt(f)?;
}
f.write_str("]")
}
}
impl<T> PerPseudoElementMap<T> {
/// Get an entry in the map.
pub fn get(&self, pseudo: &PseudoElement) -> Option<&T> {
let index = match pseudo.simple_index() {
Some(i) => i,
None => return None,
};
self.entries[index].as_ref()
}
/// Clear this enumerated array.
pub fn clear(&mut self) {
*self = Self::default();
}
/// Set an entry value.
///
/// Returns an error if the element is not a simple pseudo.
pub fn set(&mut self, pseudo: &PseudoElement, value: T) -> Result<(), ()> {
let index = match pseudo.simple_index() {
Some(i) => i,
None => return Err(()),
};
self.entries[index] = Some(value);
Ok(())
}
/// Get an entry for `pseudo`, or create it with calling `f`.
pub fn get_or_insert_with<F>(
&mut self,
pseudo: &PseudoElement,
f: F,
) -> Result<&mut T, ()>
where
F: FnOnce() -> T,
{
let index = match pseudo.simple_index() {
Some(i) => i,
None => return Err(()),
};
if self.entries[index].is_none() {
self.entries[index] = Some(f());
}
Ok(self.entries[index].as_mut().unwrap())
}
}

View File

@ -64,6 +64,10 @@ pub enum PseudoElement {
ServoInlineAbsolute,
}
/// The count of simple (non-functional) pseudo-elements (that is, all
/// pseudo-elements for now).
pub const SIMPLE_PSEUDO_COUNT: usize = PseudoElement::ServoInlineAbsolute as usize + 1;
impl ::selectors::parser::PseudoElement for PseudoElement {
type Impl = SelectorImpl;
@ -106,6 +110,17 @@ impl PseudoElement {
self.clone() as usize
}
/// An index for this pseudo-element to be indexed in an enumerated array.
#[inline]
pub fn simple_index(&self) -> Option<usize> {
Some(self.clone() as usize)
}
/// An array of `None`, one per simple pseudo-element.
pub fn simple_pseudo_none_array<T>() -> [Option<T>; SIMPLE_PSEUDO_COUNT] {
Default::default()
}
/// Creates a pseudo-element from an eager index.
#[inline]
pub fn from_eager_index(i: usize) -> Self {
@ -535,28 +550,6 @@ impl SelectorImpl {
}
}
/// Executes `fun` for each pseudo-element.
#[inline]
pub fn each_simple_pseudo_element<F>(mut fun: F)
where F: FnMut(PseudoElement),
{
fun(PseudoElement::Before);
fun(PseudoElement::After);
fun(PseudoElement::DetailsContent);
fun(PseudoElement::DetailsSummary);
fun(PseudoElement::Selection);
fun(PseudoElement::ServoText);
fun(PseudoElement::ServoInputText);
fun(PseudoElement::ServoTableWrapper);
fun(PseudoElement::ServoAnonymousTableWrapper);
fun(PseudoElement::ServoAnonymousTable);
fun(PseudoElement::ServoAnonymousTableRow);
fun(PseudoElement::ServoAnonymousTableCell);
fun(PseudoElement::ServoAnonymousBlock);
fun(PseudoElement::ServoInlineBlockWrapper);
fun(PseudoElement::ServoInlineAbsolute);
}
/// Returns the pseudo-class state flag for selector matching.
#[inline]
pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {

View File

@ -23,7 +23,7 @@ use properties::INHERIT_ALL;
use properties::IS_LINK;
use rule_tree::{CascadeLevel, RuleTree, StyleSource};
use selector_map::{SelectorMap, SelectorMapEntry};
use selector_parser::{SelectorImpl, PseudoElement};
use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement};
use selectors::attr::NamespaceConstraint;
use selectors::bloom::BloomFilter;
use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode};
@ -105,7 +105,7 @@ pub struct Stylist {
/// computed values on the fly on layout.
///
/// FIXME(emilio): Use the rule tree!
precomputed_pseudo_element_decls: FnvHashMap<PseudoElement, Vec<ApplicableDeclarationBlock>>,
precomputed_pseudo_element_decls: PerPseudoElementMap<Vec<ApplicableDeclarationBlock>>,
/// A monotonically increasing counter to represent the order on which a
/// style rule appears in a stylesheet, needed to sort them by source order.
@ -240,7 +240,7 @@ impl Stylist {
cascade_data: CascadeData::new(),
animations: Default::default(),
precomputed_pseudo_element_decls: Default::default(),
precomputed_pseudo_element_decls: PerPseudoElementMap::default(),
rules_source_order: 0,
rule_tree: RuleTree::new(),
invalidation_map: InvalidationMap::new(),
@ -308,7 +308,7 @@ impl Stylist {
// preserve current quirks_mode value
self.cascade_data.clear();
self.animations.clear(); // Or set to Default::default()?
self.precomputed_pseudo_element_decls = Default::default();
self.precomputed_pseudo_element_decls.clear();
self.rules_source_order = 0;
// We want to keep rule_tree around across stylist rebuilds.
self.invalidation_map.clear();
@ -474,8 +474,8 @@ impl Stylist {
}
self.precomputed_pseudo_element_decls
.entry(pseudo.canonical())
.or_insert_with(Vec::new)
.get_or_insert_with(&pseudo.canonical(), Vec::new)
.expect("Unexpected tree pseudo-element?")
.push(ApplicableDeclarationBlock::new(
StyleSource::Style(locked.clone()),
self.rules_source_order,
@ -489,8 +489,8 @@ impl Stylist {
Some(pseudo) => {
origin_cascade_data
.pseudos_map
.entry(pseudo.canonical())
.or_insert_with(SelectorMap::new)
.get_or_insert_with(&pseudo.canonical(), SelectorMap::new)
.expect("Unexpected tree pseudo-element?")
}
};
@ -1665,14 +1665,14 @@ struct PerOriginCascadeData {
/// Rules from stylesheets at this `CascadeData`'s origin that correspond
/// to a given pseudo-element.
pseudos_map: FnvHashMap<PseudoElement, SelectorMap<Rule>>,
pseudos_map: PerPseudoElementMap<SelectorMap<Rule>>,
}
impl PerOriginCascadeData {
fn new() -> Self {
Self {
element_map: SelectorMap::new(),
pseudos_map: Default::default(),
pseudos_map: PerPseudoElementMap::default(),
}
}
@ -1689,9 +1689,7 @@ impl PerOriginCascadeData {
}
fn has_rules_for_pseudo(&self, pseudo: &PseudoElement) -> bool {
// FIXME(emilio): We should probably make the pseudos map be an
// enumerated array.
self.pseudos_map.contains_key(pseudo)
self.pseudos_map.get(pseudo).is_some()
}
}