Bug 90983: Don't fire mutation events during parsing, i.e. when aNotify is false. Also make us fire mutation events on nodes that are in an orphaned subtree. r/sr=jst

This commit is contained in:
cvshook%sicking.cc 2006-06-02 00:58:04 +00:00
Родитель 8bbb081e9b
Коммит 47a9061831
7 изменённых файлов: 135 добавлений и 161 удалений

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

@ -713,14 +713,12 @@ 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.
*
* @param aContent The node to search for listeners (null for documents)
* @param aDocument The current document of the node, from nsINode
* @param aType The type of listener (NS_EVENT_BITS_MUTATION_*)
* @param aNode The node to search for listeners
* @param aType The type of listener (NS_EVENT_BITS_MUTATION_*)
*
* @return true if there are mutation listeners of the specified type
*/
static PRBool HasMutationListeners(nsIContent* aContent,
nsIDocument* aDocument,
static PRBool HasMutationListeners(nsINode* aNode,
PRUint32 aType);
/**

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

@ -2776,44 +2776,19 @@ nsContentUtils::HasNonEmptyAttr(nsIContent* aContent, PRInt32 aNameSpaceID,
== nsIContent::ATTR_VALUE_NO_MATCH;
}
/**
* Quick helper to determine whether there are any mutation listeners
* of a given type that apply to the node passed in.
*
* @param aNode to check for listeners.
*
* @return true if there are mutation listeners.
*/
/* static */
PRBool
NodeHasMutationListeners(nsINode* aNode)
{
nsCOMPtr<nsIEventListenerManager> manager;
aNode->GetListenerManager(PR_FALSE, getter_AddRefs(manager));
if (manager) {
PRBool hasListeners = PR_FALSE;
manager->HasMutationListeners(&hasListeners);
return hasListeners;
}
return PR_FALSE;
}
/* static */
PRBool
nsContentUtils::HasMutationListeners(nsIContent* aContent,
nsIDocument* aDocument,
nsContentUtils::HasMutationListeners(nsINode* aNode,
PRUint32 aType)
{
NS_PRECONDITION(!aContent || aContent->GetCurrentDoc() == aDocument,
"Incorrect aDocument");
if (!aDocument) {
// We do not support event listeners on content not attached to documents.
nsIDocument* doc = aNode->GetOwnerDoc();
if (!doc) {
return PR_FALSE;
}
// global object will be null for documents that don't have windows.
nsCOMPtr<nsPIDOMWindow> window;
window = do_QueryInterface(aDocument->GetScriptGlobalObject());
window = do_QueryInterface(doc->GetScriptGlobalObject());
if (window && !window->HasMutationListeners(aType)) {
return PR_FALSE;
}
@ -2835,13 +2810,20 @@ nsContentUtils::HasMutationListeners(nsIContent* aContent,
// If we have a window, we know a mutation listener is registered, but it
// might not be in our chain. If we don't have a window, we might have a
// mutation listener. Check quickly to see.
for (nsIContent* curr = aContent; curr; curr = curr->GetParent()) {
if (NodeHasMutationListeners(curr)) {
return PR_TRUE;
while (aNode) {
nsCOMPtr<nsIEventListenerManager> manager;
aNode->GetListenerManager(PR_FALSE, getter_AddRefs(manager));
if (manager) {
PRBool hasListeners = PR_FALSE;
manager->HasMutationListeners(&hasListeners);
if (hasListeners) {
return PR_TRUE;
}
}
aNode = aNode->GetNodeParent();
}
return NodeHasMutationListeners(aDocument);
return PR_FALSE;
}
/* static */

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

@ -415,7 +415,6 @@ nsGenericDOMDataNode::AppendData(const nsAString& aData)
PRBool haveMutationListeners =
nsContentUtils::HasMutationListeners(this,
document,
NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
nsCOMPtr<nsIAtom> oldValue;
@ -983,9 +982,8 @@ nsGenericDOMDataNode::SetText(const PRUnichar* aBuffer,
nsIDocument *document = GetCurrentDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
PRBool haveMutationListeners =
PRBool haveMutationListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
document,
NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
nsCOMPtr<nsIAtom> oldValue;

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

@ -2239,10 +2239,11 @@ nsGenericElement::doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
// XXXbz What if the kid just moved us in the document? Scripts suck. We
// really need to stop running them while we're in the middle of modifying
// the DOM....
if (aDocument && aKid->GetCurrentDoc() == aDocument &&
(aParent ? aKid->GetNodeParent() == aParent :
aKid->GetNodeParent() == aDocument)) {
if (aNotify) {
nsINode* container = aParent ? NS_STATIC_CAST(nsINode*, aParent) :
NS_STATIC_CAST(nsINode*, aDocument);
if (aKid->GetNodeParent() == container) {
if (aNotify && aDocument) {
// Note that we always want to call ContentInserted when things are added
// as kids to documents
if (aParent && isAppend) {
@ -2251,11 +2252,9 @@ nsGenericElement::doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
aDocument->ContentInserted(aParent, aKid, aIndex);
}
}
PRBool hasListeners =
nsContentUtils::HasMutationListeners(aParent,
aDocument,
NS_EVENT_BITS_MUTATION_NODEINSERTED);
if (hasListeners) {
if (aNotify &&
nsContentUtils::HasMutationListeners(container,
NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEINSERTED);
mutation.mRelatedNode = do_QueryInterface(aParent);
nsEventDispatcher::Dispatch(aKid, nsnull, &mutation);
@ -2316,11 +2315,11 @@ nsGenericElement::doRemoveChildAt(PRUint32 aIndex, PRBool aNotify,
nsMutationGuard guard;
if (nsContentUtils::HasMutationListeners(aParent,
aDocument,
if (aNotify &&
nsContentUtils::HasMutationListeners(container,
NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEREMOVED);
mutation.mRelatedNode = do_QueryInterface(aParent);
mutation.mRelatedNode = do_QueryInterface(container);
nsEventDispatcher::Dispatch(aKid, nsnull, &mutation);
}
@ -3112,9 +3111,8 @@ nsGenericElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
nsAutoString oldValue;
PRBool modification = PR_FALSE;
PRBool hasListeners =
PRBool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
doc,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
// If we have no listeners and aNotify is false, we are almost certainly
@ -3202,32 +3200,32 @@ nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
if (binding) {
binding->AttributeChanged(aName, aNamespaceID, PR_FALSE, aNotify);
}
}
if (aFireMutation) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
if (aFireMutation) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
nsAutoString attrName;
aName->ToString(attrName);
nsCOMPtr<nsIDOMAttr> attrNode;
GetAttributeNode(attrName, getter_AddRefs(attrNode));
mutation.mRelatedNode = attrNode;
nsAutoString attrName;
aName->ToString(attrName);
nsCOMPtr<nsIDOMAttr> attrNode;
GetAttributeNode(attrName, getter_AddRefs(attrNode));
mutation.mRelatedNode = attrNode;
mutation.mAttrName = aName;
nsAutoString newValue;
GetAttr(aNamespaceID, aName, newValue);
if (!newValue.IsEmpty()) {
mutation.mNewAttrValue = do_GetAtom(newValue);
}
if (!aOldValue.IsEmpty()) {
mutation.mPrevAttrValue = do_GetAtom(aOldValue);
}
mutation.mAttrChange = modType;
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
mutation.mAttrName = aName;
nsAutoString newValue;
GetAttr(aNamespaceID, aName, newValue);
if (!newValue.IsEmpty()) {
mutation.mNewAttrValue = do_GetAtom(newValue);
}
if (aNotify) {
document->AttributeChanged(this, aNamespaceID, aName, modType);
if (!aOldValue.IsEmpty()) {
mutation.mPrevAttrValue = do_GetAtom(aOldValue);
}
mutation.mAttrChange = modType;
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
}
if (document && aNotify) {
document->AttributeChanged(this, aNamespaceID, aName, modType);
}
if (aNamespaceID == kNameSpaceID_XMLEvents &&
@ -3399,34 +3397,31 @@ nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
if (aNotify) {
document->AttributeWillChange(this, aNameSpaceID, aName);
}
}
PRBool hasListeners =
nsContentUtils::HasMutationListeners(this,
document,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
if (hasListeners) {
nsCOMPtr<nsIDOMEventTarget> node =
do_QueryInterface(NS_STATIC_CAST(nsIContent *, this));
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
if (aNotify && nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED)) {
nsCOMPtr<nsIDOMEventTarget> node =
do_QueryInterface(NS_STATIC_CAST(nsIContent *, this));
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
nsAutoString attrName;
aName->ToString(attrName);
nsCOMPtr<nsIDOMAttr> attrNode;
GetAttributeNode(attrName, getter_AddRefs(attrNode));
mutation.mRelatedNode = attrNode;
mutation.mAttrName = aName;
nsAutoString attrName;
aName->ToString(attrName);
nsCOMPtr<nsIDOMAttr> attrNode;
GetAttributeNode(attrName, getter_AddRefs(attrNode));
mutation.mRelatedNode = attrNode;
mutation.mAttrName = aName;
nsAutoString value;
// It sucks that we have to call GetAttr here, but HTML can't always
// get the value from the nsAttrAndChildArray. Specifically enums and
// nsISupports can't be converted to strings.
GetAttr(aNameSpaceID, aName, value);
if (!value.IsEmpty())
mutation.mPrevAttrValue = do_GetAtom(value);
mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
nsAutoString value;
// It sucks that we have to call GetAttr here, but HTML can't always
// get the value from the nsAttrAndChildArray. Specifically enums and
// nsISupports can't be converted to strings.
GetAttr(aNameSpaceID, aName, value);
if (!value.IsEmpty())
mutation.mPrevAttrValue = do_GetAtom(value);
mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
}
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
}
// Clear binding to nsIDOMNamedNodeMap

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

@ -1755,14 +1755,12 @@ nsresult
nsGenericHTMLElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule,
PRBool aNotify)
{
PRBool hasListeners = PR_FALSE;
PRBool modification = PR_FALSE;
nsAutoString oldValueStr;
nsIDocument* document = GetCurrentDoc();
hasListeners = nsContentUtils::HasMutationListeners(this,
document,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
PRBool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
// 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
@ -1775,7 +1773,7 @@ nsGenericHTMLElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule,
modification = GetAttr(kNameSpaceID_None, nsHTMLAtoms::style,
oldValueStr);
}
else if (aNotify) {
else if (aNotify && IsInDoc()) {
modification = !!mAttrsAndChildren.GetAttr(nsHTMLAtoms::style);
}

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

@ -320,35 +320,32 @@ nsSVGElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
NS_IMETHODIMP
nsSVGElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify)
{
PRBool hasListeners = PR_FALSE;
PRBool modification = PR_FALSE;
nsAutoString oldValueStr;
nsIDocument* document = GetCurrentDoc();
hasListeners = nsContentUtils::HasMutationListeners(this,
document,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
PRBool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
// 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
// the old and the new rules since both will point to the same declaration
// and thus will be the same.
if (hasListeners || aNotify) {
if (hasListeners) {
// save the old attribute so we can set up the mutation event properly
const nsAttrValue* value = mAttrsAndChildren.GetAttr(nsSVGAtoms::style);
if (value) {
modification = PR_TRUE;
if (hasListeners) {
value->ToString(oldValueStr);
}
}
// XXXbz if the old rule points to the same declaration as the new one,
// this is getting the new attr value, not the old one....
modification = GetAttr(kNameSpaceID_None, nsHTMLAtoms::style,
oldValueStr);
}
else if (aNotify && IsInDoc()) {
modification = !!mAttrsAndChildren.GetAttr(nsHTMLAtoms::style);
}
nsAttrValue attrValue(aStyleRule);
return SetAttrAndNotify(kNameSpaceID_None, nsSVGAtoms::style, nsnull,
oldValueStr, attrValue, modification, hasListeners,
aNotify);
return SetAttrAndNotify(kNameSpaceID_None, nsHTMLAtoms::style, nsnull, oldValueStr,
attrValue, modification, hasListeners, aNotify);
}
nsICSSStyleRule*
@ -614,14 +611,14 @@ nsSVGElement::DidModifySVGObservable(nsISVGValue* aObservable,
const nsAttrName* attrName = mMappedAttributes.AttrNameAt(i);
PRBool modification = PR_FALSE;
PRBool hasListeners = PR_FALSE;
PRBool hasListeners =
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
nsIDocument* document = GetCurrentDoc();
if (document) {
if (hasListeners || IsInDoc()) {
modification = !!mAttrsAndChildren.GetAttr(attrName->LocalName(),
attrName->NamespaceID());
hasListeners = nsContentUtils::HasMutationListeners(this,
document,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
}
nsAttrValue newValue(aObservable);

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

@ -1379,9 +1379,10 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
doc->AttributeWillChange(this, aNameSpaceID, aName);
}
PRBool hasMutationListeners = nsContentUtils::HasMutationListeners(this,
doc,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
PRBool hasMutationListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
nsCOMPtr<nsIDOMAttr> attrNode;
if (hasMutationListeners) {
nsAutoString attrName;
@ -1436,21 +1437,21 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
}
}
if (hasMutationListeners) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
mutation.mRelatedNode = attrNode;
mutation.mAttrName = aName;
if (!oldValue.IsEmpty())
mutation.mPrevAttrValue = do_GetAtom(oldValue);
mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
nsEventDispatcher::Dispatch(NS_STATIC_CAST(nsIContent*, this),
nsnull, &mutation);
}
if (doc) {
if (hasMutationListeners) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
mutation.mRelatedNode = attrNode;
mutation.mAttrName = aName;
if (!oldValue.IsEmpty())
mutation.mPrevAttrValue = do_GetAtom(oldValue);
mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
nsEventDispatcher::Dispatch(NS_STATIC_CAST(nsIContent*, this),
nsnull, &mutation);
}
nsXBLBinding *binding = doc->BindingManager()->GetBinding(this);
if (binding)
binding->AttributeChanged(aName, aNameSpaceID, PR_TRUE, aNotify);
@ -1918,27 +1919,32 @@ nsXULElement::GetInlineStyleRule()
NS_IMETHODIMP
nsXULElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify)
{
PRBool hasListeners = PR_FALSE;
PRBool modification = PR_FALSE;
nsAutoString oldValueStr;
PRBool modification = PR_FALSE;
nsAutoString oldValueStr;
nsIDocument* document = GetCurrentDoc();
hasListeners = nsContentUtils::HasMutationListeners(this,
document,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
PRBool hasListeners = aNotify &&
nsContentUtils::HasMutationListeners(this,
NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
// We can't compare the stringvalues of the old and the new rules
// since both will point to the same declaration and thus will be
// the same.
if (hasListeners || aNotify) {
modification = !!mAttrsAndChildren.GetAttr(nsXULAtoms::style);
}
// 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
// the old and the new rules since both will point to the same declaration
// and thus will be the same.
if (hasListeners) {
// save the old attribute so we can set up the mutation event properly
// XXXbz if the old rule points to the same declaration as the new one,
// this is getting the new attr value, not the old one....
modification = GetAttr(kNameSpaceID_None, nsHTMLAtoms::style,
oldValueStr);
}
else if (aNotify && IsInDoc()) {
modification = !!mAttrsAndChildren.GetAttr(nsHTMLAtoms::style);
}
nsAttrValue attrValue(aStyleRule);
nsAttrValue attrValue(aStyleRule);
return SetAttrAndNotify(kNameSpaceID_None, nsXULAtoms::style, nsnull,
oldValueStr, attrValue, modification, hasListeners,
aNotify);
return SetAttrAndNotify(kNameSpaceID_None, nsHTMLAtoms::style, nsnull, oldValueStr,
attrValue, modification, hasListeners, aNotify);
}
nsChangeHint