Bug 558943. Pass the right value for aIsLink from ReparentStyleContext. r=dbaron
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 08 Jun 2010 15:58:26 -0400
changeset 43326 e88b028a04833a3b97abae450d252b7b3e44a52a
parent 43325 155d4a2be1bce19dd043bda5eaa1151cc1446bd7
child 43327 4a0fcf9b58ff4e38a979d27ba61147be1e1a08e6
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs558943
milestone1.9.3a5pre
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 558943. Pass the right value for aIsLink from ReparentStyleContext. r=dbaron
layout/style/crashtests/558943-1.xhtml
layout/style/crashtests/crashtests.list
layout/style/nsStyleContext.h
layout/style/nsStyleSet.cpp
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/558943-1.xhtml
@@ -0,0 +1,11 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
+<head>
+<style>
+.x:first-line { }
+.y { }
+</style>
+</head>
+<body onload="setTimeout(function(){  document.documentElement.className = 'y'; }, 0)">
+<td class="x"><a href="#">Link</a></td>
+</body>
+</html>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -49,8 +49,9 @@ load 495269-2.html
 load 498036-1.html
 load 509155-1.html
 load 509156-1.html
 load 509569-1.html
 load 524252-1.html
 load font-face-truncated-src.html 
 load 536789-1.html
 load 565248-1.html
+load 558943-1.xhtml
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -140,16 +140,22 @@ public:
     { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); }
 
   // Is the only link whose visitedness is allowed to influence the
   // style of the node this style context is for (which is that element
   // or its nearest ancestor that is a link) visited?
   PRBool RelevantLinkVisited() const
     { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); }
 
+  // Is this a style context for a link?
+  PRBool IsLinkContext() const {
+    return
+      GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent();
+  }
+
   // Is this style context the GetStyleIfVisited() for some other style
   // context?
   PRBool IsStyleIfVisited() const
     { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); }
 
   // Tells this style context that it should return true from
   // IsStyleIfVisited.
   void SetIsStyleIfVisited()
@@ -164,17 +170,17 @@ public:
   // calls until null is returned) is the same as |this|, since its
   // parent is either |this|'s parent or |this|'s parent's
   // style-if-visited.
   //
   // Structs on this context should never be examined without also
   // examining the corresponding struct on |this|.  Doing so will likely
   // both (1) lead to a privacy leak and (2) lead to dynamic change bugs
   // related to the Peek code in nsStyleContext::CalcStyleDifference.
-  nsStyleContext* GetStyleIfVisited()
+  nsStyleContext* GetStyleIfVisited() const
     { return mStyleIfVisited; }
 
   // To be called only from nsStyleSet.
   void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
   {
     NS_ABORT_IF_FALSE(!IsStyleIfVisited(), "this context is not visited data");
     NS_ABORT_IF_FALSE(aStyleIfVisited.get()->IsStyleIfVisited(),
                       "other context is visited data");
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -419,20 +419,16 @@ already_AddRefed<nsStyleContext>
 nsStyleSet::GetContext(nsStyleContext* aParentContext,
                        nsRuleNode* aRuleNode,
                        // aVisitedRuleNode may be null; if it is null
                        // it means that we don't need to force creation
                        // of a StyleIfVisited.  (But if we make one
                        // because aParentContext has one, then aRuleNode
                        // should be used.)
                        nsRuleNode* aVisitedRuleNode,
-                       // NB: ReparentStyleContext and
-                       // ResolveStyleByAddingRules pass bogus values
-                       // that work based on what this function is known
-                       // to do with aIsLink and aIsVisitedLink
                        PRBool aIsLink,
                        PRBool aIsVisitedLink,
                        nsIAtom* aPseudoTag,
                        nsCSSPseudoElements::Type aPseudoType)
 {
   NS_PRECONDITION((!aPseudoTag &&
                    aPseudoType ==
                      nsCSSPseudoElements::ePseudo_NotPseudoElement) ||
@@ -849,19 +845,18 @@ nsStyleSet::ResolveStyleByAddingRules(ns
     ruleWalker.SetCurrentNode(aBaseContext->GetStyleIfVisited()->GetRuleNode());
     for (PRInt32 i = 0; i < aRules.Count(); i++) {
       ruleWalker.Forward(aRules.ObjectAt(i));
     }
     visitedRuleNode = ruleWalker.CurrentNode();
   }
 
   return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
-                    // bogus values for aIsLink and aIsVisitedLink that
-                    // we know will make GetContext do the right thing.
-                    PR_TRUE, aBaseContext->RelevantLinkVisited(),
+                    aBaseContext->IsLinkContext(),
+                    aBaseContext->RelevantLinkVisited(),
                     aBaseContext->GetPseudo(),
                     aBaseContext->GetPseudoType());
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext)
 {
   return GetContext(aParentContext, mRuleTree, nsnull,
@@ -1148,24 +1143,32 @@ nsStyleSet::ReparentStyleContext(nsStyle
     return aStyleContext;
   }
 
   nsIAtom* pseudoTag = aStyleContext->GetPseudo();
   nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType();
   nsRuleNode* ruleNode = aStyleContext->GetRuleNode();
   nsRuleNode* visitedRuleNode = nsnull;
   nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
+  // Reparenting a style context just changes where we inherit from,
+  // not what rules we match or what our DOM looks like.  In
+  // particular, it doesn't change whether this is a style context for
+  // a link.
   if (visitedContext) {
      visitedRuleNode = visitedContext->GetRuleNode();
+     if (visitedRuleNode == ruleNode) {
+       // We don't want to force creation of an if-visited style
+       // context if it's not actually needed.
+       visitedRuleNode = nsnull;
+     }
   }
 
   return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
-                    // bogus values for aIsLink and aIsVisitedLink that
-                    // we know will make GetContext do the right thing.
-                    PR_TRUE, aStyleContext->RelevantLinkVisited(),
+                    aStyleContext->IsLinkContext(),
+                    aStyleContext->RelevantLinkVisited(),
                     pseudoTag, pseudoType);
 }
 
 struct StatefulData : public StateRuleProcessorData {
   StatefulData(nsPresContext* aPresContext,
                Element* aElement, PRInt32 aStateMask)
     : StateRuleProcessorData(aPresContext, aElement, aStateMask),
       mHint(nsRestyleHint(0))