Bug 467005. Be smarter about our removable script blockers. r=sicking
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 19 Nov 2009 14:37:00 -0500
changeset 33067 de79f09e0ee5e8ec16d4a351ad4b6bded1a3b618
parent 33066 4546ea430ba5cecdab5d4c41322ffdc2bbb58a6f
child 33068 1d93cf3812b6e9de4d88d2115d85d82025e04fff
push id748
push userbzbarsky@mozilla.com
push dateThu, 19 Nov 2009 19:37:19 +0000
reviewerssicking
bugs467005
milestone1.9.2b4pre
Bug 467005. Be smarter about our removable script blockers. r=sicking
content/base/public/nsContentUtils.h
content/base/public/nsIDocument.h
content/base/src/nsContentSink.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDOMAttribute.cpp
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsGenericDOMDataNode.cpp
content/base/src/nsGenericElement.cpp
content/xul/content/src/nsXULElement.cpp
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -65,16 +65,17 @@ struct nsNativeKeyEvent; // Don't includ
 
 class nsIDOMScriptObjectFactory;
 class nsIXPConnect;
 class nsINode;
 class nsIContent;
 class nsIDOMNode;
 class nsIDOMKeyEvent;
 class nsIDocument;
+class nsIDocumentObserver;
 class nsIDocShell;
 class nsINameSpaceManager;
 class nsIScriptSecurityManager;
 class nsIJSContextStack;
 class nsIThreadJSContextStack;
 class nsIParserService;
 class nsIIOService;
 class nsIURI;
@@ -1648,37 +1649,23 @@ public:
   ~nsAutoScriptBlocker() {
     nsContentUtils::RemoveScriptBlocker();
   }
 };
 
 class mozAutoRemovableBlockerRemover
 {
 public:
-  mozAutoRemovableBlockerRemover()
-  {
-    mNestingLevel = nsContentUtils::GetRemovableScriptBlockerLevel();
-    for (PRUint32 i = 0; i < mNestingLevel; ++i) {
-      nsContentUtils::RemoveRemovableScriptBlocker();
-    }
-
-    NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "killing mutation events");
-  }
-
-  ~mozAutoRemovableBlockerRemover()
-  {
-    NS_ASSERTION(nsContentUtils::GetRemovableScriptBlockerLevel() == 0,
-                 "Should have had none");
-    for (PRUint32 i = 0; i < mNestingLevel; ++i) {
-      nsContentUtils::AddRemovableScriptBlocker();
-    }
-  }
+  mozAutoRemovableBlockerRemover(nsIDocument* aDocument);
+  ~mozAutoRemovableBlockerRemover();
 
 private:
   PRUint32 mNestingLevel;
+  nsCOMPtr<nsIDocument> mDocument;
+  nsCOMPtr<nsIDocumentObserver> mObserver;
 };
 
 #define NS_AUTO_GCROOT_PASTE2(tok,line) tok##line
 #define NS_AUTO_GCROOT_PASTE(tok,line) \
   NS_AUTO_GCROOT_PASTE2(tok,line)
 #define NS_AUTO_GCROOT(ptr, result) \ \
   nsAutoGCRoot NS_AUTO_GCROOT_PASTE(_autoGCRoot_, __LINE__) \
   (ptr, result)
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1314,16 +1314,29 @@ protected:
   // go to.
   nsCOMPtr<nsIDocument> mDisplayDocument;
 
   PRUint32 mEventsSuppressed;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
 
