Bug 118863. Fix several incorrect uses of IsElementContainedBy when IsElementInBuilder is required. Fixes problems with nested templates. r=rjc, sr=hyatt.

This commit is contained in:
waterson%netscape.com 2002-01-11 03:00:53 +00:00
parent dd4e2fd9f8
commit 0c07a14c41
4 changed files with 140 additions and 143 deletions

View File

@ -50,45 +50,20 @@
extern PRLogModuleInfo* gXULTemplateLog; extern PRLogModuleInfo* gXULTemplateLog;
#endif #endif
PRBool extern PRBool
IsElementContainedBy(nsIContent* aElement, nsIContent* aContainer) IsElementInBuilder(nsIContent *aContent, nsIXULTemplateBuilder *aBuilder);
{
// Make sure that we're actually creating content for the tree
// content model that we've been assigned to deal with.
// Walk up the parent chain from us to the root and
// see what we find.
if (aElement == aContainer)
return PR_TRUE;
// walk up the tree until you find rootAtom
nsCOMPtr<nsIContent> element(do_QueryInterface(aElement));
nsCOMPtr<nsIContent> parent;
element->GetParent(*getter_AddRefs(parent));
element = parent;
while (element) {
if (element.get() == aContainer)
return PR_TRUE;
element->GetParent(*getter_AddRefs(parent));
element = parent;
}
return PR_FALSE;
}
nsContentTestNode::nsContentTestNode(InnerNode* aParent, nsContentTestNode::nsContentTestNode(InnerNode* aParent,
nsConflictSet& aConflictSet, nsConflictSet& aConflictSet,
nsIXULDocument* aDocument, nsIXULDocument* aDocument,
nsIContent* aRoot, nsIXULTemplateBuilder* aBuilder,
PRInt32 aContentVariable, PRInt32 aContentVariable,
PRInt32 aIdVariable, PRInt32 aIdVariable,
nsIAtom* aTag) nsIAtom* aTag)
: TestNode(aParent), : TestNode(aParent),
mConflictSet(aConflictSet), mConflictSet(aConflictSet),
mDocument(aDocument), mDocument(aDocument),
mRoot(aRoot), mBuilder(aBuilder),
mContentVariable(aContentVariable), mContentVariable(aContentVariable),
mIdVariable(aIdVariable), mIdVariable(aIdVariable),
mTag(aTag) mTag(aTag)
@ -107,6 +82,21 @@ nsContentTestNode::nsContentTestNode(InnerNode* aParent,
#endif #endif
} }
#ifdef PR_LOGGING
static void
ElementToString(nsIContent *aContent, nsString &aResult)
{
aResult.Truncate();
nsCOMPtr<nsIAtom> tag;
aContent->GetTag(*getter_AddRefs(tag));
tag->ToString(aResult);
aResult.Append(PRUnichar('@'));
aResult.AppendInt(PRInt32(aContent), 16);
}
#endif
nsresult nsresult
nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
{ {
@ -124,6 +114,22 @@ nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void*
Value idValue; Value idValue;
PRBool hasIdBinding = inst->mAssignments.GetAssignmentFor(mIdVariable, &idValue); PRBool hasIdBinding = inst->mAssignments.GetAssignmentFor(mIdVariable, &idValue);
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
nsAutoString content(NS_LITERAL_STRING("(unbound)"));
if (hasContentBinding)
ElementToString(VALUE_TO_ICONTENT(contentValue), content);
const char *id = "(unbound)";
if (hasIdBinding)
VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&id);
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
("nsContentTestNode[%p]: FilterInstantiations() content=%s id=%s",
this, NS_LossyConvertUCS2toASCII(content).get(), id));
}
#endif
if (hasContentBinding && hasIdBinding) { if (hasContentBinding && hasIdBinding) {
// both are bound, consistency check // both are bound, consistency check
PRBool consistent = PR_TRUE; PRBool consistent = PR_TRUE;
@ -147,6 +153,9 @@ nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void*
consistent = PR_FALSE; consistent = PR_FALSE;
} }
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
(" consistency check => %s", consistent ? "passed" : "failed"));
if (consistent) { if (consistent) {
Element* element = Element* element =
nsContentTestNode::Element::Create(mConflictSet.GetPool(), nsContentTestNode::Element::Create(mConflictSet.GetPool(),
@ -172,8 +181,18 @@ nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void*
nsCOMPtr<nsIAtom> tag; nsCOMPtr<nsIAtom> tag;
content->GetTag(*getter_AddRefs(tag)); content->GetTag(*getter_AddRefs(tag));
if (tag != mTag) if (tag != mTag) {
consistent = PR_FALSE; consistent = PR_FALSE;
const PRUnichar *expected, *actual;
mTag->GetUnicode(&expected);
tag->GetUnicode(&actual);
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
(" => tag mismatch; expected %s, actual %s",
NS_LossyConvertUCS2toASCII(expected).get(),
NS_LossyConvertUCS2toASCII(actual).get()));
}
} }
if (consistent) { if (consistent) {
@ -181,6 +200,15 @@ nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void*
nsXULContentUtils::GetElementRefResource(content, getter_AddRefs(resource)); nsXULContentUtils::GetElementRefResource(content, getter_AddRefs(resource));
if (resource) { if (resource) {
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
const char *str;
resource->GetValueConst(&str);
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
(" => [%s]", str));
}
#endif
Instantiation newinst = *inst; Instantiation newinst = *inst;
newinst.AddAssignment(mIdVariable, Value(resource.get())); newinst.AddAssignment(mIdVariable, Value(resource.get()));
@ -194,6 +222,10 @@ nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void*
aInstantiations.Insert(inst, newinst); aInstantiations.Insert(inst, newinst);
} }
else {
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
(" => element has no resource"));
}
} }
aInstantiations.Erase(inst--); aInstantiations.Erase(inst--);
@ -201,21 +233,19 @@ nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void*
else if (hasIdBinding) { else if (hasIdBinding) {
// the 'id' is bound, find elements in the content tree that match // the 'id' is bound, find elements in the content tree that match
const char* uri; const char* uri;
rv = VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&uri); VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&uri);
if (NS_FAILED(rv)) return rv;
mDocument->GetElementsForID(NS_ConvertUTF8toUCS2(uri), elements);
rv = mDocument->GetElementsForID(NS_ConvertUTF8toUCS2(uri), elements);
if (NS_FAILED(rv)) return rv;
PRUint32 count; PRUint32 count;
rv = elements->Count(&count); elements->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 j = PRInt32(count) - 1; j >= 0; --j) { for (PRInt32 j = PRInt32(count) - 1; j >= 0; --j) {
nsISupports* isupports = elements->ElementAt(j); nsISupports* isupports = elements->ElementAt(j);
nsCOMPtr<nsIContent> content = do_QueryInterface(isupports); nsCOMPtr<nsIContent> content = do_QueryInterface(isupports);
NS_IF_RELEASE(isupports); NS_IF_RELEASE(isupports);
if (IsElementContainedBy(content, mRoot)) { if (IsElementInBuilder(content, mBuilder)) {
if (mTag) { if (mTag) {
// If we've got a tag, check it to ensure // If we've got a tag, check it to ensure
// we're consistent. // we're consistent.
@ -226,6 +256,16 @@ nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void*
continue; continue;
} }
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
nsAutoString str;
ElementToString(content, str);
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
(" => %s", NS_LossyConvertUCS2toASCII(str).get()));
}
#endif
Instantiation newinst = *inst; Instantiation newinst = *inst;
newinst.AddAssignment(mContentVariable, Value(content.get())); newinst.AddAssignment(mContentVariable, Value(content.get()));

View File

@ -45,6 +45,7 @@
#include "nsFixedSizeAllocator.h" #include "nsFixedSizeAllocator.h"
#include "nsIAtom.h" #include "nsIAtom.h"
class nsIXULTemplateBuilder;
class nsIXULDocument; class nsIXULDocument;
class nsConflictSet; class nsConflictSet;
@ -54,7 +55,7 @@ public:
nsContentTestNode(InnerNode* aParent, nsContentTestNode(InnerNode* aParent,
nsConflictSet& aConflictSet, nsConflictSet& aConflictSet,
nsIXULDocument* aDocument, nsIXULDocument* aDocument,
nsIContent* aRoot, nsIXULTemplateBuilder* aBuilder,
PRInt32 aContentVariable, PRInt32 aContentVariable,
PRInt32 aIdVariable, PRInt32 aIdVariable,
nsIAtom* aTag); nsIAtom* aTag);
@ -112,14 +113,11 @@ public:
protected: protected:
nsConflictSet& mConflictSet; nsConflictSet& mConflictSet;
nsIXULDocument* mDocument; // [WEAK] because we know the document will outlive us nsIXULDocument* mDocument; // [WEAK] because we know the document will outlive us
nsCOMPtr<nsIContent> mRoot; nsIXULTemplateBuilder *mBuilder;
PRInt32 mContentVariable; PRInt32 mContentVariable;
PRInt32 mIdVariable; PRInt32 mIdVariable;
nsCOMPtr<nsIAtom> mTag; nsCOMPtr<nsIAtom> mTag;
}; };
extern PRBool
IsElementContainedBy(nsIContent* aElement, nsIContent* aContainer);
#endif // nsContentTestNode_h__ #endif // nsContentTestNode_h__

