Bug 930270 - Don't initialize the ancestor filter for elements outside the document. r=dbaron a=akeybl
authorCameron McCormack <cam@mcc.id.au>
Sun, 03 Nov 2013 11:15:50 +1100
changeset 166350 dbef6344229b4b72a18729943c030582f4916308
parent 166349 5c97ce02b86a0f36403707ad5b77ce8190f85b5d
child 166351 27d0165a1097d1dab32e45bf0fb03a55be446129
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron, akeybl
bugs930270
milestone27.0a2
Bug 930270 - Don't initialize the ancestor filter for elements outside the document. r=dbaron a=akeybl
layout/style/crashtests/930270-1.html
layout/style/crashtests/crashtests.list
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsRuleProcessorData.h
layout/style/nsStyleSet.cpp
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/930270-1.html
@@ -0,0 +1,6 @@
+<nobr>
+<form>
+<style scoped></style>
+<input required="required">
+<button>
+<nobr>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -92,8 +92,9 @@ load 829817.html
 load 840898.html
 load 842134.html
 load 861489-1.html
 load 862113.html
 load 867487.html
 load 880862.html
 load 873222.html
 load 915440.html
+load 930270-1.html
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -3435,16 +3435,42 @@ TreeMatchContext::InitAncestors(Element 
     for (uint32_t i = ancestors.Length(); i-- != 0; ) {
       mAncestorFilter.PushAncestor(ancestors[i]);
       PushStyleScope(ancestors[i]);
     }
   }
 }
 
 void
+TreeMatchContext::InitStyleScopes(Element* aElement)
+{
+  MOZ_ASSERT(mStyleScopes.IsEmpty());
+
+  if (MOZ_LIKELY(aElement)) {
+    // Collect up the ancestors
+    nsAutoTArray<Element*, 50> ancestors;
+    Element* cur = aElement;
+    do {
+      ancestors.AppendElement(cur);
+      nsINode* parent = cur->GetParentNode();
+      if (!parent || !parent->IsElement()) {
+        break;
+      }
+
+      cur = parent->AsElement();
+    } while (true);
+
+    // Now push them in reverse order.
+    for (uint32_t i = ancestors.Length(); i-- != 0; ) {
+      PushStyleScope(ancestors[i]);
+    }
+  }
+}
+
+void
 AncestorFilter::PushAncestor(Element *aElement)
 {
   MOZ_ASSERT(mFilter);
 
   uint32_t oldLength = mHashes.Length();
 
   mPopTargets.AppendElement(oldLength);
 #ifdef DEBUG
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -134,20 +134,26 @@ struct MOZ_STACK_CLASS TreeMatchContext 
   bool HasSpecifiedScope() const {
     return mHaveSpecifiedScope;
   }
 
   /**
    * Initialize the ancestor filter and list of style scopes.  If aElement is
    * not null, it and all its ancestors will be passed to
    * mAncestorFilter.PushAncestor and PushStyleScope, starting from the root and
-   * going down the tree.
+   * going down the tree.  Must only be called for elements in a document.
    */
   void InitAncestors(mozilla::dom::Element *aElement);
 
+  /**
+   * Like InitAncestors, but only initializes the style scope list, not the
+   * ancestor filter.  May be called for elements outside a document.
+   */
+  void InitStyleScopes(mozilla::dom::Element* aElement);
+
   void PushStyleScope(mozilla::dom::Element* aElement)
   {
     NS_PRECONDITION(aElement, "aElement must not be null");
     if (aElement->IsScopedStyleRoot()) {
       mStyleScopes.AppendElement(aElement);
     }
   }
 
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -1153,30 +1153,30 @@ nsStyleSet::WalkRuleProcessors(nsIStyleR
     (*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
   if (mRuleProcessors[eOverrideSheet])
     (*aFunc)(mRuleProcessors[eOverrideSheet], aData);
   (*aFunc)(mRuleProcessors[eAnimationSheet], aData);
   (*aFunc)(mRuleProcessors[eTransitionSheet], aData);
 }
 
 static void
-InitAncestorsIfInStyleScope(TreeMatchContext& aTreeContext, Element* aElement)
+InitStyleScopes(TreeMatchContext& aTreeContext, Element* aElement)
 {
   if (aElement->IsElementInStyleScope()) {
-    aTreeContext.InitAncestors(aElement->GetParentElement());
+    aTreeContext.InitStyleScopes(aElement->GetParentElement());
   }
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveStyleFor(Element* aElement,
                             nsStyleContext* aParentContext)
 {
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aElement->OwnerDoc());
-  InitAncestorsIfInStyleScope(treeContext, aElement);
+  InitStyleScopes(treeContext, aElement);
   return ResolveStyleFor(aElement, aParentContext, treeContext);
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveStyleFor(Element* aElement,
                             nsStyleContext* aParentContext,
                             TreeMatchContext& aTreeMatchContext)
 {
@@ -1342,17 +1342,17 @@ nsStyleSet::ResolvePseudoElementStyle(El
 
   NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
                "must have pseudo element type");
   NS_ASSERTION(aParentElement, "Must have parent element");
 
   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aParentElement->OwnerDoc());
-  InitAncestorsIfInStyleScope(treeContext, aParentElement);
+  InitStyleScopes(treeContext, aParentElement);
   PseudoElementRuleProcessorData data(PresContext(), aParentElement,
                                       &ruleWalker, aType, treeContext,
                                       aPseudoElement);
   WalkRestrictionRule(aType, &ruleWalker);
   FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
             aParentElement, &ruleWalker);
 
   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
@@ -1387,17 +1387,17 @@ nsStyleSet::ResolvePseudoElementStyle(El
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
                                     nsCSSPseudoElements::Type aType,
                                     nsStyleContext* aParentContext)
 {
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aParentElement->OwnerDoc());
-  InitAncestorsIfInStyleScope(treeContext, aParentElement);
+  InitStyleScopes(treeContext, aParentElement);
   return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
                                  treeContext);
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
                                     nsCSSPseudoElements::Type aType,
                                     nsStyleContext* aParentContext,
@@ -1528,17 +1528,17 @@ nsStyleSet::ResolveXULTreePseudoStyle(El
 
   NS_ASSERTION(aPseudoTag, "must have pseudo tag");
   NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
                "Unexpected pseudo");
 
   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
                                aParentElement->OwnerDoc());
