Bug 1348490 - Part 1. Match both ::placehoder & ::moz-placeholder for placeholder pseudo-elements.
authorcku <cku@mozilla.com>
Sat, 20 May 2017 16:38:05 +0800
changeset 583030 b1b6e7cb6c90887e50e5b6b77f29981ab3b7ebe6
parent 583011 3a82a745123f1f0f36937a45b877724023d112cd
child 583031 7164462b31ca928d68d3db5e8b565cea27507a2c
push id60276
push userbmo:cku@mozilla.com
push dateTue, 23 May 2017 16:05:54 +0000
bugs1348490
milestone55.0a1
Bug 1348490 - Part 1. Match both ::placehoder & ::moz-placeholder for placeholder pseudo-elements. MozReview-Commit-ID: IDc7dI0m7Lw
servo/components/style/gecko/pseudo_element.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/matching.rs
servo/components/style/servo/selector_parser.rs
servo/components/style/stylist.rs
--- a/servo/components/style/gecko/pseudo_element.rs
+++ b/servo/components/style/gecko/pseudo_element.rs
@@ -88,16 +88,26 @@ impl PseudoElement {
         (self.flags() & structs::CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE) != 0
     }
 
     /// Whether this pseudo-element is precomputed.
     #[inline]
     pub fn is_precomputed(&self) -> bool {
         self.is_anon_box()
     }
+
+    /// Covert non-canonical pseudo-element to canonical one, and keep a
+    /// canonical one as it is.
+    #[inline]
+    pub fn canonical(&self) -> PseudoElement {
+        return match *self {
+            PseudoElement::MozPlaceholder => PseudoElement::Placeholder,
+            _ => self.clone(),
+        };
+    }
 }
 
 impl ToCss for PseudoElement {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         dest.write_char(':')?;
         dest.write_str(self.as_str())
     }
 }
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -1363,17 +1363,17 @@ impl<'le> ::selectors::Element for Gecko
                             pseudo_element: &PseudoElement,
                             _context: &mut MatchingContext)
                             -> bool
     {
         // TODO(emilio): I believe we could assert we are a pseudo-element and
         // match the proper pseudo-element, given how we rulehash the stuff
         // based on the pseudo.
         match self.implemented_pseudo_element() {
-            Some(ref pseudo) => pseudo == pseudo_element,
+            Some(ref pseudo) => *pseudo == pseudo_element.canonical(),
             None => false,
         }
     }
 
     fn get_id(&self) -> Option<Atom> {
         if !self.has_id() {
             return None;
         }
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -680,16 +680,18 @@ pub trait MatchMethods : TElement {
     fn match_primary(&self,
                      context: &mut StyleContext<Self>,
                      data: &mut ElementData,
                      relations: &mut StyleRelations)
                      -> RulesMatchedResult
     {
         let implemented_pseudo = self.implemented_pseudo_element();
         if let Some(ref pseudo) = implemented_pseudo {
+            // We don't expect to match against a non-canonical pseudo-element.
+            debug_assert_eq!(*pseudo, pseudo.canonical());
             if pseudo.is_eager() {
                 // If it's an eager element-backed pseudo, just grab the matched
                 // rules from the parent, and update animations.
                 let parent = self.parent_element().unwrap();
                 let parent_data = parent.borrow_data().unwrap();
                 let pseudo_style =
                     parent_data.styles().pseudos.get(&pseudo).unwrap();
                 let mut rules = pseudo_style.rules.clone();
--- a/servo/components/style/servo/selector_parser.rs
+++ b/servo/components/style/servo/selector_parser.rs
@@ -147,16 +147,23 @@ impl PseudoElement {
             PseudoElement::ServoAnonymousTable |
             PseudoElement::ServoAnonymousTableRow |
             PseudoElement::ServoAnonymousTableCell |
             PseudoElement::ServoAnonymousBlock |
             PseudoElement::ServoInlineBlockWrapper |
             PseudoElement::ServoInlineAbsolute => PseudoElementCascadeType::Precomputed,
         }
     }
+
+    /// Covert non-canonical pseudo-element to canonical one, and keep a
+    /// canonical one as it is.
+    #[inline]
+    pub fn canonical(&self) -> PseudoElement {
+        self.clone()
+    }
 }
 
 /// A non tree-structural pseudo-class.
 /// See https://drafts.csswg.org/selectors-4/#structural-pseudos
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 pub enum NonTSPseudoClass {
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -472,17 +472,17 @@ impl Stylist {
     #[inline]
     fn add_rule_to_map(&mut self,
                        selector: &Selector<SelectorImpl>,
                        rule: &Arc<Locked<StyleRule>>,
                        stylesheet: &Stylesheet)
     {
         let map = if let Some(pseudo) = selector.pseudo_element() {
             self.pseudos_map
-                .entry(pseudo.clone())
+                .entry(pseudo.canonical())
                 .or_insert_with(PerPseudoElementSelectorMap::new)
                 .borrow_for_origin(&stylesheet.origin)
         } else {
             self.element_map.borrow_for_origin(&stylesheet.origin)
         };
 
         map.insert(Rule::new(selector.clone(),
                              rule.clone(),
@@ -664,18 +664,19 @@ impl Stylist {
     /// docs/components/style.md
     pub fn lazy_pseudo_rules<E>(&self,
                                 guards: &StylesheetGuards,
                                 element: &E,
                                 pseudo: &PseudoElement)
                                 -> Option<StrongRuleNode>
         where E: TElement
     {
+        let pseudo = pseudo.canonical();
         debug_assert!(pseudo.is_lazy());
-        if self.pseudos_map.get(pseudo).is_none() {
+        if self.pseudos_map.get(&pseudo).is_none() {
             return None
         }
 
         // Apply the selector flags. We should be in sequential mode
         // already, so we can directly apply the parent flags.
         let mut set_selector_flags = |element: &E, flags: ElementSelectorFlags| {
             if cfg!(feature = "servo") {
                 // Servo calls this function from the worker, but only for internal
@@ -697,17 +698,17 @@ impl Stylist {
                 }
             }
         };
 
         let mut declarations = ApplicableDeclarationList::new();
         let mut matching_context =
             MatchingContext::new(MatchingMode::ForStatelessPseudoElement, None);
         self.push_applicable_declarations(element,
-                                          Some(pseudo),
+                                          Some(&pseudo),
                                           None,
                                           None,
                                           AnimationRules(None, None),
                                           &mut declarations,
                                           &mut matching_context,
                                           &mut set_selector_flags);
         if declarations.is_empty() {
             return None