+#define NS_IDOCUMENT_MOZILLA_1_9_2_BRANCH_IID               \
+  { 0x149e42ac, 0x0d6d, 0x4eaf,                             \
+      { 0x9a, 0x99, 0xc3, 0x69, 0x8d, 0x8f, 0xee, 0x2c } }
+class nsIDocument_MOZILLA_1_9_2_BRANCH : public nsISupports {
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_MOZILLA_1_9_2_BRANCH_IID)
+
+  virtual nsISupports* GetCurrentContentSink() = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument_MOZILLA_1_9_2_BRANCH,
+                              NS_IDOCUMENT_MOZILLA_1_9_2_BRANCH_IID)
+
 /**
  * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
  * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
  * object is deleted.
  */
 class NS_STACK_CLASS mozAutoSubtreeModified
 {
 public:
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -1595,17 +1595,17 @@ nsContentSink::FavorPerformanceHint(PRBo
   if (appShell)
     appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
 }
 
 void
 nsContentSink::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
 {
   // Remember nested updates from updates that we started.
-  if (mInNotification && mUpdatesInNotification < 2) {
+  if (mInNotification > 0 && mUpdatesInNotification < 2) {
     ++mUpdatesInNotification;
   }
 
   // If we're in a script and we didn't do the notification,
   // something else in the script processing caused the
   // notification to occur. Since this could result in frame
   // creation, make sure we've flushed everything before we
   // continue.
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5126,8 +5126,39 @@ nsContentUtils::DispatchXULCommand(nsICo
     return aShell->HandleDOMEventWithTarget(aTarget, event, &status);
   }
 
   nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(aTarget);
   NS_ENSURE_STATE(target);
   PRBool dummy;
   return target->DispatchEvent(event, &dummy);
 }
+
+mozAutoRemovableBlockerRemover::mozAutoRemovableBlockerRemover(nsIDocument* aDocument)
+{
+  mNestingLevel = nsContentUtils::GetRemovableScriptBlockerLevel();
+  mDocument = aDocument;
+  nsCOMPtr<nsIDocument_MOZILLA_1_9_2_BRANCH> branchDocument =
+    do_QueryInterface(aDocument);
+  nsISupports* sink =
+    branchDocument ? branchDocument->GetCurrentContentSink() : nsnull;
+  mObserver = do_QueryInterface(sink);
+  for (PRUint32 i = 0; i < mNestingLevel; ++i) {
+    if (mObserver) {
+      mObserver->EndUpdate(mDocument, UPDATE_CONTENT_MODEL);
+    }
+    nsContentUtils::RemoveRemovableScriptBlocker();
+  }
+
+  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "killing mutation events");
+}
+
+mozAutoRemovableBlockerRemover::~mozAutoRemovableBlockerRemover()
+{
+  NS_ASSERTION(nsContentUtils::GetRemovableScriptBlockerLevel() == 0,
+               "Should have had none");
+  for (PRUint32 i = 0; i < mNestingLevel; ++i) {
+    nsContentUtils::AddRemovableScriptBlocker();
+    if (mObserver) {
+      mObserver->BeginUpdate(mDocument, UPDATE_CONTENT_MODEL);
+    }
+  }
+}
--- a/content/base/src/nsDOMAttribute.cpp
+++ b/content/base/src/nsDOMAttribute.cpp
@@ -718,17 +718,17 @@ nsDOMAttribute::RemoveChildAt(PRUint32 a
   mozAutoDocUpdate updateBatch(GetOwnerDoc(), UPDATE_CONTENT_MODEL, aNotify);
   nsMutationGuard guard;
 
   mozAutoSubtreeModified subtree(nsnull, nsnull);
   if (aNotify &&
       nsContentUtils::HasMutationListeners(mChild,
                                            NS_EVENT_BITS_MUTATION_NODEREMOVED,
                                            this)) {
-    mozAutoRemovableBlockerRemover blockerRemover;
+    mozAutoRemovableBlockerRemover blockerRemover(GetOwnerDoc());
     nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEREMOVED);
     mutation.mRelatedNode =
       do_QueryInterface(static_cast<nsIAttribute*>(this));
     subtree.UpdateTarget(GetOwnerDoc(), this);
     nsEventDispatcher::Dispatch(mChild, nsnull, &mutation);
   }
   if (guard.Mutated(0) && mChild != child) {
     return NS_OK;
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1623,16 +1623,17 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNSEventTarget)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsPIDOMEventTarget)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsISupportsWeakReference)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNodeSelector)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMXPathNSResolver)
+    NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocument_MOZILLA_1_9_2_BRANCH)
   NS_OFFSET_AND_INTERFACE_TABLE_END
   NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDocument)
   if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
       aIID.Equals(NS_GET_IID(nsIXPathEvaluatorInternal))) {
     if (!mXPathEvaluatorTearoff) {
       nsresult rv;
       mXPathEvaluatorTearoff =
@@ -7274,17 +7275,17 @@ nsDocument::MutationEventDispatched(nsIN
         realTargets.AppendObject(possibleTarget);
       }
     }
 
     mSubtreeModifiedTargets.Clear();
 
     PRInt32 realTargetCount = realTargets.Count();
     for (PRInt32 k = 0; k < realTargetCount; ++k) {
-      mozAutoRemovableBlockerRemover blockerRemover;
+      mozAutoRemovableBlockerRemover blockerRemover(this);
 
       nsMutationEvent mutation(PR_TRUE, NS_MUTATION_SUBTREEMODIFIED);
       nsEventDispatcher::Dispatch(realTargets[k], nsnull, &mutation);
     }
   }
 }
 
 static PRUint32 GetURIHash(nsIURI* aURI)
