Bug 470687, r=enndeakin, sr=neil, a=beltzner
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 14 Jan 2009 12:48:04 +0200
changeset 22817 1a72e7f44b09f66f9b5a9b01c890ff1cfcaee00c
parent 22816 f2c5086fceb28ca430d4a5a9c5e59729794220fd
child 22818 744228ccf0ad915a0bea428d9584936774a2d5c1
push id431
push useropettay@mozilla.com
push dateWed, 14 Jan 2009 10:48:20 +0000
reviewersenndeakin, neil, beltzner
bugs470687
milestone1.9.1b3pre
Bug 470687, r=enndeakin, sr=neil, a=beltzner
content/xul/document/src/nsXULDocument.cpp
content/xul/document/src/nsXULDocument.h
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -1016,33 +1016,46 @@ nsXULDocument::AttributeChanged(nsIDocum
                     static_cast<BroadcastListener*>(entry->mListeners[i]);
 
                 if ((bl->mAttribute == aAttribute) ||
                     (bl->mAttribute == nsGkAtoms::_asterix)) {
                     nsCOMPtr<nsIDOMElement> listenerEl
                         = do_QueryReferent(bl->mListener);
                     nsCOMPtr<nsIContent> l = do_QueryInterface(listenerEl);
                     if (l) {
-                      nsAutoString currentValue;
-                      PRBool hasAttr = l->GetAttr(kNameSpaceID_None,
-                                                  aAttribute,
-                                                  currentValue);
-                      // We need to update listener only if we're
-                      // (1) removing an existing attribute,
-                      // (2) adding a new attribute or
-                      // (3) changing the value of an attribute.
-                      PRBool needsAttrChange =
-                          attrSet != hasAttr || !value.Equals(currentValue);
-                      nsDelayedBroadcastUpdate delayedUpdate(domele,
-                                                             listenerEl,
-                                                             aAttribute,
-                                                             value,
-                                                             attrSet,
-                                                             needsAttrChange);
-                      mDelayedAttrChangeBroadcasts.AppendElement(delayedUpdate);
+                        PRBool possibleCycle = PR_FALSE;
+                        for (PRUint32 j = 0; j < mDelayedAttrChangeBroadcasts.Length(); ++j) {
+                            if (mDelayedAttrChangeBroadcasts[j].mListener == listenerEl &&
+                                mDelayedAttrChangeBroadcasts[j].mAttrName == aAttribute) {
+                                possibleCycle = PR_TRUE;
+                                break;
+                            }
+                        }
+
+                        if (possibleCycle) {
+                            NS_WARNING("Broadcasting loop!");
+                        } else {
+                            nsAutoString currentValue;
+                            PRBool hasAttr = l->GetAttr(kNameSpaceID_None,
+                                                        aAttribute,
+                                                        currentValue);
+                            // We need to update listener only if we're
+                            // (1) removing an existing attribute,
+                            // (2) adding a new attribute or
+                            // (3) changing the value of an attribute.
+                            PRBool needsAttrChange =
+                                attrSet != hasAttr || !value.Equals(currentValue);
+                            nsDelayedBroadcastUpdate delayedUpdate(domele,
+                                                                   listenerEl,
+                                                                   aAttribute,
+                                                                   value,
+                                                                   attrSet,
+                                                                   needsAttrChange);
+                            mDelayedAttrChangeBroadcasts.AppendElement(delayedUpdate);
+                        }
                     }
                 }
             }
         }
     }
 
     // checks for modifications in broadcasters
     PRBool listener, resolved;
@@ -3284,44 +3297,43 @@ nsXULDocument::StyleSheetLoaded(nsICSSSt
     return NS_OK;
 }
 
 void
 nsXULDocument::EndUpdate(nsUpdateType aUpdateType)
 {
     nsXMLDocument::EndUpdate(aUpdateType);
     if (mUpdateNestLevel == 0) {
-        PRUint32 length = mDelayedAttrChangeBroadcasts.Length();
-        if (length) {
-          nsTArray<nsDelayedBroadcastUpdate> delayedAttrChangeBroadcasts;
-            mDelayedAttrChangeBroadcasts.SwapElements(
-                                             delayedAttrChangeBroadcasts);
-            for (PRUint32 i = 0; i < length; ++i) {
-                nsIAtom* attrName = delayedAttrChangeBroadcasts[i].mAttrName;
-                if (delayedAttrChangeBroadcasts[i].mNeedsAttrChange) {
+        if (!mHandlingDelayedAttrChange) {
+            mHandlingDelayedAttrChange = PR_TRUE;
+            for (PRUint32 i = 0; i < mDelayedAttrChangeBroadcasts.Length(); ++i) {
+                nsIAtom* attrName = mDelayedAttrChangeBroadcasts[i].mAttrName;
+                if (mDelayedAttrChangeBroadcasts[i].mNeedsAttrChange) {
                     nsCOMPtr<nsIContent> listener =
-                        do_QueryInterface(delayedAttrChangeBroadcasts[i].mListener);
-                    nsString value = delayedAttrChangeBroadcasts[i].mAttr;
-                    if (delayedAttrChangeBroadcasts[i].mSetAttr) {
+                        do_QueryInterface(mDelayedAttrChangeBroadcasts[i].mListener);
+                    nsString value = mDelayedAttrChangeBroadcasts[i].mAttr;
+                    if (mDelayedAttrChangeBroadcasts[i].mSetAttr) {
                         listener->SetAttr(kNameSpaceID_None, attrName, value,
                                           PR_TRUE);
                     } else {
                         listener->UnsetAttr(kNameSpaceID_None, attrName,
                                             PR_TRUE);
                     }
                 }
                 nsCOMPtr<nsIContent> broadcaster =
-                    do_QueryInterface(delayedAttrChangeBroadcasts[i].mBroadcaster);
+                    do_QueryInterface(mDelayedAttrChangeBroadcasts[i].mBroadcaster);
                 ExecuteOnBroadcastHandlerFor(broadcaster,
-                                             delayedAttrChangeBroadcasts[i].mListener,
+                                             mDelayedAttrChangeBroadcasts[i].mListener,
                                              attrName);
             }
+            mDelayedAttrChangeBroadcasts.Clear();
+            mHandlingDelayedAttrChange = PR_FALSE;
         }
 
-        length = mDelayedBroadcasters.Length();
+        PRUint32 length = mDelayedBroadcasters.Length();
         if (length) {
             nsTArray<nsDelayedBroadcastUpdate> delayedBroadcasters;
             mDelayedBroadcasters.SwapElements(delayedBroadcasters);
             for (PRUint32 i = 0; i < length; ++i) {
                 SynchronizeBroadcastListener(delayedBroadcasters[i].mBroadcaster,
                                              delayedBroadcasters[i].mListener,
                                              delayedBroadcasters[i].mAttr);
             }
--- a/content/xul/document/src/nsXULDocument.h
+++ b/content/xul/document/src/nsXULDocument.h
@@ -729,14 +729,15 @@ protected:
       nsString                mAttr;
       nsCOMPtr<nsIAtom>       mAttrName;
       PRPackedBool            mSetAttr;
       PRPackedBool            mNeedsAttrChange;
     };
 
     nsTArray<nsDelayedBroadcastUpdate> mDelayedBroadcasters;
     nsTArray<nsDelayedBroadcastUpdate> mDelayedAttrChangeBroadcasts;
+    PRBool                             mHandlingDelayedAttrChange;
 private:
     // helpers
 
 };
 
 #endif // nsXULDocument_h__