2008-08-08 01:34:43 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is the Mozilla SVG project.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is IBM Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2005
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* rocallahan@mozilla.com
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsSVGEffects.h"
|
|
|
|
#include "nsISupportsImpl.h"
|
|
|
|
#include "nsSVGOuterSVGFrame.h"
|
2008-10-01 00:51:05 +00:00
|
|
|
#include "nsSVGFilterFrame.h"
|
|
|
|
#include "nsSVGClipPathFrame.h"
|
|
|
|
#include "nsSVGMaskFrame.h"
|
2008-10-11 11:29:35 +00:00
|
|
|
#include "nsSVGTextPathFrame.h"
|
2008-10-22 09:09:03 +00:00
|
|
|
#include "nsCSSFrameConstructor.h"
|
2008-12-12 08:25:16 +00:00
|
|
|
#include "nsFrameManager.h"
|
2008-10-01 00:51:05 +00:00
|
|
|
|
2010-03-29 01:46:55 +00:00
|
|
|
using namespace mozilla;
|
|
|
|
|
2010-01-23 18:47:53 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
* tree changes to the element or any of its *descendants*.
|
|
|
|
*
|
|
|
|
* In nsSVGRenderingObserver::GetReferencedFrame() the nsSVGRenderingObserver
|
|
|
|
* object also adds itself to an nsSVGRenderingObserverList object belonging
|
|
|
|
* to the nsIFrame corresponding 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.
|
|
|
|
*/
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
NS_IMPL_ISUPPORTS1(nsSVGRenderingObserver, nsIMutationObserver)
|
|
|
|
|
2010-01-13 08:18:48 +00: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
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver::nsSVGRenderingObserver(nsIURI *aURI,
|
|
|
|
nsIFrame *aFrame)
|
|
|
|
: mElement(this), mFrame(aFrame),
|
|
|
|
mFramePresShell(aFrame->PresContext()->PresShell()),
|
|
|
|
mReferencedFrame(nsnull),
|
|
|
|
mReferencedFramePresShell(nsnull)
|
2010-01-13 08:18:48 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif
|
2008-08-08 01:34:43 +00:00
|
|
|
{
|
|
|
|
// Start watching the target element
|
|
|
|
mElement.Reset(aFrame->GetContent(), aURI);
|
|
|
|
if (mElement.get()) {
|
|
|
|
mElement.get()->AddMutationObserver(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver::~nsSVGRenderingObserver()
|
2008-08-08 01:34:43 +00:00
|
|
|
{
|
|
|
|
if (mElement.get()) {
|
|
|
|
mElement.get()->RemoveMutationObserver(this);
|
|
|
|
}
|
2009-03-30 02:54:33 +00:00
|
|
|
if (mReferencedFrame && !mReferencedFramePresShell->IsDestroying()) {
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGEffects::RemoveRenderingObserver(mReferencedFrame, this);
|
|
|
|
}
|
2008-08-08 01:34:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame*
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver::GetReferencedFrame()
|
2008-08-08 01:34:43 +00:00
|
|
|
{
|
2009-03-30 02:54:33 +00:00
|
|
|
if (mReferencedFrame && !mReferencedFramePresShell->IsDestroying()) {
|
2009-04-01 01:08:34 +00:00
|
|
|
// Don't test this assertion if it's not a good time to call
|
|
|
|
// GetPrimaryFrame
|
|
|
|
if (!mReferencedFramePresShell->FrameManager()->IsDestroyingFrames()) {
|
|
|
|
NS_ASSERTION(mElement.get() &&
|
|
|
|
static_cast<nsGenericElement*>(mElement.get())->GetPrimaryFrame() == mReferencedFrame,
|
|
|
|
"Cached frame is incorrect!");
|
|
|
|
}
|
2008-10-01 00:51:05 +00:00
|
|
|
return mReferencedFrame;
|
|
|
|
}
|
|
|
|
|
2008-08-08 01:34:43 +00:00
|
|
|
if (mElement.get()) {
|
2008-12-12 08:25:16 +00:00
|
|
|
nsIDocument* doc = mElement.get()->GetCurrentDoc();
|
2010-06-25 13:59:57 +00:00
|
|
|
nsIPresShell* shell = doc ? doc->GetShell() : nsnull;
|
2008-12-12 08:25:16 +00:00
|
|
|
if (shell && !shell->FrameManager()->IsDestroyingFrames()) {
|
2009-12-24 21:20:06 +00:00
|
|
|
nsIFrame* frame = mElement.get()->GetPrimaryFrame();
|
2008-12-12 08:25:16 +00:00
|
|
|
if (frame) {
|
|
|
|
mReferencedFrame = frame;
|
|
|
|
mReferencedFramePresShell = shell;
|
|
|
|
nsSVGEffects::AddRenderingObserver(mReferencedFrame, this);
|
|
|
|
return frame;
|
|
|
|
}
|
2008-10-01 00:51:05 +00:00
|
|
|
}
|
2008-08-08 01:34:43 +00:00
|
|
|
}
|
2008-10-01 00:51:05 +00:00
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame*
|
|
|
|
nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, PRBool* aOK)
|
|
|
|
{
|
|
|
|
nsIFrame* frame = GetReferencedFrame();
|
|
|
|
if (frame && frame->GetType() == aFrameType)
|
|
|
|
return frame;
|
2008-08-08 01:34:43 +00:00
|
|
|
if (aOK) {
|
|
|
|
*aOK = PR_FALSE;
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver::DoUpdate()
|
|
|
|
{
|
2009-03-30 02:54:33 +00:00
|
|
|
if (mFramePresShell->IsDestroying()) {
|
2008-10-01 00:51:05 +00:00
|
|
|
// mFrame is no longer valid. Bail out.
|
|
|
|
mFrame = nsnull;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (mReferencedFrame) {
|
|
|
|
nsSVGEffects::RemoveRenderingObserver(mReferencedFrame, this);
|
|
|
|
mReferencedFrame = nsnull;
|
|
|
|
mReferencedFramePresShell = nsnull;
|
|
|
|
}
|
|
|
|
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
|
|
|
|
nsSVGRenderingObserver::InvalidateViaReferencedFrame()
|
|
|
|
{
|
|
|
|
// Clear mReferencedFrame since the referenced frame has already
|
|
|
|
// dropped its reference back to us
|
|
|
|
mReferencedFrame = nsnull;
|
|
|
|
mReferencedFramePresShell = nsnull;
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGRenderingObserver::AttributeChanged(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContent,
|
|
|
|
PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom *aAttribute,
|
2009-12-10 22:36:04 +00:00
|
|
|
PRInt32 aModType)
|
2008-08-08 01:34:43 +00:00
|
|
|
{
|
2010-01-23 18:47:53 +00: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-08 01:34:43 +00:00
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver::ContentAppended(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContainer,
|
2010-05-11 01:12:34 +00:00
|
|
|
nsIContent *aFirstNewContent,
|
|
|
|
PRInt32 /* unused */)
|
2008-08-08 01:34:43 +00:00
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver::ContentInserted(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContainer,
|
|
|
|
nsIContent *aChild,
|
2010-05-11 01:12:34 +00:00
|
|
|
PRInt32 /* unused */)
|
2008-08-08 01:34:43 +00:00
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver::ContentRemoved(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContainer,
|
|
|
|
nsIContent *aChild,
|
|
|
|
PRInt32 aIndexInContainer)
|
2008-08-08 01:34:43 +00:00
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED1(nsSVGFilterProperty,
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver,
|
2008-08-08 01:34:43 +00:00
|
|
|
nsISVGFilterProperty)
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGFilterFrame *
|
2008-10-10 13:14:05 +00:00
|
|
|
nsSVGFilterProperty::GetFilterFrame()
|
|
|
|
{
|
2008-10-01 00:51:05 +00:00
|
|
|
return static_cast<nsSVGFilterFrame *>
|
|
|
|
(GetReferencedFrame(nsGkAtoms::svgFilterFrame, nsnull));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
InvalidateAllContinuations(nsIFrame* aFrame)
|
2008-08-08 01:34:43 +00:00
|
|
|
{
|
2008-10-01 00:51:05 +00:00
|
|
|
for (nsIFrame* f = aFrame; f; f = f->GetNextContinuation()) {
|
|
|
|
f->InvalidateOverflowRect();
|
2008-08-08 01:34:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGFilterProperty::DoUpdate()
|
2008-09-30 11:28:20 +00:00
|
|
|
{
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver::DoUpdate();
|
|
|
|
if (!mFrame)
|
2008-08-08 01:34:43 +00:00
|
|
|
return;
|
|
|
|
|
2008-10-27 11:48:20 +00:00
|
|
|
// Repaint asynchronously in case the filter frame is being torn down
|
|
|
|
nsChangeHint changeHint =
|
|
|
|
nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects);
|
|
|
|
|
|
|
|
if (!mFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
|
|
|
NS_UpdateHint(changeHint, nsChangeHint_ReflowFrame);
|
2008-09-30 11:28:20 +00:00
|
|
|
}
|
2008-10-27 11:48:20 +00:00
|
|
|
mFramePresShell->FrameConstructor()->PostRestyleEvent(
|
2010-05-14 17:04:51 +00:00
|
|
|
mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
|
2008-09-30 11:28:20 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 13:14:05 +00:00
|
|
|
void
|
|
|
|
nsSVGMarkerProperty::DoUpdate()
|
|
|
|
{
|
|
|
|
nsSVGRenderingObserver::DoUpdate();
|
|
|
|
if (!mFrame)
|
|
|
|
return;
|
|
|
|
|
2009-01-22 01:02:40 +00:00
|
|
|
NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
|
|
|
|
|
|
|
|
// Repaint asynchronously
|
|
|
|
nsChangeHint changeHint =
|
|
|
|
nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects);
|
|
|
|
|
|
|
|
mFramePresShell->FrameConstructor()->PostRestyleEvent(
|
2010-05-14 17:04:51 +00:00
|
|
|
mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
|
2008-10-10 13:14:05 +00:00
|
|
|
}
|
|
|
|
|
2008-10-11 11:29:35 +00:00
|
|
|
void
|
|
|
|
nsSVGTextPathProperty::DoUpdate()
|
|
|
|
{
|
|
|
|
nsSVGRenderingObserver::DoUpdate();
|
|
|
|
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 11:28:20 +00:00
|
|
|
void
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGPaintingProperty::DoUpdate()
|
2008-09-30 11:28:20 +00:00
|
|
|
{
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver::DoUpdate();
|
|
|
|
if (!mFrame)
|
2008-09-30 11:28:20 +00:00
|
|
|
return;
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
if (mFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
2008-12-04 18:17:45 +00:00
|
|
|
nsSVGUtils::InvalidateCoveredRegion(mFrame);
|
2008-10-01 00:51:05 +00:00
|
|
|
} else {
|
|
|
|
InvalidateAllContinuations(mFrame);
|
2008-09-30 11:28:20 +00:00
|
|
|
}
|
2008-08-08 01:34:43 +00:00
|
|
|
}
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
static nsSVGRenderingObserver *
|
2008-08-08 01:34:43 +00:00
|
|
|
CreateFilterProperty(nsIURI *aURI, nsIFrame *aFrame)
|
|
|
|
{ return new nsSVGFilterProperty(aURI, aFrame); }
|
|
|
|
|
2008-10-10 13:14:05 +00:00
|
|
|
static nsSVGRenderingObserver *
|
|
|
|
CreateMarkerProperty(nsIURI *aURI, nsIFrame *aFrame)
|
|
|
|
{ return new nsSVGMarkerProperty(aURI, aFrame); }
|
|
|
|
|
2008-10-11 11:29:35 +00:00
|
|
|
static nsSVGRenderingObserver *
|
|
|
|
CreateTextPathProperty(nsIURI *aURI, nsIFrame *aFrame)
|
|
|
|
{ return new nsSVGTextPathProperty(aURI, aFrame); }
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
static nsSVGRenderingObserver *
|
|
|
|
CreatePaintingProperty(nsIURI *aURI, nsIFrame *aFrame)
|
|
|
|
{ return new nsSVGPaintingProperty(aURI, aFrame); }
|
2008-08-08 01:34:43 +00:00
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
static nsSVGRenderingObserver *
|
2010-03-29 01:46:55 +00:00
|
|
|
GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProperty,
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *))
|
2008-08-08 01:34:43 +00:00
|
|
|
{
|
|
|
|
if (!aURI)
|
|
|
|
return nsnull;
|
2010-03-29 01:46:55 +00:00
|
|
|
|
|
|
|
FrameProperties props = aFrame->Properties();
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGRenderingObserver *prop =
|
2010-03-29 01:46:55 +00:00
|
|
|
static_cast<nsSVGRenderingObserver*>(props.Get(aProperty));
|
2008-08-08 01:34:43 +00:00
|
|
|
if (prop)
|
|
|
|
return prop;
|
|
|
|
prop = aCreate(aURI, aFrame);
|
|
|
|
if (!prop)
|
|
|
|
return nsnull;
|
|
|
|
NS_ADDREF(prop);
|
2010-03-29 01:46:55 +00:00
|
|
|
props.Set(aProperty, static_cast<nsISupports*>(prop));
|
2008-08-08 01:34:43 +00:00
|
|
|
return prop;
|
|
|
|
}
|
|
|
|
|
2008-10-10 13:14:05 +00:00
|
|
|
nsSVGMarkerProperty *
|
2010-03-29 01:46:55 +00:00
|
|
|
nsSVGEffects::GetMarkerProperty(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProp)
|
2008-10-10 13:14:05 +00:00
|
|
|
{
|
|
|
|
return static_cast<nsSVGMarkerProperty*>(
|
|
|
|
GetEffectProperty(aURI, aFrame, aProp, CreateMarkerProperty));
|
|
|
|
}
|
|
|
|
|
2008-10-11 11:29:35 +00:00
|
|
|
nsSVGTextPathProperty *
|
2010-03-29 01:46:55 +00:00
|
|
|
nsSVGEffects::GetTextPathProperty(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProp)
|
2008-10-11 11:29:35 +00:00
|
|
|
{
|
|
|
|
return static_cast<nsSVGTextPathProperty*>(
|
|
|
|
GetEffectProperty(aURI, aFrame, aProp, CreateTextPathProperty));
|
|
|
|
}
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGPaintingProperty *
|
2010-03-29 01:46:55 +00:00
|
|
|
nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame,
|
|
|
|
const FramePropertyDescriptor *aProp)
|
2008-10-01 00:51:05 +00:00
|
|
|
{
|
|
|
|
return static_cast<nsSVGPaintingProperty*>(
|
|
|
|
GetEffectProperty(aURI, aFrame, aProp, CreatePaintingProperty));
|
|
|
|
}
|
|
|
|
|
2008-08-08 01:34:43 +00: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-29 01:46:55 +00:00
|
|
|
(GetEffectProperty(style->mFilter, aFrame, FilterProperty(),
|
|
|
|
CreateFilterProperty));
|
|
|
|
result.mClipPath =
|
|
|
|
GetPaintingProperty(style->mClipPath, aFrame, ClipPathProperty());
|
|
|
|
result.mMask =
|
|
|
|
GetPaintingProperty(style->mMask, aFrame, MaskProperty());
|
2008-08-08 01:34:43 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
nsSVGClipPathFrame *
|
2008-10-10 13:14:05 +00:00
|
|
|
nsSVGEffects::EffectProperties::GetClipPathFrame(PRBool *aOK)
|
|
|
|
{
|
2008-10-01 00:51:05 +00:00
|
|
|
if (!mClipPath)
|
|
|
|
return nsnull;
|
2010-03-02 09:31:07 +00:00
|
|
|
nsSVGClipPathFrame *frame = static_cast<nsSVGClipPathFrame *>
|
2008-10-01 00:51:05 +00:00
|
|
|
(mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
|
2010-03-02 09:31:07 +00:00
|
|
|
if (frame && aOK && *aOK) {
|
|
|
|
*aOK = frame->IsValid();
|
|
|
|
}
|
|
|
|
return frame;
|
2008-10-01 00:51:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGMaskFrame *
|
2008-10-10 13:14:05 +00:00
|
|
|
nsSVGEffects::EffectProperties::GetMaskFrame(PRBool *aOK)
|
|
|
|
{
|
2008-10-01 00:51:05 +00:00
|
|
|
if (!mMask)
|
|
|
|
return nsnull;
|
|
|
|
return static_cast<nsSVGMaskFrame *>
|
|
|
|
(mMask->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
|
|
|
|
}
|
|
|
|
|
2008-08-08 01:34:43 +00:00
|
|
|
void
|
|
|
|
nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
|
|
|
|
{
|
2010-04-30 13:12:06 +00:00
|
|
|
NS_ASSERTION(aFrame->GetContent()->IsElement(),
|
2010-01-13 11:09:58 +00:00
|
|
|
"aFrame's content should be an element");
|
|
|
|
|
2010-03-29 01:46:55 +00: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());
|
2008-10-22 09:09:03 +00:00
|
|
|
|
2008-10-27 11:48:20 +00:00
|
|
|
// Ensure that the filter is repainted correctly
|
2008-10-22 09:09:03 +00:00
|
|
|
// We can't do that in DoUpdate as the referenced frame may not be valid
|
2009-01-22 01:02:40 +00:00
|
|
|
GetEffectProperty(aFrame->GetStyleSVGReset()->mFilter,
|
2010-03-29 01:46:55 +00:00
|
|
|
aFrame, FilterProperty(), CreateFilterProperty);
|
2009-01-22 01:02:40 +00:00
|
|
|
|
2009-01-30 07:13:36 +00:00
|
|
|
if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
|
|
|
// Set marker properties here to avoid reference loops
|
|
|
|
const nsStyleSVG *style = aFrame->GetStyleSVG();
|
2010-03-29 01:46:55 +00:00
|
|
|
GetEffectProperty(style->mMarkerStart, aFrame, MarkerBeginProperty(),
|
2009-01-30 07:13:36 +00:00
|
|
|
CreateMarkerProperty);
|
2010-03-29 01:46:55 +00:00
|
|
|
GetEffectProperty(style->mMarkerMid, aFrame, MarkerMiddleProperty(),
|
2009-01-30 07:13:36 +00:00
|
|
|
CreateMarkerProperty);
|
2010-03-29 01:46:55 +00:00
|
|
|
GetEffectProperty(style->mMarkerEnd, aFrame, MarkerEndProperty(),
|
2009-01-30 07:13:36 +00:00
|
|
|
CreateMarkerProperty);
|
|
|
|
}
|
2010-01-07 19:07:30 +00:00
|
|
|
|
2010-01-13 11:09:58 +00:00
|
|
|
nsIFrame *kid = aFrame->GetFirstChild(nsnull);
|
|
|
|
while (kid) {
|
2010-04-30 13:12:06 +00:00
|
|
|
if (kid->GetContent()->IsElement()) {
|
2010-01-13 11:09:58 +00:00
|
|
|
UpdateEffects(kid);
|
|
|
|
}
|
|
|
|
kid = kid->GetNextSibling();
|
2010-01-07 19:07:30 +00:00
|
|
|
}
|
2008-08-08 01:34:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGFilterProperty *
|
|
|
|
nsSVGEffects::GetFilterProperty(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
|
|
|
|
|
|
|
|
if (!aFrame->GetStyleSVGReset()->mFilter)
|
|
|
|
return nsnull;
|
|
|
|
|
2010-03-29 01:46:55 +00:00
|
|
|
return static_cast<nsSVGFilterProperty *>
|
|
|
|
(aFrame->Properties().Get(FilterProperty()));
|
2008-08-08 01:34:43 +00:00
|
|
|
}
|
2008-10-01 00:51:05 +00:00
|
|
|
|
2008-10-21 06:50:05 +00:00
|
|
|
static PLDHashOperator
|
2008-10-01 00:51:05 +00:00
|
|
|
GatherEnumerator(nsVoidPtrHashKey* aEntry, void* aArg)
|
|
|
|
{
|
|
|
|
nsTArray<nsSVGRenderingObserver*>* array =
|
|
|
|
static_cast<nsTArray<nsSVGRenderingObserver*>*>(aArg);
|
|
|
|
array->AppendElement(static_cast<nsSVGRenderingObserver*>(
|
|
|
|
const_cast<void*>(aEntry->GetKey())));
|
|
|
|
return PL_DHASH_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGRenderingObserverList::InvalidateAll()
|
|
|
|
{
|
|
|
|
if (mObservers.Count() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsAutoTArray<nsSVGRenderingObserver*,10> observers;
|
2010-01-23 18:47:53 +00:00
|
|
|
|
|
|
|
// The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here:
|
2008-10-01 00:51:05 +00:00
|
|
|
mObservers.EnumerateEntries(GatherEnumerator, &observers);
|
2010-01-23 18:47:53 +00:00
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
for (PRUint32 i = 0; i < observers.Length(); ++i) {
|
|
|
|
observers[i]->InvalidateViaReferencedFrame();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-29 01:46:55 +00:00
|
|
|
static void
|
|
|
|
DestroyObservers(void* aPropertyValue)
|
|
|
|
{
|
|
|
|
delete static_cast<nsSVGRenderingObserverList*>(aPropertyValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_DECLARE_FRAME_PROPERTY(ObserversProperty, DestroyObservers)
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
static nsSVGRenderingObserverList *
|
|
|
|
GetObserverList(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
if (!(aFrame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS))
|
|
|
|
return nsnull;
|
2010-03-29 01:46:55 +00:00
|
|
|
return static_cast<nsSVGRenderingObserverList*>
|
|
|
|
(aFrame->Properties().Get(ObserversProperty()));
|
2009-06-24 08:47:21 +00:00
|
|
|
}
|
|
|
|
|
2008-10-01 00:51:05 +00:00
|
|
|
void
|
|
|
|
nsSVGEffects::AddRenderingObserver(nsIFrame *aFrame, nsSVGRenderingObserver *aObserver)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
|
|
|
|
|
|
|
|
nsSVGRenderingObserverList *observerList = GetObserverList(aFrame);
|
|
|
|
if (!observerList) {
|
|
|
|
observerList = new nsSVGRenderingObserverList();
|
|
|
|
if (!observerList)
|
|
|
|
return;
|
|
|
|
for (nsIFrame* f = aFrame; f; f = f->GetNextContinuation()) {
|
|
|
|
f->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS);
|
|
|
|
}
|
2010-03-29 01:46:55 +00:00
|
|
|
aFrame->Properties().Set(ObserversProperty(), observerList);
|
2008-10-01 00:51:05 +00:00
|
|
|
}
|
|
|
|
observerList->Add(aObserver);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGEffects::RemoveRenderingObserver(nsIFrame *aFrame, nsSVGRenderingObserver *aObserver)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
|
|
|
|
|
|
|
|
nsSVGRenderingObserverList *observerList = GetObserverList(aFrame);
|
|
|
|
if (observerList) {
|
|
|
|
observerList->Remove(aObserver);
|
|
|
|
// Don't remove the property even if the observer list is empty.
|
|
|
|
// This might not be a good time to modify the frame property
|
|
|
|
// hashtables.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
|
|
|
|
|
|
|
|
nsSVGRenderingObserverList *observerList = GetObserverList(aFrame);
|
|
|
|
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()) {
|
|
|
|
observerList = GetObserverList(f);
|
|
|
|
if (observerList) {
|
|
|
|
observerList->InvalidateAll();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
nsSVGRenderingObserverList *observerList = GetObserverList(aFrame);
|
|
|
|
if (observerList) {
|
|
|
|
observerList->InvalidateAll();
|
|
|
|
}
|
|
|
|
}
|