@@ -7607,16 +7608,22 @@ nsDocument::UnsuppressEventHandlingAndFi
 
   if (aFireEvents) {
     NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(documents));
   } else {
     FireOrClearDelayedEvents(documents, PR_FALSE);
   }
 }
 
+nsISupports*
+nsDocument::GetCurrentContentSink()
+{
+  return mParser ? mParser->GetContentSink() : nsnull;
+}
+
 void
 nsIDocument::RegisterFreezableElement(nsIContent* aContent)
 {
   if (!mFreezableElements) {
     mFreezableElements = new nsTHashtable<nsPtrHashKey<nsIContent> >();
     if (!mFreezableElements)
       return;
     mFreezableElements->Init();
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -572,17 +572,18 @@ class nsDocument : public nsIDocument,
                    public nsIDOMEventTarget,
                    public nsIDOM3EventTarget,
                    public nsIDOMNSEventTarget,
                    public nsIScriptObjectPrincipal,
                    public nsIRadioGroupContainer,
                    public nsIDOMNodeSelector,
                    public nsIApplicationCacheContainer,
                    public nsIDOMXPathNSResolver,
-                   public nsStubMutationObserver
+                   public nsStubMutationObserver,
+                   public nsIDocument_MOZILLA_1_9_2_BRANCH
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup);
   virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
                           nsIPrincipal* aPrincipal);
 
@@ -1005,16 +1006,19 @@ public:
 
   nsresult CloneDocHelper(nsDocument* clone) const;
 
   void MaybeInitializeFinalizeFrameLoaders();
 
   void MaybeEndOutermostXBLUpdate();
 
   virtual void MaybePreLoadImage(nsIURI* uri);
