Bug 508373 - Generated content may cause reference loops, r=roc
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 13 Aug 2009 22:29:42 +0300
changeset 31438 93a7af291db13ad00dfce9381a205228e1f4b466
parent 31437 8c402112ba9c814a93cf7d2578d18a82d9f611e8
child 31439 2625009724286b9408f45de494a3b83b52085597
push id8551
push useropettay@mozilla.com
push dateThu, 13 Aug 2009 19:33:56 +0000
treeherdermozilla-central@93a7af291db1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs508373
milestone1.9.3a1pre
Bug 508373 - Generated content may cause reference loops, r=roc
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -803,16 +803,18 @@ public:
   // together.
   PRPackedBool              mFixedPosIsAbsPos;
 
   // A boolean to indicate whether we have a "pending" popupgroup.  That is, we
   // have already created the FrameConstructionItem for the root popupgroup but
   // we have not yet created the relevant frame.
   PRPackedBool              mHavePendingPopupgroup;
 
+  nsCOMArray<nsIContent>    mGeneratedTextNodesWithInitializer;
+
   // Constructor
   // Use the passed-in history state.
   nsFrameConstructorState(nsIPresShell*          aPresShell,
                           nsIFrame*              aFixedContainingBlock,
                           nsIFrame*              aAbsoluteContainingBlock,
                           nsIFrame*              aFloatContainingBlock,
                           nsILayoutHistoryState* aHistoryState);
   // Get the history state from the pres context's pres shell.
@@ -978,16 +980,20 @@ nsFrameConstructorState::~nsFrameConstru
   // items whose containing block is outside the abs-pos frames. 
   MOZ_COUNT_DTOR(nsFrameConstructorState);
   ProcessFrameInsertions(mFloatedItems, nsGkAtoms::floatList);
   ProcessFrameInsertions(mAbsoluteItems, nsGkAtoms::absoluteList);
   ProcessFrameInsertions(mFixedItems, nsGkAtoms::fixedList);
 #ifdef MOZ_XUL
   ProcessFrameInsertions(mPopupItems, nsGkAtoms::popupList);
 #endif
+  for (PRInt32 i = mGeneratedTextNodesWithInitializer.Count() - 1; i >= 0; --i) {
+    mGeneratedTextNodesWithInitializer[i]->
+      DeleteProperty(nsGkAtoms::genConInitializerProperty);
+  }
 }
 
 static nsIFrame*
 AdjustAbsoluteContainingBlock(nsIFrame* aContainingBlockIn)
 {
   if (!aContainingBlockIn) {
     return nsnull;
   }
@@ -1638,17 +1644,18 @@ DestroyGenConInitializer(void*    aFrame
                          nsIAtom* aPropertyName,
                          void*    aPropertyValue,
                          void*    aDtorData)
 {
   delete static_cast<nsGenConInitializer*>(aPropertyValue);
 }
 
 already_AddRefed<nsIContent>
-nsCSSFrameConstructor::CreateGenConTextNode(const nsString& aString,
+nsCSSFrameConstructor::CreateGenConTextNode(nsFrameConstructorState& aState,
+                                            const nsString& aString,
                                             nsCOMPtr<nsIDOMCharacterData>* aText,
                                             nsGenConInitializer* aInitializer)
 {
   nsCOMPtr<nsIContent> content;
   NS_NewTextNode(getter_AddRefs(content), mDocument->NodeInfoManager());
   if (!content) {
     // XXX The quotes/counters code doesn't like the text pointer
     // being null in case of dynamic changes!
@@ -1657,22 +1664,24 @@ nsCSSFrameConstructor::CreateGenConTextN
   }
   content->SetText(aString, PR_FALSE);
   if (aText) {
     *aText = do_QueryInterface(content);
   }
   if (aInitializer) {
     content->SetProperty(nsGkAtoms::genConInitializerProperty, aInitializer,
                          DestroyGenConInitializer);
+    aState.mGeneratedTextNodesWithInitializer.AppendObject(content);
   }
   return content.forget();
 }
 
 already_AddRefed<nsIContent>
-nsCSSFrameConstructor::CreateGeneratedContent(nsIContent*     aParentContent,
+nsCSSFrameConstructor::CreateGeneratedContent(nsFrameConstructorState& aState,
+                                              nsIContent*     aParentContent,
                                               nsStyleContext* aStyleContext,
                                               PRUint32        aContentIndex)
 {
   // Get the content value
   const nsStyleContentData &data =
     aStyleContext->GetStyleContent()->ContentAt(aContentIndex);
   nsStyleContentType type = data.mType;
 
@@ -1693,18 +1702,19 @@ nsCSSFrameConstructor::CreateGeneratedCo
     nsCOMPtr<nsIContent> content;
     NS_NewGenConImageContent(getter_AddRefs(content), nodeInfo,
                              data.mContent.mImage);
     return content.forget();
   }
 
   switch (type) {
   case eStyleContentType_String:
-    return CreateGenConTextNode(nsDependentString(data.mContent.mString), nsnull,
-                                nsnull);
+    return CreateGenConTextNode(aState,
+                                nsDependentString(data.mContent.mString),
+                                nsnull, nsnull);
 
   case eStyleContentType_Attr:
     {
       nsCOMPtr<nsIAtom> attrName;
       PRInt32 attrNameSpace = kNameSpaceID_None;
       nsAutoString contentString(data.mContent.mString);
       PRInt32 barIndex = contentString.FindChar('|'); // CSS namespace delimiter
       if (-1 != barIndex) {
@@ -1744,17 +1754,18 @@ nsCSSFrameConstructor::CreateGeneratedCo
         new nsCounterUseNode(counters, aContentIndex,
                              type == eStyleContentType_Counters);
       if (!node)
         return nsnull;
 
       nsGenConInitializer* initializer =
         new nsGenConInitializer(node, counterList,
                                 &nsCSSFrameConstructor::CountersDirty);
-      return CreateGenConTextNode(EmptyString(), &node->mText, initializer);
+      return CreateGenConTextNode(aState, EmptyString(), &node->mText,
+                                  initializer);
     }
 
   case eStyleContentType_Image:
     NS_NOTREACHED("handled by if above");
     return nsnull;
 
   case eStyleContentType_OpenQuote:
   case eStyleContentType_CloseQuote:
@@ -1764,17 +1775,18 @@ nsCSSFrameConstructor::CreateGeneratedCo
       nsQuoteNode* node =
         new nsQuoteNode(type, aContentIndex);
       if (!node)
         return nsnull;
 
       nsGenConInitializer* initializer =
         new nsGenConInitializer(node, &mQuoteList,
                                 &nsCSSFrameConstructor::QuotesDirty);
-      return CreateGenConTextNode(EmptyString(), &node->mText, initializer);
+      return CreateGenConTextNode(aState, EmptyString(), &node->mText,
+                                  initializer);
     }
   
   case eStyleContentType_AltContent:
     {
       // Use the "alt" attribute; if that fails and the node is an HTML
       // <input>, try the value attribute and then fall back to some default
       // localized text we have.
       // XXX what if the 'alt' attribute is added later, how will we
@@ -1793,17 +1805,17 @@ nsCSSFrameConstructor::CreateGeneratedCo
           NS_NewAttributeContent(mDocument->NodeInfoManager(),
                                  kNameSpaceID_None, nsGkAtoms::value, getter_AddRefs(content));
           return content.forget();
         }
 
         nsXPIDLString temp;
         nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
                                            "Submit", temp);
-        return CreateGenConTextNode(temp, nsnull, nsnull);
+        return CreateGenConTextNode(aState, temp, nsnull, nsnull);
       }
 
       break;
     }
   } // switch
 
   return nsnull;
 }