-  InitAncestorsIfInStyleScope(treeContext, aParentElement);
+  InitStyleScopes(treeContext, aParentElement);
   XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
                                 aPseudoTag, aComparator, treeContext);
   FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
             &ruleWalker);
 
   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
   nsRuleNode *visitedRuleNode = nullptr;
 
@@ -1891,17 +1891,17 @@ nsStyleSet::HasDocumentStateDependentSty
                                            nsIContent*    aContent,
                                            nsEventStates  aStateMask)
 {
   if (!aContent || !aContent->IsElement())
     return false;
 
   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
                                aContent->OwnerDoc());
-  InitAncestorsIfInStyleScope(treeContext, aContent->AsElement());
+  InitStyleScopes(treeContext, aContent->AsElement());
   StatefulData data(aPresContext, aContent->AsElement(), aStateMask,
                     treeContext);
   WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
   return data.mHint != 0;
 }
 
 static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
                                     void *aData)
@@ -1915,17 +1915,17 @@ static bool SheetHasStatefulStyle(nsISty
 // Test if style is dependent on content state
 nsRestyleHint
 nsStyleSet::HasStateDependentStyle(nsPresContext*       aPresContext,
                                    Element*             aElement,
                                    nsEventStates        aStateMask)
 {
   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
                                aElement->OwnerDoc());
-  InitAncestorsIfInStyleScope(treeContext, aElement);
+  InitStyleScopes(treeContext, aElement);
   StatefulData data(aPresContext, aElement, aStateMask, treeContext);
   WalkRuleProcessors(SheetHasStatefulStyle, &data, false);
   return data.mHint;
 }
 
 struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData {
   AttributeData(nsPresContext* aPresContext,
                 Element* aElement, nsIAtom* aAttribute, int32_t aModType,
@@ -1951,17 +1951,17 @@ nsRestyleHint
 nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
                                        Element*       aElement,
                                        nsIAtom*       aAttribute,
                                        int32_t        aModType,
                                        bool           aAttrHasChanged)
 {
   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
                                aElement->OwnerDoc());
-  InitAncestorsIfInStyleScope(treeContext, aElement);
+  InitStyleScopes(treeContext, aElement);
   AttributeData data(aPresContext, aElement, aAttribute,
                      aModType, aAttrHasChanged, treeContext);
   WalkRuleProcessors(SheetHasAttributeStyle, &data, false);
   return data.mHint;
 }
 
 bool
 nsStyleSet::MediumFeaturesChanged(nsPresContext* aPresContext)