View File

@ -70,6 +70,7 @@
#include "nsXULContentUtils.h" #include "nsXULContentUtils.h"
#include "nsXULElement.h" #include "nsXULElement.h"
#include "nsXULTemplateBuilder.h" #include "nsXULTemplateBuilder.h"
#include "nsSupportsArray.h"
#include "jsapi.h" #include "jsapi.h"
#include "pldhash.h" #include "pldhash.h"
@ -82,6 +83,38 @@ static NS_DEFINE_CID(kTextNodeCID, NS_TEXTNODE_CID);
static NS_DEFINE_CID(kXMLElementFactoryCID, NS_XML_ELEMENT_FACTORY_CID); static NS_DEFINE_CID(kXMLElementFactoryCID, NS_XML_ELEMENT_FACTORY_CID);
static NS_DEFINE_CID(kXULSortServiceCID, NS_XULSORTSERVICE_CID); static NS_DEFINE_CID(kXULSortServiceCID, NS_XULSORTSERVICE_CID);
PRBool
IsElementInBuilder(nsIContent *aContent, nsIXULTemplateBuilder *aBuilder)
{
// Make sure that the element is contained within the heirarchy
// that we're supposed to be processing.
nsCOMPtr<nsIDocument> doc;
aContent->GetDocument(*getter_AddRefs(doc));
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
if (! xuldoc)
return PR_FALSE;
nsCOMPtr<nsIContent> content = dont_QueryInterface(aContent);
do {
nsCOMPtr<nsIXULTemplateBuilder> builder;
xuldoc->GetTemplateBuilderFor(content, getter_AddRefs(builder));
if (builder) {
if (builder == aBuilder)
return PR_TRUE; // aBuilder is the builder for this element.
// We found a builder, but it's not aBuilder.
break;
}
nsCOMPtr<nsIContent> parent;
content->GetParent(*getter_AddRefs(parent));
content = parent;
} while (content);
return PR_FALSE;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// //
// Return values for EnsureElementHasGenericChild() // Return values for EnsureElementHasGenericChild()
@ -126,9 +159,6 @@ protected:
nsresult Init(); nsresult Init();
// Implementation methods // Implementation methods
PRBool
IsElementInBuilder(nsIContent *aElement);
nsresult nsresult
OpenContainer(nsIContent* aElement); OpenContainer(nsIContent* aElement);
@ -930,6 +960,9 @@ nsXULContentBuilder::SynchronizeUsingTemplate(nsIContent* aTemplateNode,
rv = aTemplateNode->GetAttrCount(numAttribs); rv = aTemplateNode->GetAttrCount(numAttribs);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
// XXXwaterson. Ugh, we just checked the failure code, above. Why
// do it again? This method needs a scrub-down, and could stand
// to have some of this bogo-error checking removed.
if (rv == NS_CONTENT_ATTR_HAS_VALUE) { if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
for (PRInt32 aLoop=0; aLoop<numAttribs; aLoop++) { for (PRInt32 aLoop=0; aLoop<numAttribs; aLoop++) {
PRInt32 attribNameSpaceID; PRInt32 attribNameSpaceID;
@ -1011,7 +1044,6 @@ nsXULContentBuilder::SynchronizeUsingTemplate(nsIContent* aTemplateNode,
return NS_OK; return NS_OK;
} }
PRBool PRBool
nsXULContentBuilder::IsDirectlyContainedBy(nsIContent* aChild, nsIContent* aParent) nsXULContentBuilder::IsDirectlyContainedBy(nsIContent* aChild, nsIContent* aParent)
{ {
@ -1751,7 +1783,7 @@ nsXULContentBuilder::CreateContents(nsIContent* aElement)
if (! aElement) if (! aElement)
return NS_ERROR_NULL_POINTER; return NS_ERROR_NULL_POINTER;
NS_ASSERTION(IsElementContainedBy(aElement, mRoot), "element not managed by this template builder"); NS_ASSERTION(IsElementInBuilder(aElement, this), "element not managed by this template builder");
return CreateTemplateAndContainerContents(aElement, nsnull /* don't care */, nsnull /* don't care */); return CreateTemplateAndContainerContents(aElement, nsnull /* don't care */, nsnull /* don't care */);
} }
@ -1907,26 +1939,13 @@ nsXULContentBuilder::SynchronizeMatch(nsTemplateMatch* match, const VariableSet&
} }
#endif #endif
Value parentValue;
match->mAssignments.GetAssignmentFor(mContentVar, &parentValue);
nsIContent* parent = VALUE_TO_ICONTENT(parentValue);
// Now that we've got the resource of the member variable, we // Now that we've got the resource of the member variable, we
// should be able to update its kids appropriately // should be able to update its kids appropriately
nsresult rv; nsSupportsArray elements;
nsCOMPtr<nsISupportsArray> elements; GetElementsForResource(resource, &elements);
rv = NS_NewISupportsArray(getter_AddRefs(elements));
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create new ISupportsArray");
if (NS_FAILED(rv)) return rv;
rv = GetElementsForResource(resource, elements); PRUint32 cnt = 0;
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to retrieve elements from resource"); elements.Count(&cnt);
if (NS_FAILED(rv)) return rv;
PRUint32 cnt;
rv = elements->Count(&cnt);
if (NS_FAILED(rv)) return rv;
#ifdef PR_LOGGING #ifdef PR_LOGGING
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG) && cnt == 0) { if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG) && cnt == 0) {
@ -1939,24 +1958,19 @@ nsXULContentBuilder::SynchronizeMatch(nsTemplateMatch* match, const VariableSet&
#endif #endif
for (PRInt32 i = PRInt32(cnt) - 1; i >= 0; --i) { for (PRInt32 i = PRInt32(cnt) - 1; i >= 0; --i) {
nsISupports* isupports = elements->ElementAt(i); nsCOMPtr<nsIContent> element = do_QueryElementAt(&elements, i);
nsCOMPtr<nsIContent> element( do_QueryInterface(isupports) ); if (! IsElementInBuilder(element, this))
NS_IF_RELEASE(isupports);
// If the element is contained by the parent of the rule
// that we've just matched, then it's the wrong element.
if (! IsElementContainedBy(element, parent))
continue; continue;
nsCOMPtr<nsIContent> templateNode; nsCOMPtr<nsIContent> templateNode;
mTemplateMap.GetTemplateFor(element, getter_AddRefs(templateNode)); mTemplateMap.GetTemplateFor(element, getter_AddRefs(templateNode));
NS_ASSERTION(templateNode, "couldn't find template node for element");
if (! templateNode) if (! templateNode)
return NS_ERROR_UNEXPECTED; continue;
// this node was created by a XUL template, so update it accordingly // this node was created by a XUL template, so update it accordingly
rv = SynchronizeUsingTemplate(templateNode, element, *match, modified); SynchronizeUsingTemplate(templateNode, element, *match, modified);
if (NS_FAILED(rv)) return rv;
} }
#ifdef PR_LOGGING #ifdef PR_LOGGING
@ -1977,43 +1991,11 @@ nsXULContentBuilder::SynchronizeMatch(nsTemplateMatch* match, const VariableSet&
// Implementation methods // Implementation methods
// //
PRBool
nsXULContentBuilder::IsElementInBuilder(nsIContent *aContent)
{
// Make sure that the element is contained within the heirarchy
// that we're supposed to be processing.
nsCOMPtr<nsIDocument> doc;
aContent->GetDocument(*getter_AddRefs(doc));
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
if (! xuldoc)
return PR_FALSE;
nsCOMPtr<nsIContent> content = dont_QueryInterface(aContent);
do {
nsCOMPtr<nsIXULTemplateBuilder> builder;
xuldoc->GetTemplateBuilderFor(content, getter_AddRefs(builder));
if (builder) {
if (builder == NS_STATIC_CAST(nsIXULTemplateBuilder *, this))
return PR_TRUE; // We're the builder for this element.
// We found a builder, but it's not us.
break;
}
nsCOMPtr<nsIContent> parent;
content->GetParent(*getter_AddRefs(parent));
content = parent;
} while (content);
return PR_FALSE;
}
nsresult nsresult
nsXULContentBuilder::OpenContainer(nsIContent* aElement) nsXULContentBuilder::OpenContainer(nsIContent* aElement)
{ {
// See if we're responsible for this element // See if we're responsible for this element
if (! IsElementInBuilder(aElement)) if (! IsElementInBuilder(aElement, this))
return NS_OK; return NS_OK;
nsCOMPtr<nsIRDFResource> resource; nsCOMPtr<nsIRDFResource> resource;
@ -2055,7 +2037,7 @@ nsresult
nsXULContentBuilder::CloseContainer(nsIContent* aElement) nsXULContentBuilder::CloseContainer(nsIContent* aElement)
{ {
// See if we're responsible for this element // See if we're responsible for this element
if (! IsElementInBuilder(aElement)) if (! IsElementInBuilder(aElement, this))
return NS_OK; return NS_OK;
nsCOMPtr<nsIAtom> tag; nsCOMPtr<nsIAtom> tag;
@ -2143,7 +2125,7 @@ nsXULContentBuilder::InitializeRuleNetworkForSimpleRules(InnerNode** aChildNode)
new nsContentTestNode(mRules.GetRoot(), new nsContentTestNode(mRules.GetRoot(),
mConflictSet, mConflictSet,
xuldoc, xuldoc,
mRoot, this,
mContentVar, mContentVar,
mContainerVar, mContainerVar,
nsnull); nsnull);
@ -2263,7 +2245,7 @@ nsXULContentBuilder::CompileContentCondition(nsTemplateRule* aRule,
new nsContentTestNode(aParentNode, new nsContentTestNode(aParentNode,
mConflictSet, mConflictSet,
xuldoc, xuldoc,
mRoot, this,
mContentVar, // XXX see above mContentVar, // XXX see above
urivar, urivar,
tag); tag);

View File

@ -469,9 +469,8 @@ nsXULTemplateBuilder::Propagate(nsIRDFResource* aSource,
nsRDFTestNode* rdftestnode = NS_STATIC_CAST(nsRDFTestNode*, *i); nsRDFTestNode* rdftestnode = NS_STATIC_CAST(nsRDFTestNode*, *i);
Instantiation seed; Instantiation seed;
if (rdftestnode->CanPropagate(aSource, aProperty, aTarget, seed)) { if (rdftestnode->CanPropagate(aSource, aProperty, aTarget, seed))
livenodes.Add(rdftestnode); livenodes.Add(rdftestnode);
}
} }
} }
@ -573,23 +572,15 @@ nsXULTemplateBuilder::OnAssert(nsIRDFDataSource* aDataSource,
if (IsActivated(aSource)) if (IsActivated(aSource))
return NS_OK; return NS_OK;
nsresult rv;
if (mCache) if (mCache)
mCache->Assert(aSource, aProperty, aTarget, PR_TRUE /* XXX should be value passed in */); mCache->Assert(aSource, aProperty, aTarget, PR_TRUE /* XXX should be value passed in */);
LOG("onassert", aSource, aProperty, aTarget); LOG("onassert", aSource, aProperty, aTarget);
nsClusterKeySet newkeys; nsClusterKeySet newkeys;
rv = Propagate(aSource, aProperty, aTarget, newkeys); Propagate(aSource, aProperty, aTarget, newkeys);
if (NS_FAILED(rv)) return rv; FireNewlyMatchedRules(newkeys);
SynchronizeAll(aSource, aProperty, nsnull, aTarget);
rv = FireNewlyMatchedRules(newkeys);
if (NS_FAILED(rv)) return rv;
rv = SynchronizeAll(aSource, aProperty, nsnull, aTarget);
if (NS_FAILED(rv)) return rv;
return NS_OK; return NS_OK;
} }
@ -646,19 +637,13 @@ nsXULTemplateBuilder::OnUnassert(nsIRDFDataSource* aDataSource,
if (IsActivated(aSource)) if (IsActivated(aSource))
return NS_OK; return NS_OK;
nsresult rv;
if (mCache) if (mCache)
mCache->Unassert(aSource, aProperty, aTarget); mCache->Unassert(aSource, aProperty, aTarget);
LOG("onunassert", aSource, aProperty, aTarget); LOG("onunassert", aSource, aProperty, aTarget);
rv = Retract(aSource, aProperty, aTarget); Retract(aSource, aProperty, aTarget);
if (NS_FAILED(rv)) return rv; SynchronizeAll(aSource, aProperty, aTarget, nsnull);
rv = SynchronizeAll(aSource, aProperty, aTarget, nsnull);
if (NS_FAILED(rv)) return rv;
return NS_OK; return NS_OK;
} }
@ -688,30 +673,22 @@ nsXULTemplateBuilder::OnChange(nsIRDFDataSource* aDataSource,
mCache->Assert(aSource, aProperty, aNewTarget, PR_TRUE); mCache->Assert(aSource, aProperty, aNewTarget, PR_TRUE);
} }
nsresult rv;
LOG("onchange", aSource, aProperty, aNewTarget); LOG("onchange", aSource, aProperty, aNewTarget);
if (aOldTarget) { if (aOldTarget) {
// Pull any old rules that were relying on aOldTarget // Pull any old rules that were relying on aOldTarget
rv = Retract(aSource, aProperty, aOldTarget); Retract(aSource, aProperty, aOldTarget);
if (NS_FAILED(rv)) return rv;
} }
if (aNewTarget) { if (aNewTarget) {
// Fire any new rules that are activated by aNewTarget // Fire any new rules that are activated by aNewTarget
nsClusterKeySet newkeys; nsClusterKeySet newkeys;
rv = Propagate(aSource, aProperty, aNewTarget, newkeys); Propagate(aSource, aProperty, aNewTarget, newkeys);
if (NS_FAILED(rv)) return rv; FireNewlyMatchedRules(newkeys);
rv = FireNewlyMatchedRules(newkeys);
if (NS_FAILED(rv)) return rv;
} }
// Synchronize any of the content model that may have changed. // Synchronize any of the content model that may have changed.
rv = SynchronizeAll(aSource, aProperty, aOldTarget, aNewTarget); SynchronizeAll(aSource, aProperty, aOldTarget, aNewTarget);
if (NS_FAILED(rv)) return rv;
return NS_OK; return NS_OK;
} }