Bug 922669 - Part 4: Pass in anonymous content nodes when restyling any pseudo-elements that can match user action pseudo-classes. r=bz
authorCameron McCormack <cam@mcc.id.au>
Thu, 28 Nov 2013 17:46:38 +1100
changeset 157869 ae82eacc5bfff04d4f7541b172d2a481b837cc52
parent 157868 d150f83a54152d32e3d05aa88b9fb394ae6e62f3
child 157870 5e10f4677311365fe3895d8b61186c43910a667a
push id36877
push usercmccormack@mozilla.com
push dateThu, 28 Nov 2013 06:47:44 +0000
treeherdermozilla-inbound@3f7925e3933b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs922669
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 922669 - Part 4: Pass in anonymous content nodes when restyling any pseudo-elements that can match user action pseudo-classes. r=bz
layout/base/RestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/forms/nsMeterFrame.cpp
layout/forms/nsNumberControlFrame.cpp
layout/forms/nsProgressFrame.cpp
layout/forms/nsRangeFrame.cpp
layout/forms/nsTextControlFrame.cpp
layout/generic/nsBlockFrame.cpp
layout/mathml/nsMathMLFrame.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleProcessorData.h
layout/style/nsStyleSet.h
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -2350,30 +2350,30 @@ ElementRestyler::RestyleSelf(nsIFrame* a
         if (!newContext) {
           // This pseudo should no longer exist; gotta reframe
           NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame);
           mChangeList->AppendChange(aSelf, element,
                                     nsChangeHint_ReconstructFrame);
           // We're reframing anyway; just keep the same context
           newContext = oldContext;
         }
-      } else if (nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(pseudoTag)) {
-        newContext = styleSet->ResolvePseudoElementStyle(element,
-                                                         pseudoType,
-                                                         parentContext,
-                                                         aSelf->GetContent()->AsElement());
       } else {
         // Don't expect XUL tree stuff here, since it needs a comparator and
         // all.
         NS_ASSERTION(pseudoType <
                        nsCSSPseudoElements::ePseudo_PseudoElementCount,
                      "Unexpected pseudo type");
+        Element* pseudoElement =
+          nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(pseudoTag) ||
+          nsCSSPseudoElements::PseudoElementSupportsUserActionState(pseudoTag) ?
+            aSelf->GetContent()->AsElement() : nullptr;
         newContext = styleSet->ResolvePseudoElementStyle(element,
                                                          pseudoType,
-                                                         parentContext);
+                                                         parentContext,
+                                                         pseudoElement);
       }
     }
     else {
       NS_ASSERTION(aSelf->GetContent(),
                    "non pseudo-element frame without content node");
       // Skip flex-item style fixup for anonymous subtrees:
       TreeMatchContext::AutoFlexItemStyleFixupSkipper
         flexFixupSkipper(mTreeMatchContext,
@@ -2441,17 +2441,18 @@ ElementRestyler::RestyleSelf(nsIFrame* a
     else {
       // Don't expect XUL tree stuff here, since it needs a comparator and
       // all.
       NS_ASSERTION(extraPseudoType <
                      nsCSSPseudoElements::ePseudo_PseudoElementCount,
                    "Unexpected type");
       newExtraContext = styleSet->ResolvePseudoElementStyle(mContent->AsElement(),
                                                             extraPseudoType,
-                                                            newContext);
+                                                            newContext,
+                                                            nullptr);
     }
 
     MOZ_ASSERT(newExtraContext);
 
     if (oldExtraContext != newExtraContext) {
       CaptureChange(oldExtraContext, newExtraContext, assumeDifferenceHint);
       if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
         aSelf->SetAdditionalStyleContext(contextIndex, newExtraContext);
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -8648,30 +8648,32 @@ nsCSSFrameConstructor::RecreateFramesFor
 already_AddRefed<nsStyleContext>
 nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent* aContent,
                                            nsStyleContext* aStyleContext)
 {
   if (aContent) {
     return mPresShell->StyleSet()->
       ResolvePseudoElementStyle(aContent->AsElement(),
                                 nsCSSPseudoElements::ePseudo_firstLetter,
-                                aStyleContext);
+                                aStyleContext,
+                                nullptr);
   }
   return nullptr;
 }
 
 already_AddRefed<nsStyleContext>
 nsCSSFrameConstructor::GetFirstLineStyle(nsIContent* aContent,
                                          nsStyleContext* aStyleContext)
 {
   if (aContent) {
     return mPresShell->StyleSet()->
       ResolvePseudoElementStyle(aContent->AsElement(),
                                 nsCSSPseudoElements::ePseudo_firstLine,
-                                aStyleContext);
+                                aStyleContext,
+                                nullptr);
   }
   return nullptr;
 }
 
 // Predicate to see if a given content (block element) has
 // first-letter style applied to it.
 bool
 nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent* aContent,
