2008-08-07 18:34:43 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2008-08-07 18:34:43 -07:00
|
|
|
|
2012-03-26 04:58:59 -07:00
|
|
|
// Main header first:
|
2008-08-07 18:34:43 -07:00
|
|
|
#include "nsSVGEffects.h"
|
2012-03-26 04:58:59 -07:00
|
|
|
|
|
|
|
// Keep others in (case-insensitive) order:
|
|
|
|
#include "nsCSSFrameConstructor.h"
|
2008-08-07 18:34:43 -07:00
|
|
|
#include "nsISupportsImpl.h"
|
2008-09-30 17:51:05 -07:00
|
|
|
#include "nsSVGClipPathFrame.h"
|
2012-03-26 04:58:59 -07:00
|
|
|
#include "nsSVGFilterFrame.h"
|
2008-09-30 17:51:05 -07:00
|
|
|
#include "nsSVGMaskFrame.h"
|
2008-10-11 04:29:35 -07:00
|
|
|
#include "nsSVGTextPathFrame.h"
|
2008-09-30 17:51:05 -07:00
|
|
|
|
2010-03-28 18:46:55 -07:00
|
|
|
using namespace mozilla;
|
2010-08-13 06:31:31 -07:00
|
|
|
using namespace mozilla::dom;
|
2010-03-28 18:46:55 -07:00
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
// 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);
|
2011-10-17 07:59:28 -07:00
|
|
|
mInObserverList = false;
|
2010-09-08 13:40:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_ASSERTION(!mInObserverList, "still in an observer list?");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-01-23 10:47:53 -08:00
|
|
|
/**
|
|
|
|
* Note that in the current setup there are two separate observer lists.
|
|
|
|
*
|
2010-09-08 13:40:39 -07:00
|
|
|
* 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
|
2010-01-23 10:47:53 -08:00
|
|
|
* tree changes to the element or any of its *descendants*.
|
|
|
|
*
|
2010-09-08 13:40:39 -07:00
|
|
|
* In nsSVGIDRenderingObserver::GetReferencedElement() the
|
|
|
|
* nsSVGIDRenderingObserver object also adds itself to an
|
|
|
|
* nsSVGRenderingObserverList object belonging to the referenced
|
|
|
|
* element.
|
2010-01-23 10:47:53 -08:00
|
|
|
*
|
|
|
|
* XXX: it would be nice to have a clear and concise executive summary of the
|
|
|
|
* benefits/necessity of maintaining a second observer list.
|
|
|
|
*/
|
|
|
|
|
2010-01-13 00:18:48 -08:00
|
|
|
#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
|
|
|
|
// doesn't dereference the pointer passed to it.
|
|
|
|
#pragma warning(push)
|
|
|
|
#pragma warning(disable:4355)
|
|
|
|
#endif
|
2010-09-08 13:40:39 -07:00
|
|
|
nsSVGIDRenderingObserver::nsSVGIDRenderingObserver(nsIURI *aURI,
|
|
|
|
nsIFrame *aFrame,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aReferenceImage)
|
2008-09-30 17:51:05 -07:00
|
|
|
: mElement(this), mFrame(aFrame),
|
2010-09-08 13:40:39 -07:00
|
|
|
mFramePresShell(aFrame->PresContext()->PresShell())
|
2010-01-13 00:18:48 -08:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif
|
2008-08-07 18:34:43 -07:00
|
|
|
{
|
|
|
|
// Start watching the target element
|
2011-10-17 07:59:28 -07:00
|
|
|
mElement.Reset(aFrame->GetContent(), aURI, true, aReferenceImage);
|
2010-08-13 06:31:31 -07:00
|
|
|
StartListening();
|
|
|
|
}
|
|
|
|
|
2010-09-08 13:40:39 -07:00
|
|
|
nsSVGIDRenderingObserver::~nsSVGIDRenderingObserver()
|
2010-08-13 06:31:31 -07:00
|
|
|
{
|
|
|
|
StopListening();
|
|
|
|
}
|
|
|
|
|
|
|
|
static nsSVGRenderingObserverList *
|
|
|
|
GetObserverList(Element *aElement)
|
2008-08-07 18:34:43 -07:00
|
|
|
{
|
2010-08-13 06:31:31 -07:00
|
|
|
return static_cast<nsSVGRenderingObserverList*>
|
|
|
|
(aElement->GetProperty(nsGkAtoms::renderingobserverlist));
|
|
|
|
}
|
2008-09-30 17:51:05 -07:00
|
|
|
|
2010-08-13 06:31:31 -07:00
|
|
|
Element*
|
|
|
|
nsSVGRenderingObserver::GetReferencedElement()
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
Element* target = GetTarget();
|
2010-08-13 06:31:31 -07:00
|
|
|
#ifdef DEBUG
|
2010-09-08 13:40:39 -07:00
|
|
|
if (target) {
|
|
|
|
nsSVGRenderingObserverList *observerList = GetObserverList(target);
|
2011-09-28 23:19:26 -07:00
|
|
|
bool inObserverList = observerList && observerList->Contains(this);
|
2010-08-13 06:31:31 -07:00
|
|
|
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?");
|
2008-08-07 18:34:43 -07:00
|
|
|
}
|
2010-08-13 06:31:31 -07:00
|
|
|
#endif
|
2010-09-08 13:40:39 -07:00
|
|
|
if (target && !mInObserverList) {
|
|
|
|
nsSVGEffects::AddRenderingObserver(target, this);
|
2011-10-17 07:59:28 -07:00
|
|
|
mInObserverList = true;
|
2010-08-13 06:31:31 -07:00
|
|
|
}
|
2010-09-08 13:40:39 -07:00
|
|
|
return target;
|
2010-08-13 06:31:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame*
|
|
|
|
nsSVGRenderingObserver::GetReferencedFrame()
|
|
|
|
{
|
|
|
|
Element* referencedElement = GetReferencedElement();
|
2012-07-30 07:20:58 -07:00
|
|
|
return referencedElement ? referencedElement->GetPrimaryFrame() : nullptr;
|
2008-09-30 17:51:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame*
|
2011-09-28 23:19:26 -07:00
|
|
|
nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, bool* aOK)
|
2008-09-30 17:51:05 -07:00
|
|
|
{
|
|
|
|
nsIFrame* frame = GetReferencedFrame();
|
2010-12-19 09:47:01 -08:00
|
|
|
if (frame) {
|
|
|
|
if (frame->GetType() == aFrameType)
|
|
|
|
return frame;
|
|
|
|
if (aOK) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aOK = false;
|
2010-12-19 09:47:01 -08:00
|
|
|
}
|
2008-08-07 18:34:43 -07:00
|
|
|
}
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2008-08-07 18:34:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-08 13:40:39 -07:00
|
|
|
nsSVGIDRenderingObserver::DoUpdate()
|
2008-09-30 17:51:05 -07:00
|
|
|
{
|
2009-03-29 19:54:33 -07:00
|
|
|
if (mFramePresShell->IsDestroying()) {
|
2008-09-30 17:51:05 -07:00
|
|
|
// mFrame is no longer valid. Bail out.
|
2012-07-30 07:20:58 -07:00
|
|
|
mFrame = nullptr;
|
2008-09-30 17:51:05 -07:00
|
|
|
return;
|
|
|
|
}
|
2010-08-13 06:31:31 -07:00
|
|
|
if (mElement.get() && mInObserverList) {
|
|
|
|
nsSVGEffects::RemoveRenderingObserver(mElement.get(), this);
|
2011-10-17 07:59:28 -07:00
|
|
|
mInObserverList = false;
|
2008-09-30 17:51:05 -07:00
|
|
|
}
|
|
|
|
if (mFrame && mFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
|
|
|
// Changes should propagate out to things that might be observing
|
|
|
|
// the referencing frame or its ancestors.
|
|
|
|
nsSVGEffects::InvalidateRenderingObservers(mFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-13 06:31:31 -07:00
|
|
|
nsSVGRenderingObserver::InvalidateViaReferencedElement()
|
2008-09-30 17:51:05 -07:00
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
mInObserverList = false;
|
2008-09-30 17:51:05 -07:00
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
2010-11-16 10:35:59 -08:00
|
|
|
void
|
|
|
|
nsSVGRenderingObserver::NotifyEvictedFromRenderingObserverList()
|
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
mInObserverList = false; // We've been removed from rendering-obs. list.
|
2010-11-16 10:35:59 -08:00
|
|
|
StopListening(); // Remove ourselves from mutation-obs. list.
|
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
void
|
2010-08-24 00:05:56 -07:00
|
|
|
nsSVGRenderingObserver::AttributeChanged(nsIDocument* aDocument,
|
|
|
|
dom::Element* aElement,
|
2008-09-30 17:51:05 -07:00
|
|
|
PRInt32 aNameSpaceID,
|
2010-08-24 00:05:56 -07:00
|
|
|
nsIAtom* aAttribute,
|
2009-12-10 14:36:04 -08:00
|
|
|
PRInt32 aModType)
|
2008-08-07 18:34:43 -07:00
|
|
|
{
|
2010-01-23 10:47:53 -08:00
|
|
|
// An attribute belonging to the element that we are observing *or one of its
|
|
|
|
// descendants* has changed.
|
|
|
|
//
|
|
|
|
// In the case of observing a gradient element, say, we want to know if any
|
|
|
|
// of its 'stop' element children change, but we don't actually want to do
|
|
|
|
// anything for changes to SMIL element children, for example. Maybe it's not
|
|
|
|
// worth having logic to optimize for that, but in most cases it could be a
|
|
|
|
// small check?
|
|
|
|
//
|
|
|
|
// XXXjwatt: do we really want to blindly break the link between our
|
|
|
|
// observers and ourselves for all attribute changes? For non-ID changes
|
|
|
|
// surely that is unnecessary.
|
|
|
|
|
2008-08-07 18:34:43 -07:00
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGRenderingObserver::ContentAppended(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContainer,
|
2010-05-10 18:12:34 -07:00
|
|
|
nsIContent *aFirstNewContent,
|
|
|
|
PRInt32 /* unused */)
|
2008-08-07 18:34:43 -07:00
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGRenderingObserver::ContentInserted(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContainer,
|
|
|
|
nsIContent *aChild,
|
2010-05-10 18:12:34 -07:00
|
|
|
PRInt32 /* unused */)
|
2008-08-07 18:34:43 -07:00
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGRenderingObserver::ContentRemoved(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContainer,
|
|
|
|
nsIContent *aChild,
|
2010-07-21 15:05:17 -07:00
|
|
|
PRInt32 aIndexInContainer,
|
|
|
|
nsIContent *aPreviousSibling)
|
2008-08-07 18:34:43 -07:00
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED1(nsSVGFilterProperty,
|
2010-09-08 13:40:39 -07:00
|
|
|
nsSVGIDRenderingObserver,
|
2008-08-07 18:34:43 -07:00
|
|
|
nsISVGFilterProperty)
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGFilterFrame *
|
2008-10-10 06:14:05 -07:00
|
|
|
nsSVGFilterProperty::GetFilterFrame()
|
|
|
|
{
|
2008-09-30 17:51:05 -07:00
|
|
|
return static_cast<nsSVGFilterFrame *>
|
2012-07-30 07:20:58 -07:00
|
|
|
(GetReferencedFrame(nsGkAtoms::svgFilterFrame, nullptr));
|
2008-09-30 17:51:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
InvalidateAllContinuations(nsIFrame* aFrame)
|
2008-08-07 18:34:43 -07:00
|
|
|
{
|
2012-06-22 03:44:18 -07:00
|
|
|
for (nsIFrame* f = aFrame; f;
|
|
|
|
f = nsLayoutUtils::GetNextContinuationOrSpecialSibling(f)) {
|
2012-07-03 17:24:55 -07:00
|
|
|
f->InvalidateOverflowRect();
|
2008-08-07 18:34:43 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGFilterProperty::DoUpdate()
|
2008-09-30 04:28:20 -07:00
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
nsSVGIDRenderingObserver::DoUpdate();
|
2008-09-30 17:51:05 -07:00
|
|
|
if (!mFrame)
|
2008-08-07 18:34:43 -07:00
|
|
|
return;
|
|
|
|
|
2008-10-27 04:48:20 -07:00
|
|
|
// Repaint asynchronously in case the filter frame is being torn down
|
|
|
|
nsChangeHint changeHint =
|
|
|
|
nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects);
|
|
|
|
|
2012-07-19 21:54:20 -07:00
|
|
|
// Don't need to request UpdateOverflow if we're being reflowed.
|
|
|
|
if (!(mFrame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
|
|
|
|
NS_UpdateHint(changeHint, nsChangeHint_UpdateOverflow);
|
2008-09-30 04:28:20 -07:00
|
|
|
}
|
2008-10-27 04:48:20 -07:00
|
|
|
mFramePresShell->FrameConstructor()->PostRestyleEvent(
|
2010-05-14 10:04:51 -07:00
|
|
|
mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
|
2008-09-30 04:28:20 -07:00
|
|
|
}
|
|
|
|
|
2008-10-10 06:14:05 -07:00
|
|
|
void
|
|
|
|
nsSVGMarkerProperty::DoUpdate()
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
nsSVGIDRenderingObserver::DoUpdate();
|
2008-10-10 06:14:05 -07:00
|
|
|
if (!mFrame)
|
|
|
|
return;
|
|
|
|
|
2009-01-21 17:02:40 -08:00
|
|
|
NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
|
|
|
|
|
2012-07-19 21:54:20 -07:00
|
|
|
// Repaint asynchronously in case the filter frame is being torn down
|
2009-01-21 17:02:40 -08:00
|
|
|
nsChangeHint changeHint =
|
|
|
|
nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects);
|
2012-07-19 21:54:20 -07:00
|
|
|
|
|
|
|
// Don't need to request ReflowFrame if we're being reflowed.
|
|
|
|
if (!(mFrame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
|
|
|
|
// XXXjwatt: We need to unify SVG into standard reflow so we can just use
|
|
|
|
// nsChangeHint_ReflowFrame here.
|
2012-07-21 17:01:44 -07:00
|
|
|
nsSVGUtils::InvalidateAndScheduleReflowSVG(mFrame);
|
2012-07-19 21:54:20 -07:00
|
|
|
}
|
2009-01-21 17:02:40 -08:00
|
|
|
mFramePresShell->FrameConstructor()->PostRestyleEvent(
|
2010-05-14 10:04:51 -07:00
|
|
|
mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
|
2008-10-10 06:14:05 -07:00
|
|
|
}
|
|
|
|
|
2008-10-11 04:29:35 -07:00
|
|
|
void
|
|
|
|
nsSVGTextPathProperty::DoUpdate()
|
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
nsSVGIDRenderingObserver::DoUpdate();
|
2008-10-11 04:29:35 -07:00
|
|
|
if (!mFrame)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
|
|
|
|
|
|
|
|
if (mFrame->GetType() == nsGkAtoms::svgTextPathFrame) {
|
|
|
|
nsSVGTextPathFrame* textPathFrame = static_cast<nsSVGTextPathFrame*>(mFrame);
|
|
|
|
textPathFrame->NotifyGlyphMetricsChange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-30 04:28:20 -07:00
|
|
|
void
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGPaintingProperty::DoUpdate()
|
2008-09-30 04:28:20 -07:00
|
|
|
{
|
2010-09-08 13:40:39 -07:00
|
|
|
nsSVGIDRenderingObserver::DoUpdate();
|
2008-09-30 17:51:05 -07:00
|
|
|
if (!mFrame)
|
2008-09-30 04:28:20 -07:00
|
|
|
return;
|
|
|
|
|
2012-07-30 12:14:18 -07:00
|
|
|
if (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
|
2012-03-20 05:15:53 -07:00
|
|
|
nsSVGUtils::InvalidateBounds(mFrame);
|
2008-09-30 17:51:05 -07:00
|
|
|
} else {
|
|
|
|
InvalidateAllContinuations(mFrame);
|
2008-09-30 04:28:20 -07:00
|
|
|
}
|
2008-08-07 18:34:43 -07:00
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
static nsSVGRenderingObserver *
|
2011-09-28 23:19:26 -07:00
|
|
|
CreateFilterProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
|
2010-08-13 06:36:05 -07:00
|
|
|
{ return new nsSVGFilterProperty(aURI, aFrame, aReferenceImage); }
|
2008-08-07 18:34:43 -07:00
|
|
|
|
2008-10-10 06:14:05 -07:00
|
|
|
static nsSVGRenderingObserver *
|
2011-09-28 23:19:26 -07:00
|
|
|
CreateMarkerProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
|
2010-08-13 06:36:05 -07:00
|
|
|
{ return new nsSVGMarkerProperty(aURI, aFrame, aReferenceImage); }
|
2008-10-10 06:14:05 -07:00
|
|
|
|
2008-10-11 04:29:35 -07:00
|
|
|
static nsSVGRenderingObserver *
|
2011-09-28 23:19:26 -07:00
|
|
|
CreateTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
|
2010-08-13 06:36:05 -07:00
|
|
|
{ return new nsSVGTextPathProperty(aURI, aFrame, aReferenceImage); }
|
2008-10-11 04:29:35 -07:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
static nsSVGRenderingObserver *
|
2011-09-28 23:19:26 -07:00
|
|
|
CreatePaintingProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage)
|
2010-08-13 06:36:05 -07:00
|
|
|
{ return new nsSVGPaintingProperty(aURI, aFrame, aReferenceImage); }
|
2008-08-07 18:34:43 -07:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
static nsSVGRenderingObserver *
|
2010-03-28 18:46:55 -07:00
|
|
|
GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProperty,
|
2011-09-28 23:19:26 -07:00
|
|
|
nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *, bool))
|
2008-08-07 18:34:43 -07:00
|
|
|
{
|
|
|
|
if (!aURI)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2010-03-28 18:46:55 -07:00
|
|
|
|
|
|
|
FrameProperties props = aFrame->Properties();
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGRenderingObserver *prop =
|
2010-03-28 18:46:55 -07:00
|
|
|
static_cast<nsSVGRenderingObserver*>(props.Get(aProperty));
|
2008-08-07 18:34:43 -07:00
|
|
|
if (prop)
|
|
|
|
return prop;
|
2011-10-17 07:59:28 -07:00
|
|
|
prop = aCreate(aURI, aFrame, false);
|
2008-08-07 18:34:43 -07:00
|
|
|
if (!prop)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2008-08-07 18:34:43 -07:00
|
|
|
NS_ADDREF(prop);
|
2010-03-28 18:46:55 -07:00
|
|
|
props.Set(aProperty, static_cast<nsISupports*>(prop));
|
2008-08-07 18:34:43 -07:00
|
|
|
return prop;
|
|
|
|
}
|
|
|
|
|
2008-10-10 06:14:05 -07:00
|
|
|
nsSVGMarkerProperty *
|
2010-03-28 18:46:55 -07:00
|
|
|
nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProp)
|
2008-10-10 06:14:05 -07:00
|
|
|
{
|
|
|
|
return static_cast<nsSVGMarkerProperty*>(
|
|
|
|
GetEffectProperty(aURI, aFrame, aProp, CreateMarkerProperty));
|
|
|
|
}
|
|
|
|
|
2008-10-11 04:29:35 -07:00
|
|
|
nsSVGTextPathProperty *
|
2010-03-28 18:46:55 -07:00
|
|
|
nsSVGEffects::GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProp)
|
2008-10-11 04:29:35 -07:00
|
|
|
{
|
|
|
|
return static_cast<nsSVGTextPathProperty*>(
|
|
|
|
GetEffectProperty(aURI, aFrame, aProp, CreateTextPathProperty));
|
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGPaintingProperty *
|
2010-03-28 18:46:55 -07:00
|
|
|
nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProp)
|
2008-09-30 17:51:05 -07:00
|
|
|
{
|
|
|
|
return static_cast<nsSVGPaintingProperty*>(
|
|
|
|
GetEffectProperty(aURI, aFrame, aProp, CreatePaintingProperty));
|
|
|
|
}
|
|
|
|
|
2010-08-13 06:30:45 -07:00
|
|
|
static nsSVGRenderingObserver *
|
|
|
|
GetEffectPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProperty,
|
2011-09-28 23:19:26 -07:00
|
|
|
nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *, bool))
|
2010-08-13 06:30:45 -07:00
|
|
|
{
|
2010-09-14 12:50:41 -07:00
|
|
|
if (!aURI)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2010-09-14 12:50:41 -07:00
|
|
|
|
2010-08-13 06:30:45 -07:00
|
|
|
FrameProperties props = aFrame->Properties();
|
|
|
|
nsSVGEffects::URIObserverHashtable *hashtable =
|
|
|
|
static_cast<nsSVGEffects::URIObserverHashtable*>(props.Get(aProperty));
|
|
|
|
if (!hashtable) {
|
|
|
|
hashtable = new nsSVGEffects::URIObserverHashtable();
|
|
|
|
hashtable->Init();
|
|
|
|
props.Set(aProperty, hashtable);
|
|
|
|
}
|
|
|
|
nsSVGRenderingObserver* prop =
|
|
|
|
static_cast<nsSVGRenderingObserver*>(hashtable->GetWeak(aURI));
|
|
|
|
if (!prop) {
|
2011-09-28 23:19:26 -07:00
|
|
|
bool watchImage = aProperty == nsSVGEffects::BackgroundImageProperty();
|
2010-08-13 06:36:05 -07:00
|
|
|
prop = aCreate(aURI, aFrame, watchImage);
|
2010-08-13 06:30:45 -07:00
|
|
|
hashtable->Put(aURI, prop);
|
|
|
|
}
|
|
|
|
return prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGPaintingProperty *
|
|
|
|
nsSVGEffects::GetPaintingPropertyForURI(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProp)
|
|
|
|
{
|
|
|
|
return static_cast<nsSVGPaintingProperty*>(
|
|
|
|
GetEffectPropertyForURI(aURI, aFrame, aProp, CreatePaintingProperty));
|
|
|
|
}
|
|
|
|
|
2008-08-07 18:34:43 -07:00
|
|
|
nsSVGEffects::EffectProperties
|
|
|
|
nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
|
|
|
|
|
|
|
|
EffectProperties result;
|
|
|
|
const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
|
|
|
|
result.mFilter = static_cast<nsSVGFilterProperty*>
|
2010-03-28 18:46:55 -07:00
|
|
|
(GetEffectProperty(style->mFilter, aFrame, FilterProperty(),
|
|
|
|
CreateFilterProperty));
|
|
|
|
result.mClipPath =
|
|
|
|
GetPaintingProperty(style->mClipPath, aFrame, ClipPathProperty());
|
|
|
|
result.mMask =
|
|
|
|
GetPaintingProperty(style->mMask, aFrame, MaskProperty());
|
2008-08-07 18:34:43 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGClipPathFrame *
|
2011-09-28 23:19:26 -07:00
|
|
|
nsSVGEffects::EffectProperties::GetClipPathFrame(bool *aOK)
|
2008-10-10 06:14:05 -07:00
|
|
|
{
|
2008-09-30 17:51:05 -07:00
|
|
|
if (!mClipPath)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2010-03-02 01:31:07 -08:00
|
|
|
nsSVGClipPathFrame *frame = static_cast<nsSVGClipPathFrame *>
|
2008-09-30 17:51:05 -07:00
|
|
|
(mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
|
2010-03-02 01:31:07 -08:00
|
|
|
if (frame && aOK && *aOK) {
|
|
|
|
*aOK = frame->IsValid();
|
|
|
|
}
|
|
|
|
return frame;
|
2008-09-30 17:51:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGMaskFrame *
|
2011-09-28 23:19:26 -07:00
|
|
|
nsSVGEffects::EffectProperties::GetMaskFrame(bool *aOK)
|
2008-10-10 06:14:05 -07:00
|
|
|
{
|
2008-09-30 17:51:05 -07:00
|
|
|
if (!mMask)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2008-09-30 17:51:05 -07:00
|
|
|
return static_cast<nsSVGMaskFrame *>
|
|
|
|
(mMask->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
|
|
|
|
}
|
|
|
|
|
2008-08-07 18:34:43 -07:00
|
|
|
void
|
|
|
|
nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
|
|
|
|
{
|
2010-04-30 06:12:06 -07:00
|
|
|
NS_ASSERTION(aFrame->GetContent()->IsElement(),
|
2010-01-13 03:09:58 -08:00
|
|
|
"aFrame's content should be an element");
|
|
|
|
|
2010-03-28 18:46:55 -07:00
|
|
|
FrameProperties props = aFrame->Properties();
|
|
|
|
props.Delete(FilterProperty());
|
|
|
|
props.Delete(MaskProperty());
|
|
|
|
props.Delete(ClipPathProperty());
|
|
|
|
props.Delete(MarkerBeginProperty());
|
|
|
|
props.Delete(MarkerMiddleProperty());
|
|
|
|
props.Delete(MarkerEndProperty());
|
|
|
|
props.Delete(FillProperty());
|
|
|
|
props.Delete(StrokeProperty());
|
2010-08-13 06:30:45 -07:00
|
|
|
props.Delete(BackgroundImageProperty());
|
2008-10-22 02:09:03 -07:00
|
|
|
|
2008-10-27 04:48:20 -07:00
|
|
|
// Ensure that the filter is repainted correctly
|
2008-10-22 02:09:03 -07:00
|
|
|
// We can't do that in DoUpdate as the referenced frame may not be valid
|
2009-01-21 17:02:40 -08:00
|
|
|
GetEffectProperty(aFrame->GetStyleSVGReset()->mFilter,
|
2010-03-28 18:46:55 -07:00
|
|
|
aFrame, FilterProperty(), CreateFilterProperty);
|
2009-01-21 17:02:40 -08:00
|
|
|
|
2009-01-29 23:13:36 -08:00
|
|
|
if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
|
|
|
// Set marker properties here to avoid reference loops
|
|
|
|
const nsStyleSVG *style = aFrame->GetStyleSVG();
|
2010-03-28 18:46:55 -07:00
|
|
|
GetEffectProperty(style->mMarkerStart, aFrame, MarkerBeginProperty(),
|
2009-01-29 23:13:36 -08:00
|
|
|
CreateMarkerProperty);
|
2010-03-28 18:46:55 -07:00
|
|
|
GetEffectProperty(style->mMarkerMid, aFrame, MarkerMiddleProperty(),
|
2009-01-29 23:13:36 -08:00
|
|
|
CreateMarkerProperty);
|
2010-03-28 18:46:55 -07:00
|
|
|
GetEffectProperty(style->mMarkerEnd, aFrame, MarkerEndProperty(),
|
2009-01-29 23:13:36 -08:00
|
|
|
CreateMarkerProperty);
|
|
|
|
}
|
2008-08-07 18:34:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGFilterProperty *
|
|
|
|
nsSVGEffects::GetFilterProperty(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
|
|
|
|
|
|
|
|
if (!aFrame->GetStyleSVGReset()->mFilter)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2008-08-07 18:34:43 -07:00
|
|
|
|
2010-03-28 18:46:55 -07:00
|
|
|
return static_cast<nsSVGFilterProperty *>
|
|
|
|
(aFrame->Properties().Get(FilterProperty()));
|
2008-08-07 18:34:43 -07:00
|
|
|
}
|
2008-09-30 17:51:05 -07:00
|
|
|
|
2008-10-20 23:50:05 -07:00
|
|
|
static PLDHashOperator
|
2012-03-21 11:07:31 -07:00
|
|
|
GatherEnumerator(nsPtrHashKey<nsSVGRenderingObserver>* aEntry, void* aArg)
|
2008-09-30 17:51:05 -07:00
|
|
|
{
|
|
|
|
nsTArray<nsSVGRenderingObserver*>* array =
|
|
|
|
static_cast<nsTArray<nsSVGRenderingObserver*>*>(aArg);
|
2012-03-21 11:07:31 -07:00
|
|
|
array->AppendElement(aEntry->GetKey());
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
return PL_DHASH_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGRenderingObserverList::InvalidateAll()
|
|
|
|
{
|
|
|
|
if (mObservers.Count() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsAutoTArray<nsSVGRenderingObserver*,10> observers;
|
2010-01-23 10:47:53 -08:00
|
|
|
|
|
|
|
// The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here:
|
2008-09-30 17:51:05 -07:00
|
|
|
mObservers.EnumerateEntries(GatherEnumerator, &observers);
|
2010-01-23 10:47:53 -08:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
for (PRUint32 i = 0; i < observers.Length(); ++i) {
|
2010-08-13 06:31:31 -07:00
|
|
|
observers[i]->InvalidateViaReferencedElement();
|
2008-09-30 17:51:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-16 10:35:59 -08:00
|
|
|
void
|
|
|
|
nsSVGRenderingObserverList::RemoveAll()
|
|
|
|
{
|
|
|
|
nsAutoTArray<nsSVGRenderingObserver*,10> observers;
|
|
|
|
|
|
|
|
// The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here:
|
|
|
|
mObservers.EnumerateEntries(GatherEnumerator, &observers);
|
|
|
|
|
|
|
|
// Our list is now cleared. We need to notify the observers we've removed,
|
|
|
|
// so they can update their state & remove themselves as mutation-observers.
|
|
|
|
for (PRUint32 i = 0; i < observers.Length(); ++i) {
|
|
|
|
observers[i]->NotifyEvictedFromRenderingObserverList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-28 18:46:55 -07:00
|
|
|
static void
|
2010-08-13 06:31:31 -07:00
|
|
|
DestroyObservers(void *aObject, nsIAtom *aPropertyName,
|
|
|
|
void *aPropertyValue, void *aData)
|
2010-03-28 18:46:55 -07:00
|
|
|
{
|
|
|
|
delete static_cast<nsSVGRenderingObserverList*>(aPropertyValue);
|
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
void
|
2010-08-13 06:31:31 -07:00
|
|
|
nsSVGEffects::AddRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver)
|
2008-09-30 17:51:05 -07:00
|
|
|
{
|
2010-08-13 06:31:31 -07:00
|
|
|
nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
|
2008-09-30 17:51:05 -07:00
|
|
|
if (!observerList) {
|
|
|
|
observerList = new nsSVGRenderingObserverList();
|
|
|
|
if (!observerList)
|
|
|
|
return;
|
2010-08-13 06:31:31 -07:00
|
|
|
aElement->SetProperty(nsGkAtoms::renderingobserverlist, observerList, DestroyObservers);
|
2008-09-30 17:51:05 -07:00
|
|
|
}
|
2010-08-13 06:31:31 -07:00
|
|
|
aElement->SetHasRenderingObservers(true);
|
2008-09-30 17:51:05 -07:00
|
|
|
observerList->Add(aObserver);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-08-13 06:31:31 -07:00
|
|
|
nsSVGEffects::RemoveRenderingObserver(Element *aElement, nsSVGRenderingObserver *aObserver)
|
2008-09-30 17:51:05 -07:00
|
|
|
{
|
2010-08-13 06:31:31 -07:00
|
|
|
nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
|
2008-09-30 17:51:05 -07:00
|
|
|
if (observerList) {
|
2010-08-13 06:31:31 -07:00
|
|
|
NS_ASSERTION(observerList->Contains(aObserver),
|
|
|
|
"removing observer from an element we're not observing?");
|
2008-09-30 17:51:05 -07:00
|
|
|
observerList->Remove(aObserver);
|
2010-08-13 06:31:31 -07:00
|
|
|
if (observerList->IsEmpty()) {
|
|
|
|
aElement->SetHasRenderingObservers(false);
|
|
|
|
}
|
2008-09-30 17:51:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-16 10:35:59 -08:00
|
|
|
void
|
|
|
|
nsSVGEffects::RemoveAllRenderingObservers(Element *aElement)
|
|
|
|
{
|
|
|
|
nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
|
|
|
|
if (observerList) {
|
|
|
|
observerList->RemoveAll();
|
|
|
|
aElement->SetHasRenderingObservers(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
void
|
|
|
|
nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
|
|
|
|
|
2010-08-13 06:31:31 -07:00
|
|
|
if (!aFrame->GetContent()->IsElement())
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsSVGRenderingObserverList *observerList =
|
|
|
|
GetObserverList(aFrame->GetContent()->AsElement());
|
2008-09-30 17:51:05 -07:00
|
|
|
if (observerList) {
|
|
|
|
observerList->InvalidateAll();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check ancestor SVG containers. The root frame cannot be of type
|
|
|
|
// eSVGContainer so we don't have to check f for null here.
|
|
|
|
for (nsIFrame *f = aFrame->GetParent();
|
|
|
|
f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) {
|
2010-08-13 06:31:31 -07:00
|
|
|
if (f->GetContent()->IsElement()) {
|
|
|
|
observerList = GetObserverList(f->GetContent()->AsElement());
|
|
|
|
if (observerList) {
|
|
|
|
observerList->InvalidateAll();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGEffects::InvalidateDirectRenderingObservers(Element *aElement)
|
|
|
|
{
|
|
|
|
if (aElement->HasRenderingObservers()) {
|
|
|
|
nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
|
2008-09-30 17:51:05 -07:00
|
|
|
if (observerList) {
|
|
|
|
observerList->InvalidateAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame)
|
|
|
|
{
|
2010-08-13 06:31:31 -07:00
|
|
|
if (aFrame->GetContent() && aFrame->GetContent()->IsElement()) {
|
|
|
|
InvalidateDirectRenderingObservers(aFrame->GetContent()->AsElement());
|
2008-09-30 17:51:05 -07:00
|
|
|
}
|
|
|
|
}
|