зеркало из https://github.com/mozilla/pjs.git
Update the binding manager before doing any other notifications, and don't
notify the document for nodes not in the document. Bug 398492, r+sr=sicking.
This commit is contained in:
Родитель
e13d925dba
Коммит
2f1107aac1
|
@ -882,7 +882,10 @@ nsDocument::~nsDocument()
|
|||
mStyleAttrStyleSheet->SetOwningDocument(nsnull);
|
||||
}
|
||||
|
||||
NS_IF_RELEASE(mBindingManager);
|
||||
if (mBindingManager) {
|
||||
mBindingManager->DropDocumentReference();
|
||||
NS_RELEASE(mBindingManager);
|
||||
}
|
||||
|
||||
delete mHeaderData;
|
||||
delete mBoxObjectTable;
|
||||
|
@ -1103,12 +1106,8 @@ nsDocument::Init()
|
|||
NS_ENSURE_TRUE(bindingManager, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(mBindingManager = bindingManager);
|
||||
|
||||
// The binding manager needs to come before everything but us in our
|
||||
// mutation observer list.
|
||||
nsINode::nsSlots* slots = GetSlots();
|
||||
NS_ENSURE_TRUE(slots &&
|
||||
slots->mMutationObservers.PrependObserver(bindingManager),
|
||||
NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ENSURE_TRUE(slots,NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Prepend self as mutation-observer whether we need it or not (some
|
||||
// subclasses currently do, other don't). This is because the code in
|
||||
|
@ -2678,18 +2677,6 @@ nsDocument::ScriptLoader()
|
|||
return mScriptLoader;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::AddMutationObserver(nsIMutationObserver* aMutationObserver)
|
||||
{
|
||||
mBindingManager->AddObserver(aMutationObserver);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RemoveMutationObserver(nsIMutationObserver* aMutationObserver)
|
||||
{
|
||||
mBindingManager->RemoveObserver(aMutationObserver);
|
||||
}
|
||||
|
||||
// Note: We don't hold a reference to the document observer; we assume
|
||||
// that it has a live reference to the document.
|
||||
void
|
||||
|
|
|
@ -456,9 +456,6 @@ public:
|
|||
*/
|
||||
virtual nsScriptLoader* ScriptLoader();
|
||||
|
||||
virtual void AddMutationObserver(nsIMutationObserver* aObserver);
|
||||
virtual void RemoveMutationObserver(nsIMutationObserver* aMutationObserver);
|
||||
|
||||
/**
|
||||
* Add a new observer of document change notifications. Whenever
|
||||
* content is changed, appended, inserted or removed the observers are
|
||||
|
|
|
@ -54,10 +54,16 @@
|
|||
#include "nsXULElement.h"
|
||||
#endif
|
||||
|
||||
// This macro expects the ownerDocument of content_ to be in scope as
|
||||
// |nsIDocument* doc|
|
||||
#define IMPL_MUTATION_NOTIFICATION(func_, content_, params_) \
|
||||
PR_BEGIN_MACRO \
|
||||
nsINode* node = content_; \
|
||||
nsINode* prev; \
|
||||
NS_ASSERTION(node->GetOwnerDoc() == doc, "Bogus document"); \
|
||||
if (doc) { \
|
||||
static_cast<nsIMutationObserver*>(doc->BindingManager())-> \
|
||||
func_ params_; \
|
||||
} \
|
||||
do { \
|
||||
nsINode::nsSlots* slots = node->GetExistingSlots(); \
|
||||
if (slots && !slots->mMutationObservers.IsEmpty()) { \
|
||||
|
@ -67,14 +73,7 @@
|
|||
slots->mMutationObservers, nsIMutationObserver, \
|
||||
func_, params_); \
|
||||
} \
|
||||
prev = node; \
|
||||
node = node->GetNodeParent(); \
|
||||
\
|
||||
if (!node && prev->HasFlag(NODE_FORCE_XBL_BINDINGS)) { \
|
||||
/* For elements that have the NODE_FORCE_XBL_BINDINGS flag \
|
||||
set we need to notify the document */ \
|
||||
node = prev->GetOwnerDoc(); \
|
||||
} \
|
||||
} while (node); \
|
||||
PR_END_MACRO
|
||||
|
||||
|
@ -114,10 +113,10 @@ void
|
|||
nsNodeUtils::ContentAppended(nsIContent* aContainer,
|
||||
PRInt32 aNewIndexInContainer)
|
||||
{
|
||||
nsIDocument* document = aContainer->GetOwnerDoc();
|
||||
nsIDocument* doc = aContainer->GetOwnerDoc();
|
||||
|
||||
IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer,
|
||||
(document, aContainer, aNewIndexInContainer));
|
||||
(doc, aContainer, aNewIndexInContainer));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -129,10 +128,11 @@ nsNodeUtils::ContentInserted(nsINode* aContainer,
|
|||
aContainer->IsNodeOfType(nsINode::eDOCUMENT),
|
||||
"container must be an nsIContent or an nsIDocument");
|
||||
nsIContent* container;
|
||||
nsIDocument* doc = aContainer->GetOwnerDoc();
|
||||
nsIDocument* document;
|
||||
if (aContainer->IsNodeOfType(nsINode::eCONTENT)) {
|
||||
container = static_cast<nsIContent*>(aContainer);
|
||||
document = aContainer->GetOwnerDoc();
|
||||
document = doc;
|
||||
}
|
||||
else {
|
||||
container = nsnull;
|
||||
|
@ -152,10 +152,11 @@ nsNodeUtils::ContentRemoved(nsINode* aContainer,
|
|||
aContainer->IsNodeOfType(nsINode::eDOCUMENT),
|
||||
"container must be an nsIContent or an nsIDocument");
|
||||
nsIContent* container;
|
||||
nsIDocument* doc = aContainer->GetOwnerDoc();
|
||||
nsIDocument* document;
|
||||
if (aContainer->IsNodeOfType(nsINode::eCONTENT)) {
|
||||
container = static_cast<nsIContent*>(aContainer);
|
||||
document = aContainer->GetOwnerDoc();
|
||||
document = doc;
|
||||
}
|
||||
else {
|
||||
container = nsnull;
|
||||
|
|
|
@ -1334,52 +1334,6 @@ nsBindingManager::GetNestedSingleInsertionPoint(nsIContent* aParent,
|
|||
return insertionElement;
|
||||
}
|
||||
|
||||
// Note: We don't hold a reference to the document observer; we assume
|
||||
// that it has a live reference to the document.
|
||||
void
|
||||
nsBindingManager::AddObserver(nsIMutationObserver* aObserver)
|
||||
{
|
||||
// The array makes sure the observer isn't already in the list
|
||||
mObservers.AppendObserver(aObserver);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsBindingManager::RemoveObserver(nsIMutationObserver* aObserver)
|
||||
{
|
||||
return mObservers.RemoveObserver(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
nsBindingManager::CharacterDataWillChange(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
CharacterDataChangeInfo* aInfo)
|
||||
{
|
||||
NS_BINDINGMANAGER_NOTIFY_OBSERVERS(CharacterDataWillChange,
|
||||
(aDocument, aContent, aInfo));
|
||||
}
|
||||
|
||||
void
|
||||
nsBindingManager::CharacterDataChanged(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
CharacterDataChangeInfo* aInfo)
|
||||
{
|
||||
NS_BINDINGMANAGER_NOTIFY_OBSERVERS(CharacterDataChanged,
|
||||
(aDocument, aContent, aInfo));
|
||||
}
|
||||
|
||||
void
|
||||
nsBindingManager::AttributeChanged(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType,
|
||||
PRUint32 aStateMask)
|
||||
{
|
||||
NS_BINDINGMANAGER_NOTIFY_OBSERVERS(AttributeChanged,
|
||||
(aDocument, aContent, aNameSpaceID,
|
||||
aAttribute, aModType, aStateMask));
|
||||
}
|
||||
|
||||
void
|
||||
nsBindingManager::ContentAppended(nsIDocument* aDocument,
|
||||
nsIContent* aContainer,
|
||||
|
@ -1431,10 +1385,6 @@ nsBindingManager::ContentAppended(nsIDocument* aDocument,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_BINDINGMANAGER_NOTIFY_OBSERVERS(ContentAppended,
|
||||
(aDocument, aContainer,
|
||||
aNewIndexInContainer));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1450,10 +1400,6 @@ nsBindingManager::ContentInserted(nsIDocument* aDocument,
|
|||
NS_ASSERTION(aIndexInContainer >= 0, "Bogus index");
|
||||
HandleChildInsertion(aContainer, aChild, aIndexInContainer, PR_FALSE);
|
||||
}
|
||||
|
||||
NS_BINDINGMANAGER_NOTIFY_OBSERVERS(ContentInserted,
|
||||
(aDocument, aContainer, aChild,
|
||||
aIndexInContainer));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1483,31 +1429,18 @@ nsBindingManager::ContentRemoved(nsIDocument* aDocument,
|
|||
point->RemoveChild(aChild);
|
||||
}
|
||||
}
|
||||
SetInsertionParent(aChild, nsnull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_BINDINGMANAGER_NOTIFY_OBSERVERS(ContentRemoved,
|
||||
(aDocument, aContainer, aChild,
|
||||
aIndexInContainer));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
nsBindingManager::NodeWillBeDestroyed(const nsINode *aNode)
|
||||
nsBindingManager::DropDocumentReference()
|
||||
{
|
||||
// Make sure to not run any more XBL constructors
|
||||
mProcessingAttachedStack = PR_TRUE;
|
||||
mDocument = nsnull;
|
||||
|
||||
NS_BINDINGMANAGER_NOTIFY_OBSERVERS(NodeWillBeDestroyed, (aNode));
|
||||
}
|
||||
|
||||
void
|
||||
nsBindingManager::ParentChainChanged(nsIContent *aContent)
|
||||
{
|
||||
NS_BINDINGMANAGER_NOTIFY_OBSERVERS(ParentChainChanged, (aContent));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#ifndef nsBindingManager_h_
|
||||
#define nsBindingManager_h_
|
||||
|
||||
#include "nsIMutationObserver.h"
|
||||
#include "nsStubMutationObserver.h"
|
||||
#include "pldhash.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
@ -64,11 +64,14 @@ typedef nsTArray<nsRefPtr<nsXBLBinding> > nsBindingList;
|
|||
template<class T> class nsRunnableMethod;
|
||||
class nsIPrincipal;
|
||||
|
||||
class nsBindingManager : public nsIMutationObserver
|
||||
class nsBindingManager : public nsStubMutationObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_NSIMUTATIONOBSERVER
|
||||
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
nsBindingManager(nsIDocument* aDocument);
|
||||
~nsBindingManager();
|
||||
|
@ -180,22 +183,6 @@ public:
|
|||
|
||||
PRBool ShouldBuildChildFrames(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Add a new observer of document change notifications. Whenever content is
|
||||
* changed, appended, inserted or removed the observers are informed. This
|
||||
* is like nsIDocument::AddObserver, but these observers will be notified
|
||||
* after the XBL data structures are updated for
|
||||
* ContentInserted/ContentAppended and before they're updated for
|
||||
* ContentRemoved.
|
||||
*/
|
||||
void AddObserver(nsIMutationObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Remove an observer of document change notifications. This will
|
||||
* return false if the observer cannot be found.
|
||||
*/
|
||||
PRBool RemoveObserver(nsIMutationObserver* aObserver);
|
||||
|
||||
// Style rule methods
|
||||
nsresult WalkRules(nsStyleSet* aStyleSet,
|
||||
nsIStyleRuleProcessor::EnumFunc aFunc,
|
||||
|
@ -212,6 +199,9 @@ public:
|
|||
void BeginOutermostUpdate();
|
||||
void EndOutermostUpdate();
|
||||
|
||||
// Called when the document is going away
|
||||
void DropDocumentReference();
|
||||
|
||||
protected:
|
||||
nsIXPConnectWrappedJS* GetWrappedJS(nsIContent* aContent);
|
||||
nsresult SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
|
||||
|
@ -234,10 +224,6 @@ protected:
|
|||
void HandleChildInsertion(nsIContent* aContainer, nsIContent* aChild,
|
||||
PRUint32 aIndexInContainer, PRBool aAppend);
|
||||
|
||||
#define NS_BINDINGMANAGER_NOTIFY_OBSERVERS(func_, params_) \
|
||||
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(mObservers, nsIMutationObserver, \
|
||||
func_, params_);
|
||||
|
||||
// Same as ProcessAttachedQueue, but also nulls out
|
||||
// mProcessAttachedQueueEvent
|
||||
void DoProcessAttachedQueue();
|
||||
|
@ -291,11 +277,6 @@ protected:
|
|||
// table, they have not yet finished loading.
|
||||
nsInterfaceHashtable<nsURIHashKey,nsIStreamListener> mLoadingDocTable;
|
||||
|
||||
// Array of mutation observers who would like to be notified of content
|
||||
// appends/inserts after we update our data structures and of content removes
|
||||
// before we do so.
|
||||
nsTObserverArray<nsIMutationObserver> mObservers;
|
||||
|
||||
// A queue of binding attached event handlers that are awaiting execution.
|
||||
nsBindingList mAttachedStack;
|
||||
PRPackedBool mProcessingAttachedStack;
|
||||
|
|
|
@ -55,6 +55,7 @@ _TEST_FILES = \
|
|||
test_bug378866.xhtml \
|
||||
test_bug397934.xhtml \
|
||||
test_bug398135.xhtml \
|
||||
test_bug398492.xul \
|
||||
test_bug400705.xhtml \
|
||||
test_bug401907.xhtml \
|
||||
test_bug403162.xhtml \
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=398492
|
||||
-->
|
||||
<window title="Mozilla Bug 398492"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="/MochiKit/packed.js" />
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
|
||||
<bindings xmlns="http://www.mozilla.org/xbl">
|
||||
<binding id="test">
|
||||
<content>
|
||||
<xul:hbox id="xxx"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<children/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
</binding>
|
||||
</bindings>
|
||||
|
||||
<!-- test resuls are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=398492"
|
||||
target="_blank">Mozilla Bug 398492</a>
|
||||
</body>
|
||||
|
||||
<hbox id="testbox" style="-moz-binding: url(#test)">Text</hbox>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
/** Test for Bug 398492 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function getXBLParent(node) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var utils = Components.classes["@mozilla.org/inspector/dom-utils;1"]
|
||||
.getService(Components.interfaces.inIDOMUtils);
|
||||
return utils.getParentForNode(node, true);
|
||||
}
|
||||
|
||||
addLoadEvent(function() {
|
||||
var n = $("testbox");
|
||||
var kid = n.firstChild;
|
||||
var anonKid = document.getAnonymousNodes(n)[0];
|
||||
is(anonKid instanceof XULElement, true, "Must be a XUL element");
|
||||
is(anonKid, getXBLParent(kid), "Unexpected anonymous nodes");
|
||||
|
||||
var n2 = n.cloneNode(true);
|
||||
var kid2 = n2.firstChild;
|
||||
var anonKid2 = document.getAnonymousNodes(n2)[0];
|
||||
is(anonKid2 instanceof XULElement, true,
|
||||
"Must be a XUL element after clone");
|
||||
is(anonKid2, getXBLParent(kid2),
|
||||
"Unexpected anonymous nodes after clone");
|
||||
|
||||
var n3 = document.createElement("hbox");
|
||||
var kid3 = document.createTextNode("Text");
|
||||
n3.appendChild(kid3);
|
||||
document.addBinding(n3, document.location.href + "#test");
|
||||
var anonKid3 = document.getAnonymousNodes(n3)[0];
|
||||
is(anonKid3 instanceof XULElement, true,
|
||||
"Must be a XUL element after addBinding");
|
||||
is(anonKid3, getXBLParent(kid3),
|
||||
"Unexpected anonymous nodes after addBinding");
|
||||
|
||||
|
||||
n.removeChild(kid);
|
||||
isnot(anonKid, getXBLParent(kid),
|
||||
"Should have removed kid from insertion point");
|
||||
|
||||
n2.removeChild(kid2);
|
||||
isnot(anonKid2, getXBLParent(kid2),
|
||||
"Should have removed kid2 from insertion point");
|
||||
|
||||
n3.removeChild(kid3);
|
||||
isnot(anonKid3, getXBLParent(kid3),
|
||||
"Should have removed kid3 from insertion point");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
|
||||
]]></script>
|
||||
</window>
|
Загрузка…
Ссылка в новой задаче