--- a/layout/forms/nsMeterFrame.cpp
+++ b/layout/forms/nsMeterFrame.cpp
@@ -71,17 +71,17 @@ nsMeterFrame::CreateAnonymousContent(nsT
   nsresult rv = NS_NewHTMLElement(getter_AddRefs(mBarDiv), nodeInfo.forget(),
                                   mozilla::dom::NOT_FROM_PARSER);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Associate ::-moz-meter-bar pseudo-element to the anonymous child.
   nsCSSPseudoElements::Type pseudoType = nsCSSPseudoElements::ePseudo_mozMeterBar;
   nsRefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
     ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
-                              StyleContext());
+                              StyleContext(), mBarDiv->AsElement());
 
   if (!aElements.AppendElement(ContentInfo(mBarDiv, newStyleContext))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -193,22 +193,24 @@ nsNumberControlFrame::MakeAnonymousEleme
 
   // If we legitimately fail this assertion and need to allow
   // non-pseudo-element anonymous children, then we'll need to add a branch
   // that calls ResolveStyleFor((*aResult)->AsElement(), aParentContext)") to
   // set newStyleContext.
   NS_ASSERTION(aPseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement,
                "Expecting anonymous children to all be pseudo-elements");
   // Associate the pseudo-element with the anonymous child
+  Element* resultElement = (*aResult)->AsElement();
   nsRefPtr<nsStyleContext> newStyleContext =
     PresContext()->StyleSet()->ResolvePseudoElementStyle(mContent->AsElement(),
                                                          aPseudoType,
-                                                         aParentContext);
+                                                         aParentContext,
+                                                         resultElement);
 
