Bug 780199 - better mutationobserver handling when attribute value doesn't change, r=sicking

This commit is contained in:
Olli Pettay 2012-08-15 13:06:01 +03:00
parent a86157e431
commit 76fa88f9b3
8 changed files with 121 additions and 14 deletions

View File

@ -20,8 +20,8 @@ class Element;
} // namespace mozilla
#define NS_IMUTATION_OBSERVER_IID \
{ 0x85eea794, 0xed8e, 0x4e1b, \
{ 0xa1, 0x28, 0xd0, 0x93, 0x00, 0xae, 0x51, 0xaa } }
{ 0x16fe5e3e, 0xeadc, 0x4312, \
{ 0x9d, 0x44, 0xb6, 0xbe, 0xdd, 0x6b, 0x54, 0x74 } }
/**
* Information details about a characterdata change. Basically, we
@ -192,6 +192,20 @@ public:
nsIAtom* aAttribute,
PRInt32 aModType) = 0;
/**
* Notification that an attribute of an element has been
* set to the value it already had.
*
* @param aDocument The owner-document of aContent.
* @param aElement The element whose attribute changed
* @param aNameSpaceID The namespace id of the changed attribute
* @param aAttribute The name of the changed attribute
*/
virtual void AttributeSetToCurrentValue(nsIDocument* aDocument,
mozilla::dom::Element* aElement,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute) {}
/**
* Notification that one or more content nodes have been appended to the
* child list of another node in the tree.

View File

@ -21,6 +21,7 @@
#include "mozilla/dom/Element.h"
#include "nsClassHashtable.h"
#include "nsNodeUtils.h"
#include "nsIDOMMutationEvent.h"
class nsDOMMutationObserver;
@ -273,6 +274,16 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
virtual void AttributeSetToCurrentValue(nsIDocument* aDocument,
mozilla::dom::Element* aElement,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute)
{
// We can reuse AttributeWillChange implementation.
AttributeWillChange(aDocument, aElement, aNameSpaceID, aAttribute,
nsIDOMMutationEvent::MODIFICATION);
}
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsMutationReceiver, NS_MUTATION_OBSERVER_IID)

View File

@ -1883,13 +1883,7 @@ nsGenericElement::MaybeCheckSameAttrVal(PRInt32 aNamespaceID,
}
bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
if (valueMatches && aPrefix == info.mName->GetPrefix()) {
if (OwnerDoc()->MayHaveDOMMutationObservers()) {
// For backward compatibility, don't fire mutation events
// when setting an attribute to its old value.
*aHasListeners = false;
} else {
return true;
}
return true;
}
modification = true;
}
@ -1920,8 +1914,8 @@ nsGenericElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
nsAttrValueOrString value(aValue);
nsAttrValue oldValue;
if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify,
oldValue, &modType, &hasListeners)) {
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
oldValue, &modType, &hasListeners)) {
return NS_OK;
}
@ -1967,8 +1961,8 @@ nsGenericElement::SetParsedAttr(PRInt32 aNamespaceID, nsIAtom* aName,
nsAttrValueOrString value(aParsedValue);
nsAttrValue oldValue;
if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify,
oldValue, &modType, &hasListeners)) {
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
oldValue, &modType, &hasListeners)) {
return NS_OK;
}

View File

@ -36,7 +36,7 @@
#include "nsIInlineEventHandlers.h"
#include "mozilla/CORSMode.h"
#include "mozilla/Attributes.h"
#include "nsContentUtils.h"
#include "nsISMILAttr.h"
class nsIDOMAttr;
@ -102,6 +102,22 @@ public:
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
PRUint8* aModType, bool* aHasListeners);
bool OnlyNotifySameValueSet(PRInt32 aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix,
const nsAttrValueOrString& aValue,
bool aNotify, nsAttrValue& aOldValue,
PRUint8* aModType, bool* aHasListeners)
{
if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
aOldValue, aModType, aHasListeners)) {
nsAutoScriptBlocker scriptBlocker;
nsNodeUtils::AttributeSetToCurrentValue(this, aNamespaceID, aName);
return true;
}
return false;
}
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
const nsAString& aValue, bool aNotify);
virtual nsresult SetParsedAttr(PRInt32 aNameSpaceID, nsIAtom* aName,

View File

@ -108,6 +108,16 @@ nsNodeUtils::AttributeChanged(Element* aElement,
aModType));
}
void
nsNodeUtils::AttributeSetToCurrentValue(Element* aElement,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute)
{
nsIDocument* doc = aElement->OwnerDoc();
IMPL_MUTATION_NOTIFICATION(AttributeSetToCurrentValue, aElement,
(doc, aElement, aNameSpaceID, aAttribute));
}
void
nsNodeUtils::ContentAppended(nsIContent* aContainer,
nsIContent* aFirstNewContent,

View File

@ -64,6 +64,16 @@ public:
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType);
/**
* Send AttributeSetToCurrentValue notifications to nsIMutationObservers.
* @param aElement Element whose data changed
* @param aNameSpaceID Namespace of the attribute
* @param aAttribute Local-name of the attribute
* @see nsIMutationObserver::AttributeSetToCurrentValue
*/
static void AttributeSetToCurrentValue(mozilla::dom::Element* aElement,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute);
/**
* Send ContentAppended notifications to nsIMutationObservers

View File

@ -43,6 +43,7 @@ MOCHITEST_CHROME_FILES = \
test_bug752226-3.xul \
test_bug752226-4.xul \
test_bug682305.html \
test_bug780199.xul \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,51 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=780199
-->
<window title="Mozilla Bug 780199"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="test()">
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=780199"
target="_blank">Mozilla Bug 780199</a>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 780199 **/
SimpleTest.waitForExplicitFinish();
var b;
function callback(r) {
is(r[0].type, "attributes");
is(r[0].oldValue, b.getAttribute("src"));
setTimeout(continueTest, 500);
}
function continueTest() {
// Check that a new page wasn't loaded.
is(b.contentDocument.documentElement.textContent, "testvalue");
SimpleTest.finish();
}
function test() {
b = document.getElementById("b");
var m = MutationObserver(callback);
m.observe(b, { attributes: true, attributeOldValue: true });
b.contentDocument.documentElement.textContent = "testvalue";
b.setAttribute("src", b.getAttribute("src"));
}
]]>
</script>
<browser id="b" src="data:text/plain,initial"/>
</window>