mirror of
https://github.com/servo/servo.git
synced 2025-06-22 08:08:59 +01:00
Auto merge of #17990 - heycam:invert-selector-maps, r=emilio
style: Invert storage of selector maps to key off origin first. <!-- Please describe your changes on the following line: --> This will make it easier to avoid rebuilding all cascade levels when only a style sheet at a particular level changes. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- 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/17990) <!-- Reviewable:end -->
This commit is contained in:
commit
cc1aab35ea
1 changed files with 167 additions and 104 deletions
|
@ -51,9 +51,8 @@ pub use ::fnv::FnvHashMap;
|
||||||
|
|
||||||
/// This structure holds all the selectors and device characteristics
|
/// This structure holds all the selectors and device characteristics
|
||||||
/// for a given document. The selectors are converted into `Rule`s
|
/// for a given document. The selectors are converted into `Rule`s
|
||||||
/// (defined in rust-selectors), and introduced in a `SelectorMap`
|
/// (defined in rust-selectors), and sorted into `SelectorMap`s keyed
|
||||||
/// depending on the pseudo-element (see `PerPseudoElementSelectorMap`),
|
/// off stylesheet origin and pseudo-element (see `CascadeData`).
|
||||||
/// and stylesheet origin (see the fields of `PerPseudoElementSelectorMap`).
|
|
||||||
///
|
///
|
||||||
/// This structure is effectively created once per pipeline, in the
|
/// This structure is effectively created once per pipeline, in the
|
||||||
/// LayoutThread corresponding to that pipeline.
|
/// LayoutThread corresponding to that pipeline.
|
||||||
|
@ -90,17 +89,14 @@ pub struct Stylist {
|
||||||
/// had clear() called on it with no following rebuild()).
|
/// had clear() called on it with no following rebuild()).
|
||||||
is_cleared: bool,
|
is_cleared: bool,
|
||||||
|
|
||||||
/// The current selector maps, after evaluating media
|
/// Selector maps for all of the style sheets in the stylist, after
|
||||||
/// rules against the current device.
|
/// evalutaing media rules against the current device, split out per
|
||||||
element_map: PerPseudoElementSelectorMap,
|
/// cascade level.
|
||||||
|
cascade_data: CascadeData,
|
||||||
|
|
||||||
/// The rule tree, that stores the results of selector matching.
|
/// The rule tree, that stores the results of selector matching.
|
||||||
rule_tree: RuleTree,
|
rule_tree: RuleTree,
|
||||||
|
|
||||||
/// The selector maps corresponding to a given pseudo-element
|
|
||||||
/// (depending on the implementation)
|
|
||||||
pseudos_map: FnvHashMap<PseudoElement, PerPseudoElementSelectorMap>,
|
|
||||||
|
|
||||||
/// A map with all the animations indexed by name.
|
/// A map with all the animations indexed by name.
|
||||||
animations: FnvHashMap<Atom, KeyframesAnimation>,
|
animations: FnvHashMap<Atom, KeyframesAnimation>,
|
||||||
|
|
||||||
|
@ -234,7 +230,7 @@ impl Stylist {
|
||||||
/// be reset in clear().
|
/// be reset in clear().
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(device: Device, quirks_mode: QuirksMode) -> Self {
|
pub fn new(device: Device, quirks_mode: QuirksMode) -> Self {
|
||||||
let mut stylist = Stylist {
|
Stylist {
|
||||||
viewport_constraints: None,
|
viewport_constraints: None,
|
||||||
device: device,
|
device: device,
|
||||||
is_device_dirty: true,
|
is_device_dirty: true,
|
||||||
|
@ -242,8 +238,7 @@ impl Stylist {
|
||||||
quirks_mode: quirks_mode,
|
quirks_mode: quirks_mode,
|
||||||
effective_media_query_results: EffectiveMediaQueryResults::new(),
|
effective_media_query_results: EffectiveMediaQueryResults::new(),
|
||||||
|
|
||||||
element_map: PerPseudoElementSelectorMap::new(),
|
cascade_data: CascadeData::new(),
|
||||||
pseudos_map: Default::default(),
|
|
||||||
animations: Default::default(),
|
animations: Default::default(),
|
||||||
precomputed_pseudo_element_decls: Default::default(),
|
precomputed_pseudo_element_decls: Default::default(),
|
||||||
rules_source_order: 0,
|
rules_source_order: 0,
|
||||||
|
@ -257,15 +252,9 @@ impl Stylist {
|
||||||
num_selectors: 0,
|
num_selectors: 0,
|
||||||
num_declarations: 0,
|
num_declarations: 0,
|
||||||
num_rebuilds: 0,
|
num_rebuilds: 0,
|
||||||
};
|
}
|
||||||
|
|
||||||
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
|
||||||
stylist.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new());
|
|
||||||
});
|
|
||||||
|
|
||||||
// FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8.
|
// FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8.
|
||||||
|
|
||||||
stylist
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of selectors.
|
/// Returns the number of selectors.
|
||||||
|
@ -317,8 +306,7 @@ impl Stylist {
|
||||||
// preserve current device
|
// preserve current device
|
||||||
self.is_device_dirty = true;
|
self.is_device_dirty = true;
|
||||||
// preserve current quirks_mode value
|
// preserve current quirks_mode value
|
||||||
self.element_map = PerPseudoElementSelectorMap::new();
|
self.cascade_data.clear();
|
||||||
self.pseudos_map = Default::default();
|
|
||||||
self.animations.clear(); // Or set to Default::default()?
|
self.animations.clear(); // Or set to Default::default()?
|
||||||
self.precomputed_pseudo_element_decls = Default::default();
|
self.precomputed_pseudo_element_decls = Default::default();
|
||||||
self.rules_source_order = 0;
|
self.rules_source_order = 0;
|
||||||
|
@ -393,10 +381,6 @@ impl Stylist {
|
||||||
self.device.account_for_viewport_rule(constraints);
|
self.device.account_for_viewport_rule(constraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
|
||||||
self.pseudos_map.insert(pseudo, PerPseudoElementSelectorMap::new());
|
|
||||||
});
|
|
||||||
|
|
||||||
extra_data.clear();
|
extra_data.clear();
|
||||||
|
|
||||||
if let Some(ua_stylesheets) = ua_stylesheets {
|
if let Some(ua_stylesheets) = ua_stylesheets {
|
||||||
|
@ -420,8 +404,8 @@ impl Stylist {
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectorImpl::each_precomputed_pseudo_element(|pseudo| {
|
SelectorImpl::each_precomputed_pseudo_element(|pseudo| {
|
||||||
if let Some(map) = self.pseudos_map.remove(&pseudo) {
|
if let Some(map) = self.cascade_data.user_agent.pseudos_map.remove(&pseudo) {
|
||||||
let declarations = map.user_agent.get_universal_rules(CascadeLevel::UANormal);
|
let declarations = map.get_universal_rules(CascadeLevel::UANormal);
|
||||||
self.precomputed_pseudo_element_decls.insert(pseudo, declarations);
|
self.precomputed_pseudo_element_decls.insert(pseudo, declarations);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -482,19 +466,13 @@ impl Stylist {
|
||||||
for selector in &style_rule.selectors.0 {
|
for selector in &style_rule.selectors.0 {
|
||||||
self.num_selectors += 1;
|
self.num_selectors += 1;
|
||||||
|
|
||||||
let map = if let Some(pseudo) = selector.pseudo_element() {
|
|
||||||
self.pseudos_map
|
|
||||||
.entry(pseudo.canonical())
|
|
||||||
.or_insert_with(PerPseudoElementSelectorMap::new)
|
|
||||||
.borrow_for_origin(&origin)
|
|
||||||
} else {
|
|
||||||
self.element_map.borrow_for_origin(&origin)
|
|
||||||
};
|
|
||||||
|
|
||||||
let hashes =
|
let hashes =
|
||||||
AncestorHashes::new(&selector, self.quirks_mode);
|
AncestorHashes::new(&selector, self.quirks_mode);
|
||||||
|
|
||||||
map.insert(
|
self.cascade_data
|
||||||
|
.borrow_mut_for_origin(&origin)
|
||||||
|
.borrow_mut_for_pseudo_or_insert(selector.pseudo_element())
|
||||||
|
.insert(
|
||||||
Rule::new(selector.clone(),
|
Rule::new(selector.clone(),
|
||||||
hashes.clone(),
|
hashes.clone(),
|
||||||
locked.clone(),
|
locked.clone(),
|
||||||
|
@ -857,7 +835,8 @@ impl Stylist {
|
||||||
{
|
{
|
||||||
let pseudo = pseudo.canonical();
|
let pseudo = pseudo.canonical();
|
||||||
debug_assert!(pseudo.is_lazy());
|
debug_assert!(pseudo.is_lazy());
|
||||||
if self.pseudos_map.get(&pseudo).is_none() {
|
|
||||||
|
if !self.cascade_data.has_rules_for_pseudo(&pseudo) {
|
||||||
return CascadeInputs::default()
|
return CascadeInputs::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1117,17 +1096,6 @@ impl Stylist {
|
||||||
self.quirks_mode = quirks_mode;
|
self.quirks_mode = quirks_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the correspond PerPseudoElementSelectorMap given PseudoElement.
|
|
||||||
fn get_map(&self,
|
|
||||||
pseudo_element: Option<&PseudoElement>) -> Option<&PerPseudoElementSelectorMap>
|
|
||||||
{
|
|
||||||
match pseudo_element {
|
|
||||||
Some(pseudo) => self.pseudos_map.get(pseudo),
|
|
||||||
None => Some(&self.element_map),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns the applicable CSS declarations for the given element by
|
/// Returns the applicable CSS declarations for the given element by
|
||||||
/// treating us as an XBL stylesheet-only stylist.
|
/// treating us as an XBL stylesheet-only stylist.
|
||||||
pub fn push_applicable_declarations_as_xbl_only_stylist<E, V>(&self,
|
pub fn push_applicable_declarations_as_xbl_only_stylist<E, V>(&self,
|
||||||
|
@ -1141,15 +1109,12 @@ impl Stylist {
|
||||||
MatchingContext::new(MatchingMode::Normal, None, self.quirks_mode);
|
MatchingContext::new(MatchingMode::Normal, None, self.quirks_mode);
|
||||||
let mut dummy_flag_setter = |_: &E, _: ElementSelectorFlags| {};
|
let mut dummy_flag_setter = |_: &E, _: ElementSelectorFlags| {};
|
||||||
|
|
||||||
let map = match self.get_map(pseudo_element) {
|
|
||||||
Some(map) => map,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
let rule_hash_target = element.rule_hash_target();
|
let rule_hash_target = element.rule_hash_target();
|
||||||
|
|
||||||
// nsXBLPrototypeResources::LoadResources() loads Chrome XBL style
|
// nsXBLPrototypeResources::LoadResources() loads Chrome XBL style
|
||||||
// sheets under eAuthorSheetFeatures level.
|
// sheets under eAuthorSheetFeatures level.
|
||||||
map.author.get_all_matching_rules(element,
|
if let Some(map) = self.cascade_data.author.borrow_for_pseudo(pseudo_element) {
|
||||||
|
map.get_all_matching_rules(element,
|
||||||
&rule_hash_target,
|
&rule_hash_target,
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
&mut matching_context,
|
&mut matching_context,
|
||||||
|
@ -1157,6 +1122,7 @@ impl Stylist {
|
||||||
&mut dummy_flag_setter,
|
&mut dummy_flag_setter,
|
||||||
CascadeLevel::XBL);
|
CascadeLevel::XBL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the applicable CSS declarations for the given element.
|
/// Returns the applicable CSS declarations for the given element.
|
||||||
///
|
///
|
||||||
|
@ -1187,10 +1153,6 @@ impl Stylist {
|
||||||
"Style attributes do not apply to pseudo-elements");
|
"Style attributes do not apply to pseudo-elements");
|
||||||
debug_assert!(pseudo_element.map_or(true, |p| !p.is_precomputed()));
|
debug_assert!(pseudo_element.map_or(true, |p| !p.is_precomputed()));
|
||||||
|
|
||||||
let map = match self.get_map(pseudo_element) {
|
|
||||||
Some(map) => map,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
let rule_hash_target = element.rule_hash_target();
|
let rule_hash_target = element.rule_hash_target();
|
||||||
|
|
||||||
debug!("Determining if style is shareable: pseudo: {}",
|
debug!("Determining if style is shareable: pseudo: {}",
|
||||||
|
@ -1199,13 +1161,15 @@ impl Stylist {
|
||||||
let only_default_rules = rule_inclusion == RuleInclusion::DefaultOnly;
|
let only_default_rules = rule_inclusion == RuleInclusion::DefaultOnly;
|
||||||
|
|
||||||
// Step 1: Normal user-agent rules.
|
// Step 1: Normal user-agent rules.
|
||||||
map.user_agent.get_all_matching_rules(element,
|
if let Some(map) = self.cascade_data.user_agent.borrow_for_pseudo(pseudo_element) {
|
||||||
|
map.get_all_matching_rules(element,
|
||||||
&rule_hash_target,
|
&rule_hash_target,
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
context,
|
context,
|
||||||
self.quirks_mode,
|
self.quirks_mode,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
CascadeLevel::UANormal);
|
CascadeLevel::UANormal);
|
||||||
|
}
|
||||||
|
|
||||||
if pseudo_element.is_none() && !only_default_rules {
|
if pseudo_element.is_none() && !only_default_rules {
|
||||||
// Step 2: Presentational hints.
|
// Step 2: Presentational hints.
|
||||||
|
@ -1233,13 +1197,15 @@ impl Stylist {
|
||||||
// Which may be more what you would probably expect.
|
// Which may be more what you would probably expect.
|
||||||
if rule_hash_target.matches_user_and_author_rules() {
|
if rule_hash_target.matches_user_and_author_rules() {
|
||||||
// Step 3a: User normal rules.
|
// Step 3a: User normal rules.
|
||||||
map.user.get_all_matching_rules(element,
|
if let Some(map) = self.cascade_data.user.borrow_for_pseudo(pseudo_element) {
|
||||||
|
map.get_all_matching_rules(element,
|
||||||
&rule_hash_target,
|
&rule_hash_target,
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
context,
|
context,
|
||||||
self.quirks_mode,
|
self.quirks_mode,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
CascadeLevel::UserNormal);
|
CascadeLevel::UserNormal);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!("skipping user rules");
|
debug!("skipping user rules");
|
||||||
}
|
}
|
||||||
|
@ -1254,13 +1220,15 @@ impl Stylist {
|
||||||
// See nsStyleSet::FileRules().
|
// See nsStyleSet::FileRules().
|
||||||
if !cut_off_inheritance {
|
if !cut_off_inheritance {
|
||||||
// Step 3c: Author normal rules.
|
// Step 3c: Author normal rules.
|
||||||
map.author.get_all_matching_rules(element,
|
if let Some(map) = self.cascade_data.author.borrow_for_pseudo(pseudo_element) {
|
||||||
|
map.get_all_matching_rules(element,
|
||||||
&rule_hash_target,
|
&rule_hash_target,
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
context,
|
context,
|
||||||
self.quirks_mode,
|
self.quirks_mode,
|
||||||
flags_setter,
|
flags_setter,
|
||||||
CascadeLevel::AuthorNormal);
|
CascadeLevel::AuthorNormal);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!("skipping author normal rules due to cut off inheritance");
|
debug!("skipping author normal rules due to cut off inheritance");
|
||||||
}
|
}
|
||||||
|
@ -1592,37 +1560,132 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map that contains the CSS rules for a specific PseudoElement
|
/// Data resulting from performing the CSS cascade.
|
||||||
/// (or lack of PseudoElement).
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct PerPseudoElementSelectorMap {
|
struct CascadeData {
|
||||||
/// Rules from user agent stylesheets
|
/// Rules from user agent stylesheets
|
||||||
user_agent: SelectorMap<Rule>,
|
user_agent: PerOriginCascadeData,
|
||||||
/// Rules from author stylesheets
|
/// Rules from author stylesheets
|
||||||
author: SelectorMap<Rule>,
|
author: PerOriginCascadeData,
|
||||||
/// Rules from user stylesheets
|
/// Rules from user stylesheets
|
||||||
user: SelectorMap<Rule>,
|
user: PerOriginCascadeData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PerPseudoElementSelectorMap {
|
impl CascadeData {
|
||||||
#[inline]
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
PerPseudoElementSelectorMap {
|
CascadeData {
|
||||||
user_agent: SelectorMap::new(),
|
user_agent: PerOriginCascadeData::new(),
|
||||||
author: SelectorMap::new(),
|
author: PerOriginCascadeData::new(),
|
||||||
user: SelectorMap::new(),
|
user: PerOriginCascadeData::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn borrow_for_origin(&mut self, origin: &Origin) -> &mut SelectorMap<Rule> {
|
fn borrow_mut_for_origin(&mut self, origin: &Origin) -> &mut PerOriginCascadeData {
|
||||||
match *origin {
|
match *origin {
|
||||||
Origin::UserAgent => &mut self.user_agent,
|
Origin::UserAgent => &mut self.user_agent,
|
||||||
Origin::Author => &mut self.author,
|
Origin::Author => &mut self.author,
|
||||||
Origin::User => &mut self.user,
|
Origin::User => &mut self.user,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.user_agent.clear();
|
||||||
|
self.author.clear();
|
||||||
|
self.user.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_rules_for_pseudo(&self, pseudo: &PseudoElement) -> bool {
|
||||||
|
self.iter_origins().any(|d| d.has_rules_for_pseudo(pseudo))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter_origins(&self) -> CascadeDataIter {
|
||||||
|
CascadeDataIter {
|
||||||
|
cascade_data: &self,
|
||||||
|
cur: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CascadeDataIter<'a> {
|
||||||
|
cascade_data: &'a CascadeData,
|
||||||
|
cur: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for CascadeDataIter<'a> {
|
||||||
|
type Item = &'a PerOriginCascadeData;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<&'a PerOriginCascadeData> {
|
||||||
|
let result = match self.cur {
|
||||||
|
0 => &self.cascade_data.user_agent,
|
||||||
|
1 => &self.cascade_data.author,
|
||||||
|
2 => &self.cascade_data.user,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
self.cur += 1;
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Data resulting from performing the CSS cascade that is specific to a given
|
||||||
|
/// origin.
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct PerOriginCascadeData {
|
||||||
|
/// Rules from stylesheets at this `CascadeData`'s origin.
|
||||||
|
element_map: SelectorMap<Rule>,
|
||||||
|
|
||||||
|
/// Rules from stylesheets at this `CascadeData`'s origin that correspond
|
||||||
|
/// to a given pseudo-element.
|
||||||
|
pseudos_map: FnvHashMap<PseudoElement, SelectorMap<Rule>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PerOriginCascadeData {
|
||||||
|
fn new() -> Self {
|
||||||
|
let mut data = PerOriginCascadeData {
|
||||||
|
element_map: SelectorMap::new(),
|
||||||
|
pseudos_map: Default::default(),
|
||||||
|
};
|
||||||
|
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
||||||
|
data.pseudos_map.insert(pseudo, SelectorMap::new());
|
||||||
|
});
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn borrow_for_pseudo(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
|
||||||
|
match pseudo {
|
||||||
|
Some(pseudo) => self.pseudos_map.get(&pseudo.canonical()),
|
||||||
|
None => Some(&self.element_map),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn borrow_mut_for_pseudo_or_insert(&mut self, pseudo: Option<&PseudoElement>) -> &mut SelectorMap<Rule> {
|
||||||
|
match pseudo {
|
||||||
|
Some(pseudo) => {
|
||||||
|
self.pseudos_map
|
||||||
|
.entry(pseudo.canonical())
|
||||||
|
.or_insert_with(SelectorMap::new)
|
||||||
|
}
|
||||||
|
None => &mut self.element_map,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.element_map = SelectorMap::new();
|
||||||
|
self.pseudos_map = Default::default();
|
||||||
|
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
||||||
|
self.pseudos_map.insert(pseudo, SelectorMap::new());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A rule, that wraps a style rule, but represents a single selector of the
|
/// A rule, that wraps a style rule, but represents a single selector of the
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue