Bug 386802, Mutation events always fired during setting of innerHTML, r+sr=bz

This commit is contained in:
Olli.Pettay%helsinki.fi 2007-07-04 20:39:11 +00:00
Родитель 7269d880ea
Коммит 5d525ee576
10 изменённых файлов: 50 добавлений и 26 удалений

Просмотреть файл

@ -780,14 +780,19 @@ public:
/**
* Quick helper to determine whether there are any mutation listeners
* of a given type that apply to this content or any of its ancestors.
* The method has the side effect to call document's MayDispatchMutationEvent
* using aTargetForSubtreeModified as the parameter.
*
* @param aNode The node to search for listeners
* @param aType The type of listener (NS_EVENT_BITS_MUTATION_*)
* @param aTargetForSubtreeModified The node which is the target of the
* possible DOMSubtreeModified event.
*
* @return true if there are mutation listeners of the specified type
*/
static PRBool HasMutationListeners(nsINode* aNode,
PRUint32 aType);
PRUint32 aType,
nsINode* aTargetForSubtreeModified);
/**
* This method creates and dispatches a trusted event.

Просмотреть файл

@ -95,8 +95,9 @@ class mozAutoSubtreeModified;
// IID for the nsIDocument interface
#define NS_IDOCUMENT_IID \
{ 0x7dd5790f, 0x110d, 0x4bf6, \
{ 0x83, 0x50, 0x4b, 0xe3, 0x5d, 0xdc, 0xe1, 0x1e } }
{ 0x6700e22b, 0x95b8, 0x44cf, \
{ 0x8f, 0x5a, 0x57, 0x2c, 0x14, 0x5b, 0xd1, 0xa1 } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -851,9 +852,13 @@ public:
virtual void FlushSkinBindings() = 0;
/**
* Returns PR_TRUE if one or more mutation events are being dispatched.
* To batch DOMSubtreeModified, document needs to be informed when
* a mutation event might be dispatched, even if the event isn't actually
* created because there are no listeners for it.
*
* @param aTarget is the target for the mutation event.
*/
virtual PRBool MutationEventBeingDispatched() = 0;
virtual void MayDispatchMutationEvent(nsINode* aTarget) = 0;
/**
* Marks as not-going-to-be-collected for the given generation of

Просмотреть файл

@ -2978,18 +2978,15 @@ nsContentUtils::HasNonEmptyAttr(nsIContent* aContent, PRInt32 aNameSpaceID,
/* static */
PRBool
nsContentUtils::HasMutationListeners(nsINode* aNode,
PRUint32 aType)
PRUint32 aType,
nsINode* aTargetForSubtreeModified)
{
nsIDocument* doc = aNode->GetOwnerDoc();
if (!doc) {
return PR_FALSE;
}
// To batch DOMSubtreeModified properly, all mutation events should be
// processed if one is being processed already.
if (doc->MutationEventBeingDispatched()) {
return PR_TRUE;
}
doc->MayDispatchMutationEvent(aTargetForSubtreeModified);
// global object will be null for documents that don't have windows.
nsCOMPtr<nsPIDOMWindow> window;

Просмотреть файл

@ -5662,6 +5662,14 @@ nsDocument::OnPageHide(PRBool aPersisted)
mVisible = PR_FALSE;
}
void
nsDocument::MayDispatchMutationEvent(nsINode* aTarget)
{
if (mSubtreeModifiedDepth > 0) {
mSubtreeModifiedTargets.AppendObject(aTarget);
}
}
void
nsDocument::WillDispatchMutationEvent(nsINode* aTarget)
{
@ -5670,7 +5678,12 @@ nsDocument::WillDispatchMutationEvent(nsINode* aTarget)
"mSubtreeModifiedTargets not cleared after dispatching?");
++mSubtreeModifiedDepth;
if (aTarget) {
mSubtreeModifiedTargets.AppendObject(aTarget);
// MayDispatchMutationEvent is often called just before this method,
// so it has already appended the node to mSubtreeModifiedTargets.
PRInt32 count = mSubtreeModifiedTargets.Count();
if (!count || mSubtreeModifiedTargets[count - 1] != aTarget) {
mSubtreeModifiedTargets.AppendObject(aTarget);
}
}
}

Просмотреть файл

@ -507,12 +507,9 @@ public:
virtual void OnPageShow(PRBool aPersisted);
virtual void OnPageHide(PRBool aPersisted);
virtual void MayDispatchMutationEvent(nsINode* aTarget);
virtual void WillDispatchMutationEvent(nsINode* aTarget);
virtual void MutationEventDispatched(nsINode* aTarget);
virtual PRBool MutationEventBeingDispatched()
{
return (mSubtreeModifiedDepth > 0);
}
// nsINode
virtual PRBool IsNodeOfType(PRUint32 aFlags) const;

Просмотреть файл

@ -409,7 +409,8 @@ nsGenericDOMDataNode::SetTextInternal(PRUint32 aOffset, PRUint32 aCount,
PRBool haveMutationListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED,
this);
nsCOMPtr<nsIAtom> oldValue;
if (haveMutationListeners) {

Просмотреть файл

@ -2637,7 +2637,7 @@ nsGenericElement::doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
}
if (nsContentUtils::HasMutationListeners(aKid,
NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
NS_EVENT_BITS_MUTATION_NODEINSERTED, container)) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEINSERTED);
mutation.mRelatedNode = do_QueryInterface(container);
mozAutoSubtreeModified subtree(container->GetOwnerDoc(), container);
@ -2688,7 +2688,7 @@ nsGenericElement::doRemoveChildAt(PRUint32 aIndex, PRBool aNotify,
mozAutoSubtreeModified subtree(nsnull, nsnull);
if (aNotify &&
nsContentUtils::HasMutationListeners(aKid,
NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
NS_EVENT_BITS_MUTATION_NODEREMOVED, container)) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEREMOVED);
mutation.mRelatedNode = do_QueryInterface(container);
subtree.UpdateTarget(container->GetOwnerDoc(), container);
@ -3521,7 +3521,8 @@ nsGenericElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
PRBool modification = PR_FALSE;
PRBool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
// If we have no listeners and aNotify is false, we are almost certainly
// coming from the content sink and will almost certainly have no previous
@ -3813,7 +3814,8 @@ nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
PRBool hasMutationListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
// Grab the attr node if needed before we remove it from the attr map
nsCOMPtr<nsIDOMAttr> attrNode;

Просмотреть файл

@ -1540,7 +1540,8 @@ nsGenericHTMLElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule,
PRBool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
// There's no point in comparing the stylerule pointers since we're always
// getting a new stylerule here. And we can't compare the stringvalues of

Просмотреть файл

@ -337,7 +337,8 @@ nsSVGElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify)
PRBool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
// There's no point in comparing the stylerule pointers since we're always
// getting a new stylerule here. And we can't compare the stringvalues of
@ -639,7 +640,8 @@ nsSVGElement::DidModifySVGObservable(nsISVGValue* aObservable,
PRBool modification = PR_FALSE;
PRBool hasListeners =
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
if (hasListeners || IsInDoc()) {
modification = !!mAttrsAndChildren.GetAttr(attrName->LocalName(),

Просмотреть файл

@ -1238,7 +1238,7 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
PRBool hasMutationListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
nsCOMPtr<nsIDOMAttr> attrNode;
if (hasMutationListeners) {
@ -1666,7 +1666,8 @@ nsXULElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify)
PRBool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
this);
// There's no point in comparing the stylerule pointers since we're always
// getting a new stylerule here. And we can't compare the stringvalues of