@@ -1861,17 +1873,18 @@ nsCSSFrameConstructor::CreateGeneratedCo
   if (NS_FAILED(rv)) {
     container->UnbindFromTree();
     return;
   }
 
   PRUint32 contentCount = pseudoStyleContext->GetStyleContent()->ContentCount();
   for (PRUint32 contentIndex = 0; contentIndex < contentCount; contentIndex++) {
     nsCOMPtr<nsIContent> content =
-      CreateGeneratedContent(aParentContent, pseudoStyleContext, contentIndex);
+      CreateGeneratedContent(aState, aParentContent, pseudoStyleContext,
+                             contentIndex);
     if (content) {
       container->AppendChildTo(content, PR_FALSE);
     }
   }
 
   AddFrameConstructionItemsInternal(aState, container, aParentFrame, elemName,
                                     kNameSpaceID_None, -1, pseudoStyleContext,
                                     ITEM_IS_GENERATED_CONTENT, aItems);
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -458,30 +458,32 @@ private:
                                   nsCOMArray<nsIContent>& aGeneratedContent,
                                   nsIContent** aNewContent,
                                   nsIFrame** aNewFrame);
 
   /**
    * Create a text node containing the given string. If aText is non-null
    * then we also set aText to the returned node.
    */
-  already_AddRefed<nsIContent> CreateGenConTextNode(const nsString& aString,  
+  already_AddRefed<nsIContent> CreateGenConTextNode(nsFrameConstructorState& aState,
+                                                    const nsString& aString,
                                                     nsCOMPtr<nsIDOMCharacterData>* aText,
                                                     nsGenConInitializer* aInitializer);
 
   /**
    * Create a content node for the given generated content style.
    * The caller takes care of making it SetNativeAnonymous, binding it
    * to the document, and creating frames for it.
    * @param aParentContent is the node that has the before/after style
    * @param aStyleContext is the 'before' or 'after' pseudo-element
    * style context
    * @param aContentIndex is the index of the content item to create
    */
-  already_AddRefed<nsIContent> CreateGeneratedContent(nsIContent*     aParentContent,
+  already_AddRefed<nsIContent> CreateGeneratedContent(nsFrameConstructorState& aState,
+                                                      nsIContent*     aParentContent,
                                                       nsStyleContext* aStyleContext,
                                                       PRUint32        aContentIndex);
 
   // aFrame may be null; this method doesn't use it directly in any case.
   void CreateGeneratedContentItem(nsFrameConstructorState& aState,
                                   nsIFrame*                aFrame,
                                   nsIContent*              aContent,
                                   nsStyleContext*          aStyleContext,