Bug 100952, round two. This time, maintain a stack of active resources that we're currently building content for. r=tingley@sundell.net, sr=brendan

This commit is contained in:
waterson%netscape.com 2001-11-07 06:56:39 +00:00
Родитель 941befc981
Коммит 4a1f8a8889
3 изменённых файлов: 65 добавлений и 33 удалений

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

@ -1203,6 +1203,12 @@ nsXULContentBuilder::CreateContainerContents(nsIContent* aElement,
nsIContent** aContainer,
PRInt32* aNewIndexInContainer)
{
// Avoid re-entrant builds for the same resource.
if (IsActivated(aResource))
return NS_OK;
ActivationEntry entry(aResource, &mTop);
// Create the contents of a container by iterating over all of the
// "containment" arcs out of the element's resource.
nsresult rv;
@ -1663,12 +1669,6 @@ nsXULContentBuilder::Rebuild(nsIContent* aElement)
if (! IsElementInWidget(aElement))
return NS_OK;
// Forbid re-entrant rebuilds
if (mIsBuilding)
return NS_OK;
AutoLatch latch(&mIsBuilding);
nsresult rv;
// Next, see if it's a XUL element whose contents have never even

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

@ -160,8 +160,8 @@ nsXULTemplateBuilder::nsXULTemplateBuilder(void)
mTimer(nsnull),
mUpdateBatchNest(0),
mRulesCompiled(PR_FALSE),
mIsBuilding(PR_FALSE),
mFlags(0)
mFlags(0),
mTop(nsnull)
{
NS_INIT_REFCNT();
}
@ -565,11 +565,14 @@ nsXULTemplateBuilder::OnAssert(nsIRDFDataSource* aDataSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget)
{
// Ignore re-entrant updates while we're building content.
if (mIsBuilding || mUpdateBatchNest != 0)
// Ignore updates if we're batching
if (mUpdateBatchNest)
return(NS_OK);
AutoLatch latch(&mIsBuilding);
// Ignore re-entrant builds for content that is currently in our
// activation stack.
if (IsActivated(aSource))
return NS_OK;
nsresult rv;
@ -635,11 +638,14 @@ nsXULTemplateBuilder::OnUnassert(nsIRDFDataSource* aDataSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget)
{
// Ignore re-entrant updates while we're building content.
if (mIsBuilding || mUpdateBatchNest != 0)
// Ignore updates if we're batching
if (mUpdateBatchNest)
return NS_OK;
AutoLatch latch(&mIsBuilding);
// Ignore re-entrant builds for content that is currently in our
// activation stack.
if (IsActivated(aSource))
return NS_OK;
nsresult rv;
@ -665,11 +671,14 @@ nsXULTemplateBuilder::OnChange(nsIRDFDataSource* aDataSource,
nsIRDFNode* aOldTarget,
nsIRDFNode* aNewTarget)
{
// Ignore re-entrant updates while we're building content.
if (mIsBuilding || mUpdateBatchNest != 0)
// Ignore updates if we're batching
if (mUpdateBatchNest)
return NS_OK;
AutoLatch latch(&mIsBuilding);
// Ignore re-entrant builds for content that is currently in our
// activation stack.
if (IsActivated(aSource))
return NS_OK;
if (mCache) {
if (aOldTarget)
@ -715,12 +724,10 @@ nsXULTemplateBuilder::OnMove(nsIRDFDataSource* aDataSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget)
{
// Ignore re-entrant updates while we're building content.
if (mIsBuilding || mUpdateBatchNest != 0)
// Ignore updates if we're batching
if (mUpdateBatchNest)
return NS_OK;
AutoLatch latch(&mIsBuilding);
if (mCache)
mCache->Move(aOldSource, aNewSource, aProperty, aTarget);
@ -2439,3 +2446,14 @@ nsXULTemplateBuilder::IsSystemPrincipal(nsIPrincipal *principal, PRBool *result)
return NS_OK;
}
PRBool
nsXULTemplateBuilder::IsActivated(nsIRDFResource *aResource)
{
for (ActivationEntry *entry = mTop;
entry != nsnull;
entry = entry->mPrevious) {
if (entry->mResource == aResource)
return PR_TRUE;
}
return PR_FALSE;
}

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

@ -60,6 +60,7 @@
#include "nsFixedSizeAllocator.h"
#include "nsResourceSet.h"
#include "nsRuleNetwork.h"
#include "nsVoidArray.h"
#include "prlog.h"
#ifdef PR_LOGGING
@ -403,8 +404,6 @@ protected:
static PRInt32 kNameSpaceID_RDF;
static PRInt32 kNameSpaceID_XUL;
PRBool mIsBuilding;
enum {
eDontTestEmpty = (1 << 0)
};
@ -412,21 +411,36 @@ protected:
PRInt32 mFlags;
/**
* Stack-based helper class to maintain a latch variable without
* worrying about control flow headaches.
* Stack-based helper class to maintain a list of ``activated''
* resources; i.e., resources for which we are currently building
* content.
*/
class AutoLatch {
protected:
PRBool* mVariable;
class ActivationEntry {
public:
AutoLatch(PRBool* aVariable) : mVariable(aVariable) {
NS_ASSERTION(! *mVariable, "latch already set");
*mVariable = PR_TRUE; }
nsIRDFResource *mResource;
ActivationEntry *mPrevious;
ActivationEntry **mLink;
~AutoLatch() { *mVariable = PR_FALSE; }
ActivationEntry(nsIRDFResource *aResource, ActivationEntry **aLink)
: mResource(aResource),
mPrevious(*aLink),
mLink(aLink) { *mLink = this; }
~ActivationEntry() { *mLink = mPrevious; }
};
/**
* The top of the stack of resources that we're currently building
* content for.
*/
ActivationEntry *mTop;
/**
* Determine if a resource is currently on the activation stack.
*/
PRBool
IsActivated(nsIRDFResource *aResource);
/**
* Must be implemented by subclasses. Handle replacing aOldMatch
* with aNewMatch. Either aOldMatch or aNewMatch may be null.