From b20b076a88b064873f654f4b01bd266b9b9a3070 Mon Sep 17 00:00:00 2001 From: "waterson%netscape.com" Date: Wed, 17 Nov 1999 02:45:46 +0000 Subject: [PATCH] Bug 13378. Make sure that we hook up any broadcasters that arrive in overlay subtrees. r=hyatt --- content/xul/content/src/nsXULElement.cpp | 24 +++--- content/xul/document/src/nsForwardReference.h | 23 ++--- content/xul/document/src/nsXULDocument.cpp | 83 ++++++++++--------- content/xul/document/src/nsXULDocument.h | 7 +- rdf/content/src/nsForwardReference.h | 23 ++--- rdf/content/src/nsXULDocument.cpp | 83 ++++++++++--------- rdf/content/src/nsXULDocument.h | 7 +- rdf/content/src/nsXULElement.cpp | 24 +++--- 8 files changed, 144 insertions(+), 130 deletions(-) diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index 0f4c4bc0c695..3c6f7d4995bb 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -2699,29 +2699,25 @@ nsXULElement::AddBroadcastListener(const nsString& attr, nsIDOMElement* anElemen listener->SetAttribute(attr->GetNameSpaceID(), attr->GetName(), value, PR_TRUE); } } - - return NS_OK; } + else { + // Find out if the attribute is even present at all. + nsCOMPtr kAtom = dont_AddRef(NS_NewAtom(attr)); - // Find out if the attribute is even present at all. - nsAutoString attrValue; - nsIAtom* kAtom = NS_NewAtom(attr); - nsresult result = GetAttribute(kNameSpaceID_None, kAtom, attrValue); - PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE || - result == NS_CONTENT_ATTR_HAS_VALUE); + nsAutoString attrValue; + nsresult result = GetAttribute(kNameSpaceID_None, kAtom, attrValue); + PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE || + result == NS_CONTENT_ATTR_HAS_VALUE); - if (attrPresent) - { + if (attrPresent) { // Set the attribute anElement->SetAttribute(attr, attrValue); } - else - { + else { // Unset the attribute anElement->RemoveAttribute(attr); } - - NS_RELEASE(kAtom); + } return NS_OK; } diff --git a/content/xul/document/src/nsForwardReference.h b/content/xul/document/src/nsForwardReference.h index 2c890666ee7a..ce2f22cbcb24 100644 --- a/content/xul/document/src/nsForwardReference.h +++ b/content/xul/document/src/nsForwardReference.h @@ -34,35 +34,38 @@ public: /** * Priority codes returned from GetPriority() */ - enum Priority { + enum State { + /** A dummy marker, used to indicate unstarted resolution */ + eStart, + /** The initial pass, after which the content model will be fully built */ - ePriority_Construction, + eConstruction, /** A second pass, after which all 'magic attribute' hookup will have been performed */ - ePriority_Hookup, + eHookup, /** A dummy marker, used in kPasses to indicate termination */ - ePriority_Done + eDone }; /** * Forward references are categorized by 'priority', and all * forward references in a higher priority are resolved before any * reference in a lower priority. This variable specifies this - * ordering. The last Priority is guaranteed to be ePriority_Done. + * ordering. The last Priority is guaranteed to be eDone. */ - static const Priority kPasses[]; + static const State kPasses[]; /** - * Get the priority of the forward reference. 'ePriority_Construction' - * references are all resolved before 'ePriority_Hookup' references + * Get the state in which the forward reference should be resolved. + * 'eConstruction' references are all resolved before 'eHookup' references * are resolved. * - * @return the Priority of the reference + * @return the State in which the reference needs to be resolved */ - virtual Priority GetPriority() = 0; + virtual State GetState() = 0; /** * Result codes returned from Resolve() diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index ac9643787821..9ccf603cc4f7 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -159,10 +159,10 @@ static NS_DEFINE_IID(kIParserIID, NS_IPARSER_IID); #define XUL_NAMESPACE_URI "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" -const nsForwardReference::Priority nsForwardReference::kPasses[] = { - nsForwardReference::ePriority_Construction, - nsForwardReference::ePriority_Hookup, - nsForwardReference::ePriority_Done +const nsForwardReference::State nsForwardReference::kPasses[] = { + nsForwardReference::State::eConstruction, + nsForwardReference::State::eHookup, + nsForwardReference::State::eDone }; @@ -217,7 +217,7 @@ nsXULDocument::nsXULDocument(void) mCharSetID("UTF-8"), mDisplaySelection(PR_FALSE), mIsPopup(PR_FALSE), - mForwardReferencesResolved(PR_FALSE), + mResolutionPhase(nsForwardReference::State::eStart), mState(eState_Master) { NS_INIT_REFCNT(); @@ -1814,7 +1814,7 @@ nsXULDocument::SetForm(nsIDOMHTMLFormElement* aForm) NS_IMETHODIMP nsXULDocument::AddForwardReference(nsForwardReference* aRef) { - if (! mForwardReferencesResolved) { + if (mResolutionPhase < aRef->GetState()) { mForwardReferences.AppendElement(aRef); } else { @@ -1829,23 +1829,17 @@ nsXULDocument::AddForwardReference(nsForwardReference* aRef) NS_IMETHODIMP nsXULDocument::ResolveForwardReferences() { - if (mForwardReferencesResolved) + if (mResolutionPhase == nsForwardReference::State::eDone) return NS_OK; - // So we're monotonic. This prevents a forward reference from - // adding _yet another_ forward reference, which could cause the - // 'annealing' process to diverge. - mForwardReferencesResolved = PR_TRUE; - // Resolve each outstanding 'forward' reference. We iterate // through the list of forward references until no more forward // references can be resolved. This annealing process is // guaranteed to converge because we've "closed the gate" to new // forward references. - for (const nsForwardReference::Priority* pass = nsForwardReference::kPasses; - *pass != nsForwardReference::ePriority_Done; - ++pass) { + const nsForwardReference::State* pass = nsForwardReference::kPasses; + while ((mResolutionPhase = *pass) != nsForwardReference::eDone) { PRInt32 previous = 0; while (mForwardReferences.Count() && mForwardReferences.Count() != previous) { previous = mForwardReferences.Count(); @@ -1853,27 +1847,28 @@ nsXULDocument::ResolveForwardReferences() for (PRInt32 i = 0; i < mForwardReferences.Count(); ++i) { nsForwardReference* fwdref = NS_REINTERPRET_CAST(nsForwardReference*, mForwardReferences[i]); - if (fwdref->GetPriority() != *pass) - continue; + if (fwdref->GetState() == *pass) { + nsForwardReference::Result result = fwdref->Resolve(); - nsForwardReference::Result result = fwdref->Resolve(); + switch (result) { + case nsForwardReference::eResolve_Succeeded: + case nsForwardReference::eResolve_Error: + mForwardReferences.RemoveElementAt(i); + delete fwdref; - switch (result) { - case nsForwardReference::eResolve_Succeeded: - case nsForwardReference::eResolve_Error: - mForwardReferences.RemoveElementAt(i); - delete fwdref; + // fixup because we removed from list + --i; + break; - // fixup because we removed from list - --i; - break; - - case nsForwardReference::eResolve_Later: - // do nothing. we'll try again later - ; + case nsForwardReference::eResolve_Later: + // do nothing. we'll try again later + ; + } } } } + + ++pass; } DestroyForwardReferences(); @@ -2445,13 +2440,13 @@ nsXULDocument::AddSubtreeToDocument(nsIContent* aElement) // 3. Check for a broadcaster hookup attribute, in which case // we'll hook the node up as a listener on a broadcaster. - PRBool resolved; - rv = CheckBroadcasterHookup(this, aElement, &resolved); + PRBool listener, resolved; + rv = CheckBroadcasterHookup(this, aElement, &listener, &resolved); if (NS_FAILED(rv)) return rv; // If it's not there yet, we may be able to defer hookup until // later. - if (!resolved && !mForwardReferencesResolved) { + if (listener && !resolved && (mResolutionPhase != nsForwardReference::State::eDone)) { BroadcasterHookup* hookup = new BroadcasterHookup(this, aElement); if (! hookup) return NS_ERROR_OUT_OF_MEMORY; @@ -5141,7 +5136,9 @@ nsForwardReference::Result nsXULDocument::BroadcasterHookup::Resolve() { nsresult rv; - rv = CheckBroadcasterHookup(mDocument, mObservesElement, &mResolved); + + PRBool listener; + rv = CheckBroadcasterHookup(mDocument, mObservesElement, &listener, &mResolved); if (NS_FAILED(rv)) return eResolve_Error; return mResolved ? eResolve_Succeeded : eResolve_Later; @@ -5196,6 +5193,7 @@ nsXULDocument::BroadcasterHookup::~BroadcasterHookup() nsresult nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, nsIContent* aElement, + PRBool* aNeedsHookup, PRBool* aDidResolve) { // Resolve a broadcaster hookup. Look at the element that we're @@ -5233,8 +5231,10 @@ nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, // If we're still parented by an 'overlay' tag, then we haven't // made it into the real document yet. Defer hookup. - if (parentTag.get() == kOverlayAtom) + if (parentTag.get() == kOverlayAtom) { + *aNeedsHookup = PR_TRUE; return NS_OK; + } listener = do_QueryInterface(parent); @@ -5253,8 +5253,10 @@ nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, if (NS_FAILED(rv)) return rv; // Bail if there's no broadcasterID - if ((rv != NS_CONTENT_ATTR_HAS_VALUE) || (broadcasterID.Length() == 0)) + if ((rv != NS_CONTENT_ATTR_HAS_VALUE) || (broadcasterID.Length() == 0)) { + *aNeedsHookup = PR_FALSE; return NS_OK; + } listener = do_QueryInterface(aElement); @@ -5274,12 +5276,16 @@ nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, // If we can't find the broadcaster, then we'll need to defer the // hookup. We may need to resolve some of the other overlays // first. - if (! target) + if (! target) { + *aNeedsHookup = PR_TRUE; return NS_OK; + } nsCOMPtr broadcaster = do_QueryInterface(target); - if (! broadcaster) + if (! broadcaster) { + *aNeedsHookup = PR_FALSE; return NS_OK; // not a XUL element, so we can't subscribe + } rv = broadcaster->AddBroadcastListener(attribute, listener); if (NS_FAILED(rv)) return rv; @@ -5310,6 +5316,7 @@ nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, } #endif + *aNeedsHookup = PR_FALSE; *aDidResolve = PR_TRUE; return NS_OK; } diff --git a/content/xul/document/src/nsXULDocument.h b/content/xul/document/src/nsXULDocument.h index 300a8a0079e2..42fda1a620af 100644 --- a/content/xul/document/src/nsXULDocument.h +++ b/content/xul/document/src/nsXULDocument.h @@ -519,7 +519,7 @@ protected: nsCOMPtr mCommandDispatcher; // [OWNER] of the focus tracker nsVoidArray mForwardReferences; - PRBool mForwardReferencesResolved; + nsForwardReference::State mResolutionPhase; // The following are pointers into the content model which provide access to // the objects triggering either a popup or a tooltip. These are marked as @@ -651,7 +651,7 @@ protected: virtual ~BroadcasterHookup(); - virtual Priority GetPriority() { return ePriority_Hookup; } + virtual State GetState() { return eHookup; } virtual Result Resolve(); }; @@ -676,7 +676,7 @@ protected: virtual ~OverlayForwardReference(); - virtual Priority GetPriority() { return ePriority_Construction; } + virtual State GetState() { return eConstruction; } virtual Result Resolve(); }; @@ -687,6 +687,7 @@ protected: nsresult CheckBroadcasterHookup(nsXULDocument* aDocument, nsIContent* aElement, + PRBool* aNeedsHookup, PRBool* aDidResolve); static diff --git a/rdf/content/src/nsForwardReference.h b/rdf/content/src/nsForwardReference.h index 2c890666ee7a..ce2f22cbcb24 100644 --- a/rdf/content/src/nsForwardReference.h +++ b/rdf/content/src/nsForwardReference.h @@ -34,35 +34,38 @@ public: /** * Priority codes returned from GetPriority() */ - enum Priority { + enum State { + /** A dummy marker, used to indicate unstarted resolution */ + eStart, + /** The initial pass, after which the content model will be fully built */ - ePriority_Construction, + eConstruction, /** A second pass, after which all 'magic attribute' hookup will have been performed */ - ePriority_Hookup, + eHookup, /** A dummy marker, used in kPasses to indicate termination */ - ePriority_Done + eDone }; /** * Forward references are categorized by 'priority', and all * forward references in a higher priority are resolved before any * reference in a lower priority. This variable specifies this - * ordering. The last Priority is guaranteed to be ePriority_Done. + * ordering. The last Priority is guaranteed to be eDone. */ - static const Priority kPasses[]; + static const State kPasses[]; /** - * Get the priority of the forward reference. 'ePriority_Construction' - * references are all resolved before 'ePriority_Hookup' references + * Get the state in which the forward reference should be resolved. + * 'eConstruction' references are all resolved before 'eHookup' references * are resolved. * - * @return the Priority of the reference + * @return the State in which the reference needs to be resolved */ - virtual Priority GetPriority() = 0; + virtual State GetState() = 0; /** * Result codes returned from Resolve() diff --git a/rdf/content/src/nsXULDocument.cpp b/rdf/content/src/nsXULDocument.cpp index ac9643787821..9ccf603cc4f7 100644 --- a/rdf/content/src/nsXULDocument.cpp +++ b/rdf/content/src/nsXULDocument.cpp @@ -159,10 +159,10 @@ static NS_DEFINE_IID(kIParserIID, NS_IPARSER_IID); #define XUL_NAMESPACE_URI "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" -const nsForwardReference::Priority nsForwardReference::kPasses[] = { - nsForwardReference::ePriority_Construction, - nsForwardReference::ePriority_Hookup, - nsForwardReference::ePriority_Done +const nsForwardReference::State nsForwardReference::kPasses[] = { + nsForwardReference::State::eConstruction, + nsForwardReference::State::eHookup, + nsForwardReference::State::eDone }; @@ -217,7 +217,7 @@ nsXULDocument::nsXULDocument(void) mCharSetID("UTF-8"), mDisplaySelection(PR_FALSE), mIsPopup(PR_FALSE), - mForwardReferencesResolved(PR_FALSE), + mResolutionPhase(nsForwardReference::State::eStart), mState(eState_Master) { NS_INIT_REFCNT(); @@ -1814,7 +1814,7 @@ nsXULDocument::SetForm(nsIDOMHTMLFormElement* aForm) NS_IMETHODIMP nsXULDocument::AddForwardReference(nsForwardReference* aRef) { - if (! mForwardReferencesResolved) { + if (mResolutionPhase < aRef->GetState()) { mForwardReferences.AppendElement(aRef); } else { @@ -1829,23 +1829,17 @@ nsXULDocument::AddForwardReference(nsForwardReference* aRef) NS_IMETHODIMP nsXULDocument::ResolveForwardReferences() { - if (mForwardReferencesResolved) + if (mResolutionPhase == nsForwardReference::State::eDone) return NS_OK; - // So we're monotonic. This prevents a forward reference from - // adding _yet another_ forward reference, which could cause the - // 'annealing' process to diverge. - mForwardReferencesResolved = PR_TRUE; - // Resolve each outstanding 'forward' reference. We iterate // through the list of forward references until no more forward // references can be resolved. This annealing process is // guaranteed to converge because we've "closed the gate" to new // forward references. - for (const nsForwardReference::Priority* pass = nsForwardReference::kPasses; - *pass != nsForwardReference::ePriority_Done; - ++pass) { + const nsForwardReference::State* pass = nsForwardReference::kPasses; + while ((mResolutionPhase = *pass) != nsForwardReference::eDone) { PRInt32 previous = 0; while (mForwardReferences.Count() && mForwardReferences.Count() != previous) { previous = mForwardReferences.Count(); @@ -1853,27 +1847,28 @@ nsXULDocument::ResolveForwardReferences() for (PRInt32 i = 0; i < mForwardReferences.Count(); ++i) { nsForwardReference* fwdref = NS_REINTERPRET_CAST(nsForwardReference*, mForwardReferences[i]); - if (fwdref->GetPriority() != *pass) - continue; + if (fwdref->GetState() == *pass) { + nsForwardReference::Result result = fwdref->Resolve(); - nsForwardReference::Result result = fwdref->Resolve(); + switch (result) { + case nsForwardReference::eResolve_Succeeded: + case nsForwardReference::eResolve_Error: + mForwardReferences.RemoveElementAt(i); + delete fwdref; - switch (result) { - case nsForwardReference::eResolve_Succeeded: - case nsForwardReference::eResolve_Error: - mForwardReferences.RemoveElementAt(i); - delete fwdref; + // fixup because we removed from list + --i; + break; - // fixup because we removed from list - --i; - break; - - case nsForwardReference::eResolve_Later: - // do nothing. we'll try again later - ; + case nsForwardReference::eResolve_Later: + // do nothing. we'll try again later + ; + } } } } + + ++pass; } DestroyForwardReferences(); @@ -2445,13 +2440,13 @@ nsXULDocument::AddSubtreeToDocument(nsIContent* aElement) // 3. Check for a broadcaster hookup attribute, in which case // we'll hook the node up as a listener on a broadcaster. - PRBool resolved; - rv = CheckBroadcasterHookup(this, aElement, &resolved); + PRBool listener, resolved; + rv = CheckBroadcasterHookup(this, aElement, &listener, &resolved); if (NS_FAILED(rv)) return rv; // If it's not there yet, we may be able to defer hookup until // later. - if (!resolved && !mForwardReferencesResolved) { + if (listener && !resolved && (mResolutionPhase != nsForwardReference::State::eDone)) { BroadcasterHookup* hookup = new BroadcasterHookup(this, aElement); if (! hookup) return NS_ERROR_OUT_OF_MEMORY; @@ -5141,7 +5136,9 @@ nsForwardReference::Result nsXULDocument::BroadcasterHookup::Resolve() { nsresult rv; - rv = CheckBroadcasterHookup(mDocument, mObservesElement, &mResolved); + + PRBool listener; + rv = CheckBroadcasterHookup(mDocument, mObservesElement, &listener, &mResolved); if (NS_FAILED(rv)) return eResolve_Error; return mResolved ? eResolve_Succeeded : eResolve_Later; @@ -5196,6 +5193,7 @@ nsXULDocument::BroadcasterHookup::~BroadcasterHookup() nsresult nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, nsIContent* aElement, + PRBool* aNeedsHookup, PRBool* aDidResolve) { // Resolve a broadcaster hookup. Look at the element that we're @@ -5233,8 +5231,10 @@ nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, // If we're still parented by an 'overlay' tag, then we haven't // made it into the real document yet. Defer hookup. - if (parentTag.get() == kOverlayAtom) + if (parentTag.get() == kOverlayAtom) { + *aNeedsHookup = PR_TRUE; return NS_OK; + } listener = do_QueryInterface(parent); @@ -5253,8 +5253,10 @@ nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, if (NS_FAILED(rv)) return rv; // Bail if there's no broadcasterID - if ((rv != NS_CONTENT_ATTR_HAS_VALUE) || (broadcasterID.Length() == 0)) + if ((rv != NS_CONTENT_ATTR_HAS_VALUE) || (broadcasterID.Length() == 0)) { + *aNeedsHookup = PR_FALSE; return NS_OK; + } listener = do_QueryInterface(aElement); @@ -5274,12 +5276,16 @@ nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, // If we can't find the broadcaster, then we'll need to defer the // hookup. We may need to resolve some of the other overlays // first. - if (! target) + if (! target) { + *aNeedsHookup = PR_TRUE; return NS_OK; + } nsCOMPtr broadcaster = do_QueryInterface(target); - if (! broadcaster) + if (! broadcaster) { + *aNeedsHookup = PR_FALSE; return NS_OK; // not a XUL element, so we can't subscribe + } rv = broadcaster->AddBroadcastListener(attribute, listener); if (NS_FAILED(rv)) return rv; @@ -5310,6 +5316,7 @@ nsXULDocument::CheckBroadcasterHookup(nsXULDocument* aDocument, } #endif + *aNeedsHookup = PR_FALSE; *aDidResolve = PR_TRUE; return NS_OK; } diff --git a/rdf/content/src/nsXULDocument.h b/rdf/content/src/nsXULDocument.h index 300a8a0079e2..42fda1a620af 100644 --- a/rdf/content/src/nsXULDocument.h +++ b/rdf/content/src/nsXULDocument.h @@ -519,7 +519,7 @@ protected: nsCOMPtr mCommandDispatcher; // [OWNER] of the focus tracker nsVoidArray mForwardReferences; - PRBool mForwardReferencesResolved; + nsForwardReference::State mResolutionPhase; // The following are pointers into the content model which provide access to // the objects triggering either a popup or a tooltip. These are marked as @@ -651,7 +651,7 @@ protected: virtual ~BroadcasterHookup(); - virtual Priority GetPriority() { return ePriority_Hookup; } + virtual State GetState() { return eHookup; } virtual Result Resolve(); }; @@ -676,7 +676,7 @@ protected: virtual ~OverlayForwardReference(); - virtual Priority GetPriority() { return ePriority_Construction; } + virtual State GetState() { return eConstruction; } virtual Result Resolve(); }; @@ -687,6 +687,7 @@ protected: nsresult CheckBroadcasterHookup(nsXULDocument* aDocument, nsIContent* aElement, + PRBool* aNeedsHookup, PRBool* aDidResolve); static diff --git a/rdf/content/src/nsXULElement.cpp b/rdf/content/src/nsXULElement.cpp index 0f4c4bc0c695..3c6f7d4995bb 100644 --- a/rdf/content/src/nsXULElement.cpp +++ b/rdf/content/src/nsXULElement.cpp @@ -2699,29 +2699,25 @@ nsXULElement::AddBroadcastListener(const nsString& attr, nsIDOMElement* anElemen listener->SetAttribute(attr->GetNameSpaceID(), attr->GetName(), value, PR_TRUE); } } - - return NS_OK; } + else { + // Find out if the attribute is even present at all. + nsCOMPtr kAtom = dont_AddRef(NS_NewAtom(attr)); - // Find out if the attribute is even present at all. - nsAutoString attrValue; - nsIAtom* kAtom = NS_NewAtom(attr); - nsresult result = GetAttribute(kNameSpaceID_None, kAtom, attrValue); - PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE || - result == NS_CONTENT_ATTR_HAS_VALUE); + nsAutoString attrValue; + nsresult result = GetAttribute(kNameSpaceID_None, kAtom, attrValue); + PRBool attrPresent = (result == NS_CONTENT_ATTR_NO_VALUE || + result == NS_CONTENT_ATTR_HAS_VALUE); - if (attrPresent) - { + if (attrPresent) { // Set the attribute anElement->SetAttribute(attr, attrValue); } - else - { + else { // Unset the attribute anElement->RemoveAttribute(attr); } - - NS_RELEASE(kAtom); + } return NS_OK; }