Bug 276431 patch 12c: Make nsSVGRenderingObserver into a generic interface, and rename the existing impl to nsSVGIDRenderingObserver. r=roc a=blocking

This commit is contained in:
Daniel Holbert 2010-09-08 13:40:39 -07:00
parent b2deb14937
commit 2ac6d89f7e
2 changed files with 116 additions and 73 deletions

View File

@ -48,24 +48,52 @@
using namespace mozilla;
using namespace mozilla::dom;
// nsSVGRenderingObserver impl
NS_IMPL_ISUPPORTS1(nsSVGRenderingObserver, nsIMutationObserver)
void
nsSVGRenderingObserver::StartListening()
{
Element* target = GetTarget();
if (target) {
target->AddMutationObserver(this);
}
}
void
nsSVGRenderingObserver::StopListening()
{
Element* target = GetTarget();
if (target) {
target->RemoveMutationObserver(this);
if (mInObserverList) {
nsSVGEffects::RemoveRenderingObserver(target, this);
mInObserverList = PR_FALSE;
}
}
NS_ASSERTION(!mInObserverList, "still in an observer list?");
}
/**
* Note that in the current setup there are two separate observer lists.
*
* In nsSVGRenderingObserver's ctor, the new object adds itself to the mutation
* observer list maintained by the referenced element. In this way the
* nsSVGRenderingObserver is notified if there are any attribute or content
* In nsSVGIDRenderingObserver's ctor, the new object adds itself to the
* mutation observer list maintained by the referenced element. In this way the
* nsSVGIDRenderingObserver is notified if there are any attribute or content
* tree changes to the element or any of its *descendants*.
*
* In nsSVGRenderingObserver::GetReferencedElement() the nsSVGRenderingObserver
* object also adds itself to an nsSVGRenderingObserverList object belonging
* to the referenced element.
* In nsSVGIDRenderingObserver::GetReferencedElement() the
* nsSVGIDRenderingObserver object also adds itself to an
* nsSVGRenderingObserverList object belonging to the referenced
* element.
*
* XXX: it would be nice to have a clear and concise executive summary of the
* benefits/necessity of maintaining a second observer list.
*/
NS_IMPL_ISUPPORTS1(nsSVGRenderingObserver, nsIMutationObserver)
#ifdef _MSC_VER
// Disable "warning C4355: 'this' : used in base member initializer list".
// We can ignore that warning because we know that mElement's constructor
@ -73,12 +101,11 @@ NS_IMPL_ISUPPORTS1(nsSVGRenderingObserver, nsIMutationObserver)
#pragma warning(push)
#pragma warning(disable:4355)
#endif
nsSVGRenderingObserver::nsSVGRenderingObserver(nsIURI *aURI,
nsIFrame *aFrame,
PRBool aReferenceImage)
nsSVGIDRenderingObserver::nsSVGIDRenderingObserver(nsIURI *aURI,
nsIFrame *aFrame,
PRBool aReferenceImage)
: mElement(this), mFrame(aFrame),
mFramePresShell(aFrame->PresContext()->PresShell()),
mInObserverList(PR_FALSE)
mFramePresShell(aFrame->PresContext()->PresShell())
#ifdef _MSC_VER
#pragma warning(pop)
#endif
@ -88,32 +115,11 @@ nsSVGRenderingObserver::nsSVGRenderingObserver(nsIURI *aURI,
StartListening();
}
nsSVGRenderingObserver::~nsSVGRenderingObserver()
nsSVGIDRenderingObserver::~nsSVGIDRenderingObserver()
{
StopListening();
}
void
nsSVGRenderingObserver::StartListening()
{
if (mElement.get()) {
mElement.get()->AddMutationObserver(this);
}
}
void
nsSVGRenderingObserver::StopListening()
{
if (mElement.get()) {
mElement.get()->RemoveMutationObserver(this);
if (mInObserverList) {
nsSVGEffects::RemoveRenderingObserver(mElement.get(), this);
mInObserverList = PR_FALSE;
}
}
NS_ASSERTION(!mInObserverList, "still in an observer list?");
}
static nsSVGRenderingObserverList *
GetObserverList(Element *aElement)
{
@ -124,20 +130,21 @@ GetObserverList(Element *aElement)
Element*
nsSVGRenderingObserver::GetReferencedElement()
{
Element* target = GetTarget();
#ifdef DEBUG
if (mElement.get()) {
nsSVGRenderingObserverList *observerList = GetObserverList(mElement.get());
if (target) {
nsSVGRenderingObserverList *observerList = GetObserverList(target);
PRBool inObserverList = observerList && observerList->Contains(this);
NS_ASSERTION(inObserverList == mInObserverList, "failed to track whether we're in our referenced element's observer list!");
} else {
NS_ASSERTION(!mInObserverList, "In whose observer list are we, then?");
}
#endif
if (mElement.get() && !mInObserverList) {
nsSVGEffects::AddRenderingObserver(mElement.get(), this);
if (target && !mInObserverList) {
nsSVGEffects::AddRenderingObserver(target, this);
mInObserverList = PR_TRUE;
}
return mElement.get();
return target;
}
nsIFrame*
@ -160,7 +167,7 @@ nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, PRBool* aOK)
}
void
nsSVGRenderingObserver::DoUpdate()
nsSVGIDRenderingObserver::DoUpdate()
{
if (mFramePresShell->IsDestroying()) {
// mFrame is no longer valid. Bail out.
@ -237,7 +244,7 @@ nsSVGRenderingObserver::ContentRemoved(nsIDocument *aDocument,
}
NS_IMPL_ISUPPORTS_INHERITED1(nsSVGFilterProperty,
nsSVGRenderingObserver,
nsSVGIDRenderingObserver,
nsISVGFilterProperty)
nsSVGFilterFrame *
@ -258,7 +265,7 @@ InvalidateAllContinuations(nsIFrame* aFrame)
void
nsSVGFilterProperty::DoUpdate()
{
nsSVGRenderingObserver::DoUpdate();
nsSVGIDRenderingObserver::DoUpdate();
if (!mFrame)
return;
@ -276,7 +283,7 @@ nsSVGFilterProperty::DoUpdate()
void
nsSVGMarkerProperty::DoUpdate()
{
nsSVGRenderingObserver::DoUpdate();
nsSVGIDRenderingObserver::DoUpdate();
if (!mFrame)
return;
@ -293,7 +300,7 @@ nsSVGMarkerProperty::DoUpdate()
void
nsSVGTextPathProperty::DoUpdate()
{
nsSVGRenderingObserver::DoUpdate();
nsSVGIDRenderingObserver::DoUpdate();
if (!mFrame)
return;
@ -308,7 +315,7 @@ nsSVGTextPathProperty::DoUpdate()
void
nsSVGPaintingProperty::DoUpdate()
{
nsSVGRenderingObserver::DoUpdate();
nsSVGIDRenderingObserver::DoUpdate();
if (!mFrame)
return;

View File

@ -51,21 +51,24 @@ class nsSVGFilterFrame;
class nsSVGMaskFrame;
/*
* SVG elements reference supporting resources by element ID. We need to
* track when those resources change and when the DOM changes in ways
* that affect which element is referenced by a given ID (e.g., when
* element IDs change). The code here is responsible for that.
*
* When a frame references a supporting resource, we create a property
* object derived from nsSVGRenderingObserver to manage the relationship. The
* property object is attached to the referencing frame.
* This interface allows us to be notified when a piece of SVG content is
* re-rendered.
*
* Concrete implementations of this interface need to implement
* "GetTarget()" to specify the piece of SVG content that they'd like to
* monitor, and they need to implement "DoUpdate" to specify how we'll react
* when that content gets re-rendered. They also need to implement a
* constructor and destructor, which should call StartListening and
* StopListening, respectively.
*/
class nsSVGRenderingObserver : public nsStubMutationObserver {
public:
typedef mozilla::dom::Element Element;
nsSVGRenderingObserver(nsIURI* aURI, nsIFrame *aFrame,
PRBool aReferenceImage);
virtual ~nsSVGRenderingObserver();
nsSVGRenderingObserver()
: mInObserverList(PR_FALSE)
{}
virtual ~nsSVGRenderingObserver()
{}
// nsISupports
NS_DECL_ISUPPORTS
@ -77,24 +80,59 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
void InvalidateViaReferencedElement();
Element* GetReferencedElement();
nsIFrame* GetReferencedFrame();
/**
* @param aOK this is only for the convenience of callers. We set *aOK to false
* if this function returns null.
*/
nsIFrame* GetReferencedFrame(nsIAtom* aFrameType, PRBool* aOK);
Element* GetReferencedElement();
protected:
// This is called when the referenced resource changes.
virtual void DoUpdate();
// Non-virtual protected methods
void StartListening();
void StopListening();
// Virtual protected methods
virtual void DoUpdate() = 0; // called when the referenced resource changes.
// This is an internally-used version of GetReferencedElement that doesn't
// forcibly add us as an observer. (whereas GetReferencedElement does)
virtual Element* GetTarget() = 0;
// Whether we're in our referenced element's observer list at this time.
PRPackedBool mInObserverList;
};
/*
* SVG elements reference supporting resources by element ID. We need to
* track when those resources change and when the DOM changes in ways
* that affect which element is referenced by a given ID (e.g., when
* element IDs change). The code here is responsible for that.
*
* When a frame references a supporting resource, we create a property
* object derived from nsSVGIDRenderingObserver to manage the relationship. The
* property object is attached to the referencing frame.
*/
class nsSVGIDRenderingObserver : public nsSVGRenderingObserver {
public:
typedef mozilla::dom::Element Element;
nsSVGIDRenderingObserver(nsIURI* aURI, nsIFrame *aFrame,
PRBool aReferenceImage);
virtual ~nsSVGIDRenderingObserver();
protected:
Element* GetTarget() { return mElement.get(); }
// This is called when the referenced resource changes.
virtual void DoUpdate();
class SourceReference : public nsReferencedElement {
public:
SourceReference(nsSVGRenderingObserver* aContainer) : mContainer(aContainer) {}
SourceReference(nsSVGIDRenderingObserver* aContainer) : mContainer(aContainer) {}
protected:
virtual void ElementChanged(Element* aFrom, Element* aTo) {
mContainer->StopListening();
@ -108,7 +146,7 @@ protected:
*/
virtual PRBool IsPersistent() { return PR_TRUE; }
private:
nsSVGRenderingObserver* mContainer;
nsSVGIDRenderingObserver* mContainer;
};
SourceReference mElement;
@ -120,16 +158,14 @@ protected:
// we test the presshell to see if it's destroying itself. If it is,
// then the frame pointer is not valid and we know the frame has gone away.
nsIPresShell *mFramePresShell;
// Whether we're in our referenced element's observer list at this time.
PRPackedBool mInObserverList;
};
class nsSVGFilterProperty :
public nsSVGRenderingObserver, public nsISVGFilterProperty {
public nsSVGIDRenderingObserver, public nsISVGFilterProperty {
public:
nsSVGFilterProperty(nsIURI *aURI, nsIFrame *aFilteredFrame,
PRBool aReferenceImage)
: nsSVGRenderingObserver(aURI, aFilteredFrame, aReferenceImage) {}
: nsSVGIDRenderingObserver(aURI, aFilteredFrame, aReferenceImage) {}
/**
* @return the filter frame, or null if there is no filter frame
@ -147,28 +183,28 @@ private:
virtual void DoUpdate();
};
class nsSVGMarkerProperty : public nsSVGRenderingObserver {
class nsSVGMarkerProperty : public nsSVGIDRenderingObserver {
public:
nsSVGMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, PRBool aReferenceImage)
: nsSVGRenderingObserver(aURI, aFrame, aReferenceImage) {}
: nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
protected:
virtual void DoUpdate();
};
class nsSVGTextPathProperty : public nsSVGRenderingObserver {
class nsSVGTextPathProperty : public nsSVGIDRenderingObserver {
public:
nsSVGTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, PRBool aReferenceImage)
: nsSVGRenderingObserver(aURI, aFrame, aReferenceImage) {}
: nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
protected:
virtual void DoUpdate();
};
class nsSVGPaintingProperty : public nsSVGRenderingObserver {
class nsSVGPaintingProperty : public nsSVGIDRenderingObserver {
public:
nsSVGPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, PRBool aReferenceImage)
: nsSVGRenderingObserver(aURI, aFrame, aReferenceImage) {}
: nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {}
protected:
virtual void DoUpdate();