-  if (!aElements.AppendElement(ContentInfo(*aResult, newStyleContext))) {
+  if (!aElements.AppendElement(ContentInfo(resultElement, newStyleContext))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 nsresult
 nsNumberControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
--- a/layout/forms/nsProgressFrame.cpp
+++ b/layout/forms/nsProgressFrame.cpp
@@ -71,17 +71,17 @@ nsProgressFrame::CreateAnonymousContent(
   nsresult rv = NS_NewHTMLElement(getter_AddRefs(mBarDiv), nodeInfo.forget(),
                                   mozilla::dom::NOT_FROM_PARSER);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Associate ::-moz-progress-bar pseudo-element to the anonymous child.
   nsCSSPseudoElements::Type pseudoType = nsCSSPseudoElements::ePseudo_mozProgressBar;
   nsRefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
     ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
-                              StyleContext());
+                              StyleContext(), mBarDiv->AsElement());
 
   if (!aElements.AppendElement(ContentInfo(mBarDiv, newStyleContext))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -112,17 +112,18 @@ nsRangeFrame::MakeAnonymousDiv(nsIConten
   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
   nsresult rv = NS_NewHTMLElement(aResult, nodeInfo.forget(),
                                   dom::NOT_FROM_PARSER);
   NS_ENSURE_SUCCESS(rv, rv);
   // Associate the pseudo-element with the anonymous child.
   nsRefPtr<nsStyleContext> newStyleContext =
     PresContext()->StyleSet()->ResolvePseudoElementStyle(mContent->AsElement(),
                                                          aPseudoType,
-                                                         StyleContext());
+                                                         StyleContext(),
+                                                         (*aResult)->AsElement());
 
   if (!aElements.AppendElement(ContentInfo(*aResult, newStyleContext))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return NS_OK;
 }
 
 nsresult
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -352,17 +352,18 @@ nsTextControlFrame::CreateAnonymousConte
     NS_ENSURE_TRUE(placeholderNode, NS_ERROR_OUT_OF_MEMORY);
 
     // Associate ::-moz-placeholder pseudo-element with the placeholder node.
     nsCSSPseudoElements::Type pseudoType =
       nsCSSPseudoElements::ePseudo_mozPlaceholder;
 
     nsRefPtr<nsStyleContext> placeholderStyleContext =
       PresContext()->StyleSet()->ResolvePseudoElementStyle(
-          mContent->AsElement(), pseudoType, StyleContext());
+          mContent->AsElement(), pseudoType, StyleContext(),
+          placeholderNode->AsElement());
 
     if (!aElements.AppendElement(ContentInfo(placeholderNode,
                                  placeholderStyleContext))) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   rv = UpdateValueDisplay(false);
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -6545,17 +6545,17 @@ nsBlockFrame::SetInitialChildList(ChildL
 
       nsIPresShell *shell = presContext->PresShell();
 
       nsStyleContext* parentStyle =
         CorrectStyleParentFrame(this,
           nsCSSPseudoElements::GetPseudoAtom(pseudoType))->StyleContext();
       nsRefPtr<nsStyleContext> kidSC = shell->StyleSet()->
         ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
-                                  parentStyle);
+                                  parentStyle, nullptr);
 
       // Create bullet frame
       nsBulletFrame* bullet = new (shell) nsBulletFrame(kidSC);
       bullet->Init(mContent, this, nullptr);
 
       // If the list bullet frame should be positioned inside then add
       // it to the flow now.
       if (NS_STYLE_LIST_STYLE_POSITION_INSIDE ==
--- a/layout/mathml/nsMathMLFrame.cpp
+++ b/layout/mathml/nsMathMLFrame.cpp
@@ -125,17 +125,17 @@ nsMathMLFrame::ResolveMathMLCharStyle(ns
                                       bool             aIsMutableChar)
 {
   nsCSSPseudoElements::Type pseudoType = (aIsMutableChar) ?
     nsCSSPseudoElements::ePseudo_mozMathStretchy :
     nsCSSPseudoElements::ePseudo_mozMathAnonymous; // savings
   nsRefPtr<nsStyleContext> newStyleContext;
   newStyleContext = aPresContext->StyleSet()->
     ResolvePseudoElementStyle(aContent->AsElement(), pseudoType,
-                              aParentStyleContext);
+                              aParentStyleContext, nullptr);
 
   aMathMLChar->SetStyleContext(newStyleContext);
 }
 
 /* static */ void
 nsMathMLFrame::GetEmbellishDataFrom(nsIFrame*        aFrame,
                                     nsEmbellishData& aEmbellishData)
 {
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -483,17 +483,18 @@ nsComputedDOMStyle::GetStyleContextForEl
   nsStyleSet *styleSet = presShell->StyleSet();
 
   nsRefPtr<nsStyleContext> sc;
   if (aPseudo) {
     nsCSSPseudoElements::Type type = nsCSSPseudoElements::GetPseudoType(aPseudo);
     if (type >= nsCSSPseudoElements::ePseudo_PseudoElementCount) {
       return nullptr;
     }
-    sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext);
+    sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
+                                             nullptr);
   } else {
     sc = styleSet->ResolveStyleFor(aElement, parentContext);
   }
 
   if (aStyleType == eDefaultOnly) {
     // We really only want the user and UA rules.  Filter out the other ones.
     nsTArray< nsCOMPtr<nsIStyleRule> > rules;
     for (nsRuleNode* ruleNode = sc->RuleNode();
--- a/layout/style/nsRuleProcessorData.h
+++ b/layout/style/nsRuleProcessorData.h
@@ -486,21 +486,21 @@ struct MOZ_STACK_CLASS PseudoElementRule
       mPseudoType(aPseudoType),
       mPseudoElement(aPseudoElement)
   {
     NS_PRECONDITION(aPseudoType <
                       nsCSSPseudoElements::ePseudo_PseudoElementCount,
                     "invalid aPseudoType value");
     NS_PRECONDITION(aTreeMatchContext.mForStyling, "Styling here!");
     NS_PRECONDITION(aRuleWalker, "Must have rule walker");
-    if (nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(aPseudoType)) {
-      NS_PRECONDITION(aPseudoElement,
-          "If pseudo element is supposed to support style attribute, it must "
-          "have a pseudo element set");
-    }
+    NS_PRECONDITION(!(!aPseudoElement &&
+                      nsCSSPseudoElements::PseudoElementSupportsUserActionState
+                                                                 (aPseudoType)),
+                    "aPseudoElement must be specified if the pseudo supports "
+                    ":hover and :active");
   }
 
   nsCSSPseudoElements::Type mPseudoType;
   mozilla::dom::Element* const mPseudoElement; // weak ref
 };
 
 struct MOZ_STACK_CLASS AnonBoxRuleProcessorData : public RuleProcessorData {
   AnonBoxRuleProcessorData(nsPresContext* aPresContext,
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -124,22 +124,24 @@ class nsStyleSet
   // Perhaps this should go away and we shouldn't even create style
   // contexts for such content nodes.  However, not doing any rule
   // matching for them is a first step.
   already_AddRefed<nsStyleContext>
   ResolveStyleForNonElement(nsStyleContext* aParentContext);
 
   // Get a style context for a pseudo-element.  aParentElement must be
   // non-null.  aPseudoID is the nsCSSPseudoElements::Type for the
-  // pseudo-element.
+  // pseudo-element.  aPseudoElement must be non-null if the pseudo-element
+  // type is one that allows user action pseudo-classes after it; otherwise,
+  // it is ignored.
   already_AddRefed<nsStyleContext>
   ResolvePseudoElementStyle(mozilla::dom::Element* aParentElement,
                             nsCSSPseudoElements::Type aType,
                             nsStyleContext* aParentContext,
-                            mozilla::dom::Element* aPseudoElement = nullptr);
+                            mozilla::dom::Element* aPseudoElement);
 
   // This functions just like ResolvePseudoElementStyle except that it will
   // return nullptr if there are no explicit style rules for that
   // pseudo element.
   already_AddRefed<nsStyleContext>
   ProbePseudoElementStyle(mozilla::dom::Element* aParentElement,
                           nsCSSPseudoElements::Type aType,
                           nsStyleContext* aParentContext);