+
+  virtual nsISupports* GetCurrentContentSink();
+
 protected:
 
   void RegisterNamedItems(nsIContent *aContent);
   void UnregisterNamedItems(nsIContent *aContent);
   void UpdateNameTableEntry(nsIContent *aContent);
   void UpdateIdTableEntry(nsIContent *aContent);
   void RemoveFromNameTable(nsIContent *aContent);
   void RemoveFromIdTable(nsIContent *aContent);
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -436,17 +436,17 @@ nsGenericDOMDataNode::SetTextInternal(PR
       aOffset == textLength,
       aOffset,
       endOffset,
       aLength
     };
     nsNodeUtils::CharacterDataChanged(this, &info);
 
     if (haveMutationListeners) {
-      mozAutoRemovableBlockerRemover blockerRemover;
+      mozAutoRemovableBlockerRemover blockerRemover(GetOwnerDoc());
 
       nsMutationEvent mutation(PR_TRUE, NS_MUTATION_CHARACTERDATAMODIFIED);
 
       mutation.mPrevAttrValue = oldValue;
       if (aLength > 0) {
         nsAutoString val;
         mText.AppendTo(val);
         mutation.mNewAttrValue = do_GetAtom(val);
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -3239,17 +3239,17 @@ nsGenericElement::doInsertChildAt(nsICon
     if (aParent && isAppend) {
       nsNodeUtils::ContentAppended(aParent, aIndex);
     } else {
       nsNodeUtils::ContentInserted(container, aKid, aIndex);
     }
 
     if (nsContentUtils::HasMutationListeners(aKid,
           NS_EVENT_BITS_MUTATION_NODEINSERTED, container)) {
-      mozAutoRemovableBlockerRemover blockerRemover;
+      mozAutoRemovableBlockerRemover blockerRemover(container->GetOwnerDoc());
       
       nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEINSERTED);
       mutation.mRelatedNode = do_QueryInterface(container);
 
       mozAutoSubtreeModified subtree(container->GetOwnerDoc(), container);
       nsEventDispatcher::Dispatch(aKid, nsnull, &mutation);
     }
   }
@@ -3311,17 +3311,17 @@ nsGenericElement::doRemoveChildAt(PRUint
 
   nsMutationGuard guard;
 
   mozAutoSubtreeModified subtree(nsnull, nsnull);
   if (aNotify &&
       aMutationEvent &&
       nsContentUtils::HasMutationListeners(aKid,
         NS_EVENT_BITS_MUTATION_NODEREMOVED, container)) {
-    mozAutoRemovableBlockerRemover blockerRemover;
+    mozAutoRemovableBlockerRemover blockerRemover(container->GetOwnerDoc());
 
     nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEREMOVED);
     mutation.mRelatedNode = do_QueryInterface(container);
 
     subtree.UpdateTarget(container->GetOwnerDoc(), container);
     nsEventDispatcher::Dispatch(aKid, nsnull, &mutation);
   }
 
@@ -3877,17 +3877,17 @@ nsGenericElement::doReplaceOrInsertBefor
     if (doc && (window = doc->GetInnerWindow()) &&
         window->HasMutationListeners(NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
 
       for (i = 0; i < count; ++i, ++insPos) {
         nsIContent* childContent = fragChildren[i];
 
         if (nsContentUtils::HasMutationListeners(childContent,
               NS_EVENT_BITS_MUTATION_NODEINSERTED, container)) {
-          mozAutoRemovableBlockerRemover blockerRemover;
+          mozAutoRemovableBlockerRemover blockerRemover(container->GetOwnerDoc());
 
           nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEINSERTED);
           mutation.mRelatedNode = do_QueryInterface(container);
 
           mozAutoSubtreeModified subtree(container->GetOwnerDoc(), container);
           nsEventDispatcher::Dispatch(childContent, nsnull, &mutation);
         }
       }
@@ -4379,17 +4379,17 @@ nsGenericElement::SetAttrAndNotify(PRInt
     mNodeInfo->GetDocument()->AddXMLEventsContent(this);
   }
   if (aValueForAfterSetAttr) {
     rv = AfterSetAttr(aNamespaceID, aName, aValueForAfterSetAttr, aNotify);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aFireMutation) {
-    mozAutoRemovableBlockerRemover blockerRemover;
+    mozAutoRemovableBlockerRemover blockerRemover(GetOwnerDoc());
     
     nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
 
     nsAutoString attrName;
     aName->ToString(attrName);
     nsCOMPtr<nsIDOMAttr> attrNode;
     nsAutoString ns;
     nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
@@ -4635,17 +4635,17 @@ nsGenericElement::UnsetAttr(PRInt32 aNam
                                   nsIDOMMutationEvent::REMOVAL,
                                   stateMask);
   }
 
   rv = AfterSetAttr(aNameSpaceID, aName, nsnull, aNotify);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (hasMutationListeners) {
-    mozAutoRemovableBlockerRemover blockerRemover;
+    mozAutoRemovableBlockerRemover blockerRemover(GetOwnerDoc());
 
     nsCOMPtr<nsIDOMEventTarget> node =
       do_QueryInterface(static_cast<nsIContent *>(this));
     nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
 
     mutation.mRelatedNode = attrNode;
     mutation.mAttrName = aName;
 
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1432,17 +1432,17 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpa
             doc->ContentStatesChanged(this, nsnull, stateMask);
         }
         nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
                                       nsIDOMMutationEvent::REMOVAL,
                                       stateMask);
     }
 
     if (hasMutationListeners) {
-        mozAutoRemovableBlockerRemover blockerRemover;
+        mozAutoRemovableBlockerRemover blockerRemover(GetOwnerDoc());
 
         nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
 
         mutation.mRelatedNode = attrNode;
         mutation.mAttrName = aName;
 
         if (!oldValue.IsEmpty())
           mutation.mPrevAttrValue = do_GetAtom(oldValue);