зеркало из https://github.com/mozilla/pjs.git
Bug 53901: Don't set is-in-doc flag on cloned XUL nodes. r/sr=jst
This commit is contained in:
Родитель
7a606cc629
Коммит
ea1afb36a5
|
@ -82,10 +82,9 @@ class nsNodeSupportsWeakRefTearoff;
|
|||
// NOTE: Should only be used on nsIContent nodes
|
||||
#define NODE_MAY_HAVE_FRAME 0x00000020U
|
||||
|
||||
// Whether the 'in doc' flag is faked to true for
|
||||
// this node. This should only ever be set on XUL
|
||||
// elements.
|
||||
#define NODE_HAS_FAKED_INDOC 0x00000040U
|
||||
// Forces the XBL code to treat this node as if it was
|
||||
// in the document and therefor should get bindings attached.
|
||||
#define NODE_FORCE_XBL_BINDINGS 0x00000040U
|
||||
|
||||
// Whether a binding manager may have a pointer to this
|
||||
#define NODE_MAY_BE_IN_BINDING_MNGR 0x00000080U
|
||||
|
|
|
@ -547,14 +547,7 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
|
||||
NS_PRECONDITION(HasSameOwnerDoc(NODE_FROM(aParent, aDocument)),
|
||||
"Must have the same owner document");
|
||||
// XXXbz XUL elements are confused about their current doc when they're
|
||||
// cloned, so we don't assert if aParent is a XUL element and aDocument is
|
||||
// null, even if aParent->GetCurrentDoc() is non-null
|
||||
// NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
|
||||
// "aDocument must be current doc of aParent");
|
||||
NS_PRECONDITION(!aParent ||
|
||||
(aParent->IsNodeOfType(eXUL) && aDocument == nsnull) ||
|
||||
aDocument == aParent->GetCurrentDoc(),
|
||||
NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
|
||||
"aDocument must be current doc of aParent");
|
||||
NS_PRECONDITION(!GetCurrentDoc() && !IsInDoc(),
|
||||
"Already have a document. Unbind first!");
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
#include "nsMutationEvent.h"
|
||||
#include "nsNodeUtils.h"
|
||||
#include "nsDocument.h"
|
||||
#include "nsXULElement.h"
|
||||
|
||||
#include "nsBindingManager.h"
|
||||
#include "nsXBLBinding.h"
|
||||
|
@ -1699,14 +1700,7 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
|
||||
NS_PRECONDITION(HasSameOwnerDoc(NODE_FROM(aParent, aDocument)),
|
||||
"Must have the same owner document");
|
||||
// XXXbz XUL elements are confused about their current doc when they're
|
||||
// cloned, so we don't assert if aParent is a XUL element and aDocument is
|
||||
// null, even if aParent->GetCurrentDoc() is non-null
|
||||
// NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
|
||||
// "aDocument must be current doc of aParent");
|
||||
NS_PRECONDITION(!aParent ||
|
||||
(aParent->IsNodeOfType(eXUL) && aDocument == nsnull) ||
|
||||
aDocument == aParent->GetCurrentDoc(),
|
||||
NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
|
||||
"aDocument must be current doc of aParent");
|
||||
NS_PRECONDITION(!GetCurrentDoc(), "Already have a document. Unbind first!");
|
||||
// Note that as we recurse into the kids, they'll have a non-null parent. So
|
||||
|
@ -1718,7 +1712,10 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
(!aBindingParent && aParent &&
|
||||
aParent->GetBindingParent() == GetBindingParent()),
|
||||
"Already have a binding parent. Unbind first!");
|
||||
NS_PRECONDITION(aBindingParent != this || IsNativeAnonymous(),
|
||||
// XXXbz XUL's SetNativeAnonymous is all weird, so can't assert
|
||||
// anything here
|
||||
NS_PRECONDITION(IsNodeOfType(eXUL) ||
|
||||
aBindingParent != this || IsNativeAnonymous(),
|
||||
"Only native anonymous content should have itself as its "
|
||||
"own binding parent");
|
||||
|
||||
|
@ -1727,6 +1724,11 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
}
|
||||
|
||||
// First set the binding parent
|
||||
nsXULElement* xulElem = nsXULElement::FromContent(this);
|
||||
if (xulElem) {
|
||||
xulElem->SetXULBindingParent(aBindingParent);
|
||||
}
|
||||
else {
|
||||
if (aBindingParent) {
|
||||
nsDOMSlots *slots = GetDOMSlots();
|
||||
|
||||
|
@ -1736,10 +1738,15 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
|
||||
slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
|
||||
}
|
||||
}
|
||||
|
||||
// Now set the parent
|
||||
// Now set the parent and set the "Force attach xbl" flag if needed.
|
||||
if (aParent) {
|
||||
mParentPtrBits = NS_REINTERPRET_CAST(PtrBits, aParent) | PARENT_BIT_PARENT_IS_CONTENT;
|
||||
|
||||
if (aParent->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
SetFlags(NODE_FORCE_XBL_BINDINGS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mParentPtrBits = NS_REINTERPRET_CAST(PtrBits, aDocument);
|
||||
|
@ -1760,12 +1767,18 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
|
||||
// Being added to a document.
|
||||
mParentPtrBits |= PARENT_BIT_INDOCUMENT;
|
||||
|
||||
// Unset this flag since we now really are in a document.
|
||||
UnsetFlags(NODE_FORCE_XBL_BINDINGS);
|
||||
}
|
||||
|
||||
// Now recurse into our kids
|
||||
nsresult rv;
|
||||
PRUint32 i;
|
||||
for (i = 0; i < GetChildCount(); ++i) {
|
||||
// Don't call GetChildCount() here since that'll make XUL generate
|
||||
// template children, which we're not in a consistent enough state for.
|
||||
// Additionally, there's not really a need to generate the children here.
|
||||
for (i = 0; i < mAttrsAndChildren.ChildCount(); ++i) {
|
||||
// The child can remove itself from the parent in BindToTree.
|
||||
nsCOMPtr<nsIContent> child = mAttrsAndChildren.ChildAt(i);
|
||||
rv = child->BindToTree(aDocument, this, aBindingParent,
|
||||
|
@ -1809,14 +1822,25 @@ nsGenericElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
|||
// Unset things in the reverse order from how we set them in BindToTree
|
||||
mParentPtrBits = aNullParent ? 0 : mParentPtrBits & ~PARENT_BIT_INDOCUMENT;
|
||||
|
||||
// Unset this since that's what the old code effectively did.
|
||||
UnsetFlags(NODE_FORCE_XBL_BINDINGS);
|
||||
|
||||
nsXULElement* xulElem = nsXULElement::FromContent(this);
|
||||
if (xulElem) {
|
||||
xulElem->SetXULBindingParent(nsnull);
|
||||
}
|
||||
else {
|
||||
nsDOMSlots *slots = GetExistingDOMSlots();
|
||||
if (slots) {
|
||||
slots->mBindingParent = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
if (aDeep) {
|
||||
// Do the kids
|
||||
PRUint32 i, n = GetChildCount();
|
||||
// Do the kids. Don't call GetChildCount() here since that'll force
|
||||
// XUL to generate template children, which there is no need for since
|
||||
// all we're going to do is unbind them anyway.
|
||||
PRUint32 i, n = mAttrsAndChildren.ChildCount();
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
// Note that we pass PR_FALSE for aNullParent here, since we don't want
|
||||
|
@ -2902,7 +2926,6 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
}
|
||||
else {
|
||||
// Not inserting a fragment but rather a single node.
|
||||
PRBool newContentIsXUL = newContent->IsNodeOfType(eXUL);
|
||||
|
||||
// Remove the element from the old parent if one exists
|
||||
nsINode* oldParent = newContent->GetNodeParent();
|
||||
|
@ -2946,7 +2969,7 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
}
|
||||
}
|
||||
|
||||
if (!newContentIsXUL) {
|
||||
if (!newContent->IsNodeOfType(eXUL)) {
|
||||
nsContentUtils::ReparentContentWrapper(newContent, aParent,
|
||||
container->GetOwnerDoc(),
|
||||
container->GetOwnerDoc());
|
||||
|
@ -3022,8 +3045,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericElement)
|
||||
nsIDocument* currentDoc = tmp->GetCurrentDoc();
|
||||
if (currentDoc && !tmp->HasFlag(NODE_HAS_FAKED_INDOC) &&
|
||||
nsCCUncollectableMarker::InGeneration(
|
||||
if (currentDoc && nsCCUncollectableMarker::InGeneration(
|
||||
currentDoc->GetMarkedCCGeneration())) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -69,13 +69,6 @@
|
|||
} \
|
||||
prev = node; \
|
||||
node = node->GetNodeParent(); \
|
||||
\
|
||||
if (!node && prev->IsNodeOfType(nsINode::eXUL)) { \
|
||||
/* XUL elements can have the in-document flag set, but \
|
||||
still be in an orphaned subtree. In this case we \
|
||||
need to notify the document */ \
|
||||
node = NS_STATIC_CAST(nsIContent*, prev)->GetCurrentDoc(); \
|
||||
} \
|
||||
} while (node); \
|
||||
PR_END_MACRO
|
||||
|
||||
|
@ -645,8 +638,7 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
|
|||
if (aClone && !aParent && aNode->IsNodeOfType(nsINode::eXUL)) {
|
||||
nsXULElement *xulElem = NS_STATIC_CAST(nsXULElement*, elem);
|
||||
if (!xulElem->mPrototype || xulElem->IsInDoc()) {
|
||||
clone->mParentPtrBits |= nsINode::PARENT_BIT_INDOCUMENT;
|
||||
clone->SetFlags(NODE_HAS_FAKED_INDOC);
|
||||
clone->SetFlags(NODE_FORCE_XBL_BINDINGS);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -494,7 +494,13 @@ nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL, PRBool aAugmentFl
|
|||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIDocument> document = aContent->GetOwnerDoc();
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
if (aContent->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
document = aContent->GetOwnerDoc();
|
||||
}
|
||||
else {
|
||||
document = aContent->GetCurrentDoc();
|
||||
}
|
||||
|
||||
// XXX document may be null if we're in the midst of paint suppression
|
||||
if (!document)
|
||||
|
|
|
@ -248,16 +248,6 @@ nsXULElement::nsXULElement(nsINodeInfo* aNodeInfo)
|
|||
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumElements);
|
||||
}
|
||||
|
||||
nsXULElement::~nsXULElement()
|
||||
{
|
||||
//XXX UnbindFromTree is not called always before dtor.
|
||||
//XXX Related to templates or overlays?
|
||||
//XXXbz probably related to the cloning thing!
|
||||
if (IsInDoc()) {
|
||||
UnbindFromTree();
|
||||
}
|
||||
}
|
||||
|
||||
nsXULElement::nsXULSlots::nsXULSlots(PtrBits aFlags)
|
||||
: nsXULElement::nsDOMSlots(aFlags)
|
||||
{
|
||||
|
@ -795,168 +785,6 @@ nsXULElement::MaybeAddPopupListener(nsIAtom* aLocalName)
|
|||
// nsIContent interface
|
||||
//
|
||||
|
||||
nsresult
|
||||
nsXULElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
PRBool aCompileEventHandlers)
|
||||
{
|
||||
NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
|
||||
NS_PRECONDITION(HasSameOwnerDoc(NODE_FROM(aParent, aDocument)),
|
||||
"Must have the same owner document");
|
||||
// XXXbz XUL elements are confused about their current doc when they're
|
||||
// cloned, so we don't assert if aParent is a XUL element and aDocument is
|
||||
// null, even if aParent->GetCurrentDoc() is non-null
|
||||
// NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
|
||||
// "aDocument must be current doc of aParent");
|
||||
NS_PRECONDITION(!aParent ||
|
||||
(aParent->IsNodeOfType(eXUL) && aDocument == nsnull) ||
|
||||
aDocument == aParent->GetCurrentDoc(),
|
||||
"aDocument must be current doc of aParent");
|
||||
// XXXbz we'd like to assert that GetCurrentDoc() is null, but the cloning
|
||||
// mess makes that impossible. We can't even assert that aDocument ==
|
||||
// GetCurrentDoc() when GetCurrentDoc() is non-null, since we may be
|
||||
// getting inserted into a different document. :(
|
||||
// NS_PRECONDITION(!GetCurrentDoc(),
|
||||
// "Already have a document. Unbind first!");
|
||||
|
||||
// Note that as we recurse into the kids, they'll have a non-null
|
||||
// parent. So only assert if our parent is _changing_ while we
|
||||
// have a parent.
|
||||
NS_PRECONDITION(!GetParent() || aParent == GetParent(),
|
||||
"Already have a parent. Unbind first!");
|
||||
NS_PRECONDITION(!GetBindingParent() ||
|
||||
aBindingParent == GetBindingParent() ||
|
||||
(!aBindingParent && aParent &&
|
||||
aParent->GetBindingParent() == GetBindingParent()),
|
||||
"Already have a binding parent. Unbind first!");
|
||||
// XXXbz XUL's SetNativeAnonymous is all weird, so can't assert
|
||||
// anything here
|
||||
// NS_PRECONDITION(aBindingParent != this || IsNativeAnonymous(),
|
||||
// "Only native anonymous content should have itself as its "
|
||||
// "own binding parent");
|
||||
|
||||
if (!aBindingParent && aParent) {
|
||||
aBindingParent = aParent->GetBindingParent();
|
||||
}
|
||||
|
||||
// First set the binding parent
|
||||
mBindingParent = aBindingParent;
|
||||
|
||||
// Now set the parent
|
||||
if (aParent) {
|
||||
mParentPtrBits = NS_REINTERPRET_CAST(PtrBits, aParent) | PARENT_BIT_PARENT_IS_CONTENT;
|
||||
}
|
||||
else {
|
||||
mParentPtrBits = NS_REINTERPRET_CAST(PtrBits, aDocument);
|
||||
}
|
||||
|
||||
// XXXbz sXBL/XBL2 issue!
|
||||
|
||||
// Finally, set the document
|
||||
if (aDocument) {
|
||||
// Notify XBL- & nsIAnonymousContentCreator-generated
|
||||
// anonymous content that the document is changing. XXXbz
|
||||
// ordering issues here? Probably not, since
|
||||
// ChangeDocumentFor is just pretty broken anyway.... Need to
|
||||
// get it working.
|
||||
|
||||
// XXXbz XBL doesn't handle this (asserts), and we don't really want
|
||||
// to be doing this during parsing anyway... sort this out.
|
||||
// aDocument->BindingManager()->ChangeDocumentFor(this, nsnull,
|
||||
// aDocument);
|
||||
|
||||
// Being added to a document.
|
||||
mParentPtrBits |= PARENT_BIT_INDOCUMENT;
|
||||
|
||||
// Unset this flag since we now really are in a document.
|
||||
UnsetFlags(NODE_HAS_FAKED_INDOC);
|
||||
}
|
||||
|
||||
// Now recurse into our kids
|
||||
nsresult rv;
|
||||
PRUint32 i;
|
||||
for (i = 0; i < GetChildCount(); ++i) {
|
||||
// The child can remove itself from the parent in BindToTree.
|
||||
nsCOMPtr<nsIContent> child = mAttrsAndChildren.ChildAt(i);
|
||||
rv = child->BindToTree(aDocument, this, aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsNodeUtils::ParentChainChanged(this);
|
||||
|
||||
// XXXbz script execution during binding can trigger some of these
|
||||
// postcondition asserts.... But we do want that, since things will
|
||||
// generally be quite broken when that happens.
|
||||
// XXXbz we'd like to assert that we have the right GetCurrentDoc(), but
|
||||
// we may be being bound to a null document while we already have a
|
||||
// current doc, due to the cloneNode hack... So can't assert that yet.
|
||||
// NS_POSTCONDITION(aDocument == GetCurrentDoc(),
|
||||
// "Bound to wrong document");
|
||||
NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
|
||||
NS_POSTCONDITION(aBindingParent == GetBindingParent(),
|
||||
"Bound to wrong binding parent");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsXULElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
||||
{
|
||||
// XXXbz we'd like to assert that called didn't screw up aDeep, but I'm not
|
||||
// sure we can....
|
||||
// NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
|
||||
// "Shallow unbind won't clear document and binding "
|
||||
// "parent on kids!");
|
||||
// Make sure to unbind this node before doing the kids
|
||||
nsIDocument *document = GetCurrentDoc();
|
||||
if (document) {
|
||||
// Notify XBL- & nsIAnonymousContentCreator-generated
|
||||
// anonymous content that the document is changing.
|
||||
document->BindingManager()->ChangeDocumentFor(this, document, nsnull);
|
||||
|
||||
document->ClearBoxObjectFor(this);
|
||||
}
|
||||
|
||||
// mControllers can own objects that are implemented
|
||||
// in JavaScript (such as some implementations of
|
||||
// nsIControllers. These objects prevent their global
|
||||
// object's script object from being garbage collected,
|
||||
// which means JS continues to hold an owning reference
|
||||
// to the nsGlobalWindow, which owns the document,
|
||||
// which owns this content. That's a cycle, so we break
|
||||
// it here. (It might be better to break this by releasing
|
||||
// mDocument in nsGlobalWindow::SetDocShell, but I'm not
|
||||
// sure whether that would fix all possible cycles through
|
||||
// mControllers.)
|
||||
nsDOMSlots* slots = GetExistingDOMSlots();
|
||||
if (slots) {
|
||||
NS_IF_RELEASE(slots->mControllers);
|
||||
}
|
||||
|
||||
// Unset things in the reverse order from how we set them in BindToTree
|
||||
mParentPtrBits = aNullParent ? 0 : mParentPtrBits & ~PARENT_BIT_INDOCUMENT;
|
||||
|
||||
mBindingParent = nsnull;
|
||||
|
||||
if (aDeep) {
|
||||
// Do the kids. Note that we don't want to GetChildCount(), because
|
||||
// that will force content generation... if we never had to generate
|
||||
// the content, we shouldn't force it now!
|
||||
PRUint32 i, n = PeekChildCount();
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
// Note that we pass PR_FALSE for aNullParent here, since we don't
|
||||
// want the kids to forget us. We _do_ want them to forget their
|
||||
// binding parent, though, since this only walks non-anonymous
|
||||
// kids.
|
||||
mAttrsAndChildren.ChildAt(i)->UnbindFromTree(PR_TRUE, PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
nsNodeUtils::ParentChainChanged(this);
|
||||
}
|
||||
|
||||
void
|
||||
nsXULElement::SetNativeAnonymous(PRBool aAnonymous)
|
||||
{
|
||||
|
|
|
@ -486,11 +486,6 @@ public:
|
|||
PRBool aNotify);
|
||||
|
||||
// nsIContent
|
||||
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
PRBool aCompileEventHandlers);
|
||||
virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
|
||||
PRBool aNullParent = PR_TRUE);
|
||||
virtual void SetNativeAnonymous(PRBool aAnonymous);
|
||||
virtual nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify);
|
||||
virtual nsIAtom *GetIDAttributeName() const;
|
||||
|
@ -563,13 +558,20 @@ public:
|
|||
|
||||
virtual void RecompileScriptEventListeners();
|
||||
|
||||
// This function should ONLY be used by BindToTree implementations.
|
||||
// The function exists soly because XUL elements store the binding parent
|
||||
// differently than nsGenericElement does.
|
||||
void SetXULBindingParent(nsIContent* aBindingParent)
|
||||
{
|
||||
mBindingParent = aBindingParent;
|
||||
}
|
||||
|
||||
protected:
|
||||
// XXX This can be removed when nsNodeUtils::CloneAndAdopt doesn't need
|
||||
// access to mPrototype anymore.
|
||||
friend class nsNodeUtils;
|
||||
|
||||
nsXULElement(nsINodeInfo* aNodeInfo);
|
||||
virtual ~nsXULElement(void);
|
||||
|
||||
// Implementation methods
|
||||
nsresult EnsureContentsGenerated(void) const;
|
||||
|
|
|
@ -6839,7 +6839,13 @@ nsElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
nsCOMPtr<nsIContent> content(do_QueryWrappedNative(wrapper));
|
||||
NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = content->GetDocument();
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
if (content->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
doc = content->GetOwnerDoc();
|
||||
}
|
||||
else {
|
||||
doc = content->GetCurrentDoc();
|
||||
}
|
||||
|
||||
if (!doc) {
|
||||
// There's no baseclass that cares about this call so we just
|
||||
|
|
Загрузка…
Ссылка в новой задаче