Bug 1401825 - Support pseudo-element properly in nsPresContext::HasAuthorSpecifiedRules. r?emilio draft
authorXidorn Quan <me@upsuper.org>
Tue, 10 Oct 2017 18:35:10 +1100
changeset 678277 aac2ca8221e82962d6c9bfc61a1d57a2391e2208
parent 678276 d04c0bd25f9ae27dd9db7961f13cd6a49f3a28db
child 735270 1b0733bc5bc2377d884d19fb53dbc0c6559e394e
push id83860
push userxquan@mozilla.com
push dateTue, 10 Oct 2017 23:25:18 +0000
reviewersemilio
bugs1401825
milestone58.0a1
Bug 1401825 - Support pseudo-element properly in nsPresContext::HasAuthorSpecifiedRules. r?emilio MozReview-Commit-ID: Iugvr9DYm2E
layout/base/nsPresContext.cpp
layout/style/ServoBindingList.h
layout/style/crashtests/1401825.html
layout/style/crashtests/crashtests.list
servo/components/style/gecko/generated/bindings.rs
servo/components/style/rule_tree/mod.rs
servo/ports/geckolib/glue.rs
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -2248,26 +2248,39 @@ nsPresContext::HasAuthorSpecifiedRules(c
   if (auto* geckoStyleContext = aFrame->StyleContext()->GetAsGecko()) {
     return
       nsRuleNode::HasAuthorSpecifiedRules(geckoStyleContext,
                                           aRuleTypeMask,
                                           UseDocumentColors());
   }
   Element* elem = aFrame->GetContent()->AsElement();
 
-  MOZ_ASSERT(elem->GetPseudoElementType() ==
-             aFrame->StyleContext()->GetPseudoType());
-  if (elem->HasServoData()) {
-    return Servo_HasAuthorSpecifiedRules(elem,
-                                         aRuleTypeMask,
-                                         UseDocumentColors());
-  } else {
+  // We need to handle non-generated content pseudos too, so we use
+  // the parent of generated content pseudo to be consistent.
+  if (elem->GetPseudoElementType() != CSSPseudoElementType::NotPseudo) {
+    MOZ_ASSERT(elem->GetParent(), "Pseudo element has no parent element?");
+    elem = elem->GetParent()->AsElement();
+  }
+  if (MOZ_UNLIKELY(!elem->HasServoData())) {
     // Probably shouldn't happen, but does. See bug 1387953
     return false;
   }
+
+  nsStyleContext* styleContext = aFrame->StyleContext();
+  CSSPseudoElementType pseudoType = styleContext->GetPseudoType();
+  // Anonymous boxes are more complicated, and we just assume that they
+  // cannot have any author-specified rules here.
+  if (pseudoType == CSSPseudoElementType::InheritingAnonBox ||
+      pseudoType == CSSPseudoElementType::NonInheritingAnonBox) {
+    return false;
+  }
+  return Servo_HasAuthorSpecifiedRules(styleContext->AsServo(),
+                                       elem, pseudoType,
+                                       aRuleTypeMask,
+                                       UseDocumentColors());
 }
 
 gfxUserFontSet*
 nsPresContext::GetUserFontSet(bool aFlushUserFontSet)
 {
   return mDocument->GetUserFontSet(aFlushUserFontSet);
 }
 
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -582,17 +582,19 @@ SERVO_BINDING_FUNC(Servo_ResolvePseudoSt
                    mozilla::CSSPseudoElementType pseudo_type,
                    bool is_probe,
                    ServoStyleContextBorrowedOrNull inherited_style,
                    RawServoStyleSetBorrowed set)
 SERVO_BINDING_FUNC(Servo_SetExplicitStyle, void,
                    RawGeckoElementBorrowed element,
                    ServoStyleContextBorrowed primary_style)
 SERVO_BINDING_FUNC(Servo_HasAuthorSpecifiedRules, bool,
+                   ServoStyleContextBorrowed style,
                    RawGeckoElementBorrowed element,
+                   mozilla::CSSPseudoElementType pseudo_type,
                    uint32_t rule_type_mask,
                    bool author_colors_allowed)
 
 // Resolves style for an element or pseudo-element without processing pending
 // restyles first. The Element and its ancestors may be unstyled, have pending
 // restyles, or be in a display:none subtree. Styles are cached when possible,
 // though caching is not possible within display:none subtrees, and the styles
 // may be invalidated by already-scheduled restyles.
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1401825.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<style>
+::-moz-list-bullet {
+  -moz-appearance: button;
+}
+</style>
+<li></li>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -225,16 +225,17 @@ load 1400035.html
 load 1400325.html
 load 1400926.html
 load 1400936-1.html
 load 1400936-2.html
 load 1401256.html
 load 1401692.html
 load 1401706.html
 load 1401801.html
+load 1401825.html
 load 1402218-1.html
 load 1402366.html
 load 1402419.html
 load 1402472.html
 load 1403028.html
 load 1403433.html
 load 1403465.html
 load 1403592.html
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -2939,17 +2939,19 @@ extern "C" {
                                     set: RawServoStyleSetBorrowed)
      -> ServoStyleContextStrong;
 }
 extern "C" {
     pub fn Servo_SetExplicitStyle(element: RawGeckoElementBorrowed,
                                   primary_style: ServoStyleContextBorrowed);
 }
 extern "C" {
-    pub fn Servo_HasAuthorSpecifiedRules(element: RawGeckoElementBorrowed,
+    pub fn Servo_HasAuthorSpecifiedRules(style: ServoStyleContextBorrowed,
+                                         element: RawGeckoElementBorrowed,
+                                         pseudo_type: CSSPseudoElementType,
                                          rule_type_mask: u32,
                                          author_colors_allowed: bool) -> bool;
 }
 extern "C" {
     pub fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
                                     pseudo_type: CSSPseudoElementType,
                                     rule_inclusion: StyleRuleInclusion,
                                     snapshots:
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -2,16 +2,18 @@
  * 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/. */
 
 #![allow(unsafe_code)]
 
 //! The rule tree.
 
 use applicable_declarations::ApplicableDeclarationList;
+#[cfg(feature = "gecko")]
+use gecko::selector_parser::PseudoElement;
 #[cfg(feature = "servo")]
 use heapsize::HeapSizeOf;
 #[cfg(feature = "gecko")]
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use properties::{Importance, LonghandIdSet, PropertyDeclarationBlock};
 use servo_arc::{Arc, ArcBorrow, NonZeroPtrMut};
 use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
 use smallvec::SmallVec;
@@ -1072,16 +1074,17 @@ impl StrongRuleNode {
     /// Implementation of `nsRuleNode::HasAuthorSpecifiedRules` for Servo rule
     /// nodes.
     ///
     /// Returns true if any properties specified by `rule_type_mask` was set by
     /// an author rule.
     #[cfg(feature = "gecko")]
     pub fn has_author_specified_rules<E>(&self,
                                          mut element: E,
+                                         mut pseudo: Option<PseudoElement>,
                                          guards: &StylesheetGuards,
                                          rule_type_mask: u32,
                                          author_colors_allowed: bool)
         -> bool
         where E: ::dom::TElement
     {
         use gecko_bindings::structs::{NS_AUTHOR_SPECIFIED_BACKGROUND, NS_AUTHOR_SPECIFIED_BORDER};
         use gecko_bindings::structs::{NS_AUTHOR_SPECIFIED_PADDING, NS_AUTHOR_SPECIFIED_TEXT_SHADOW};
@@ -1286,24 +1289,30 @@ impl StrongRuleNode {
                         }
                     }
                 }
             }
 
             if !have_explicit_ua_inherit { break }
 
             // Continue to the parent element and search for the inherited properties.
-            element = match element.inheritance_parent() {
-                Some(parent) => parent,
-                None => break
-            };
+            if let Some(pseudo) = pseudo.take() {
+                if pseudo.inherits_from_default_values() {
+                    break;
+                }
+            } else {
+                element = match element.inheritance_parent() {
+                    Some(parent) => parent,
+                    None => break
+                };
 
-            let parent_data = element.mutate_data().unwrap();
-            let parent_rule_node = parent_data.styles.primary().rules().clone();
-            element_rule_node = Cow::Owned(parent_rule_node);
+                let parent_data = element.mutate_data().unwrap();
+                let parent_rule_node = parent_data.styles.primary().rules().clone();
+                element_rule_node = Cow::Owned(parent_rule_node);
+            }
 
             properties = inherited_properties;
         }
 
         false
     }
 
     /// Returns true if there is either animation or transition level rule.
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1858,36 +1858,34 @@ pub extern "C" fn Servo_SetExplicitStyle
     // We only support this API for initial styling. There's no reason it couldn't
     // work for other things, we just haven't had a reason to do so.
     debug_assert!(element.get_data().is_none());
     let mut data = unsafe { element.ensure_data() };
     data.styles.primary = Some(unsafe { ArcBorrow::from_ref(style) }.clone_arc());
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_HasAuthorSpecifiedRules(element: RawGeckoElementBorrowed,
+pub extern "C" fn Servo_HasAuthorSpecifiedRules(style: ServoStyleContextBorrowed,
+                                                element: RawGeckoElementBorrowed,
+                                                pseudo_type: CSSPseudoElementType,
                                                 rule_type_mask: u32,
                                                 author_colors_allowed: bool)
     -> bool
 {
     let element = GeckoElement(element);
-
-    let data =
-        element.borrow_data()
-        .expect("calling Servo_HasAuthorSpecifiedRules on an unstyled element");
-
-    let primary_style = data.styles.primary();
+    let pseudo = PseudoElement::from_pseudo_type(pseudo_type);
 
     let guard = (*GLOBAL_STYLE_DATA).shared_lock.read();
     let guards = StylesheetGuards::same(&guard);
 
-    primary_style.rules().has_author_specified_rules(element,
-                                                     &guards,
-                                                     rule_type_mask,
-                                                     author_colors_allowed)
+    style.rules().has_author_specified_rules(element,
+                                             pseudo,
+                                             &guards,
+                                             rule_type_mask,
+                                             author_colors_allowed)
 }
 
 fn get_pseudo_style(
     guard: &SharedRwLockReadGuard,
     element: GeckoElement,
     pseudo: &PseudoElement,
     rule_inclusion: RuleInclusion,
     styles: &ElementStyles,