Bug 455984. Rework gradient and pattern code to use nsReferencedElement and nsSVGRenderingObservers, so they observe changes to the ID-element-map properly and propagate invalidations correctly (and with simpler code too). r=longsonr,sr=mats

This commit is contained in:
Robert O'Callahan 2008-10-01 13:51:05 +13:00
parent 1c324609bd
commit 09cfc5fa8c
30 changed files with 889 additions and 1105 deletions

View File

@ -148,7 +148,7 @@
#include "nsMathMLParts.h"
#endif
#ifdef MOZ_SVG
#include "nsSVGUtils.h"
#include "nsSVGEffects.h"
#endif
nsIFrame*
@ -9826,7 +9826,7 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
NS_ASSERTION(frame, "This shouldn't happen");
#ifdef MOZ_SVG
if (hint & nsChangeHint_UpdateEffects) {
nsSVGUtils::UpdateEffects(frame);
nsSVGEffects::UpdateEffects(frame);
}
#endif
if (hint & nsChangeHint_ReflowFrame) {

View File

@ -102,11 +102,10 @@ class gfxContext;
typedef short SelectionType;
typedef PRUint32 nsFrameState;
// 134e504f-4fd1-4590-9f5d-899afee63d0f
// 5c103bc2-788e-4bbe-b82e-635bea34e78f
#define NS_IPRESSHELL_IID \
{ 0x134e504f, 0x4fd1, 0x4590, \
{ 0x9f, 0x5d, 0x89, 0x9a, 0xfe, 0xe6, 0x3d, 0x0f } }
{ 0x5c103bc2, 0x788e, 0x4bbe, \
{ 0xb8, 0x2e, 0x63, 0x5b, 0xea, 0x34, 0xe7, 0x8f } }
// Constants for ScrollContentIntoView() function
#define NS_PRESSHELL_SCROLL_TOP 0
@ -165,6 +164,8 @@ public:
* times to make form controls behave nicely when printed.
*/
NS_IMETHOD Destroy() = 0;
PRBool IsDestroying() { return mIsDestroying; }
// All frames owned by the shell are allocated from an arena. They are also recycled
// using free lists (separate free lists being maintained for each size_t).

View File

@ -2629,7 +2629,6 @@ nsLayoutUtils::CalculateContentBottom(nsIFrame* aFrame)
childList = aFrame->GetAdditionalChildListName(nextListID);
nextListID++;
} while (childList);
}
return contentBottom;

View File

@ -122,6 +122,7 @@
#ifdef MOZ_SVG
#include "nsSVGIntegrationUtils.h"
#include "nsSVGEffects.h"
#endif
#include "gfxContext.h"
@ -430,7 +431,8 @@ nsFrame::Init(nsIContent* aContent,
// Make bits that are currently off (see constructor) the same:
mState |= state & (NS_FRAME_SELECTED_CONTENT |
NS_FRAME_INDEPENDENT_SELECTION |
NS_FRAME_IS_SPECIAL);
NS_FRAME_IS_SPECIAL |
NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS);
}
if (mParent) {
nsFrameState state = mParent->GetStateBits();
@ -442,7 +444,7 @@ nsFrame::Init(nsIContent* aContent,
if (GetStyleDisplay()->HasTransform()) {
// The frame gets reconstructed if we toggle the -moz-transform
// property, so we can set this bit here and then ignore it.
mState |= NS_FRAME_MAY_BE_TRANSFORMED;
mState |= NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS;
}
DidSetStyleContext();
@ -495,6 +497,10 @@ nsFrame::RemoveFrame(nsIAtom* aListName,
void
nsFrame::Destroy()
{
#ifdef MOZ_SVG
nsSVGEffects::InvalidateDirectRenderingObservers(this);
#endif
// Get the view pointer now before the frame properties disappear
// when we call NotifyDestroyingFrame()
nsIView* view = GetView();
@ -675,7 +681,7 @@ nsIFrame::GetPaddingRect() const
PRBool
nsIFrame::IsTransformed() const
{
return (mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
return (mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) &&
GetStyleDisplay()->HasTransform();
}
@ -1198,7 +1204,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
/* If we're being transformed, we need to invert the matrix transform so that we don't
* grab points in the wrong coordinate system!
*/
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) && disp->HasTransform())
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) &&
disp->HasTransform())
dirtyRect = nsDisplayTransform::UntransformRect(dirtyRect, this, nsPoint(0, 0));
if (applyAbsPosClipping) {
@ -1318,7 +1325,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
/* If we're going to apply a transformation, wrap everything in an
* nsDisplayTransform.
*/
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) && disp->HasTransform()) {
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) &&
disp->HasTransform()) {
nsDisplayTransform* transform = new (aBuilder) nsDisplayTransform(this, &resultList);
if (!transform)
return NS_ERROR_OUT_OF_MEMORY;
@ -1468,7 +1476,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// Child is composited if it's transformed, partially transparent, or has
// SVG effects.
PRBool isComposited = disp->mOpacity != 1.0f ||
((aChild->mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
((aChild->mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) &&
aChild->GetStyleDisplay()->HasTransform())
#ifdef MOZ_SVG
|| nsSVGIntegrationUtils::UsingEffectsForFrame(aChild)
@ -3684,7 +3692,7 @@ nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
*
* See bug #452496 for more details.
*/
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) &&
GetStyleDisplay()->HasTransform()) {
nsRect newDamageRect;
newDamageRect.UnionRect(nsDisplayTransform::TransformRect
@ -3762,7 +3770,7 @@ nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
return gfxMatrix();
/* Keep iterating while the frame can't possibly be transformed. */
while (!((*aOutAncestor)->mState & NS_FRAME_MAY_BE_TRANSFORMED)) {
while (!(*aOutAncestor)->IsTransformed()) {
/* If no parent, stop iterating. Otherwise, update the ancestor. */
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
if (!parent)
@ -3932,7 +3940,7 @@ nsIFrame::GetOverflowRectRelativeToParent() const
nsRect
nsIFrame::GetOverflowRectRelativeToSelf() const
{
if (!(mState & NS_FRAME_MAY_BE_TRANSFORMED) ||
if (!(mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) ||
!GetStyleDisplay()->HasTransform())
return GetOverflowRect();
return *static_cast<nsRect*>
@ -5632,7 +5640,7 @@ nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
*aOverflowArea = GetAdditionalOverflow(*aOverflowArea, aNewSize);
/* If we're transformed, transform the overflow rect by the current transformation. */
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS) &&
GetStyleDisplay()->HasTransform()) {
// Save overflow area before the transform
SetRectProperty(this, nsGkAtoms::preTransformBBoxProperty, *aOverflowArea);

View File

@ -105,10 +105,10 @@ struct nsMargin;
typedef class nsIFrame nsIBox;
// IID for the nsIFrame interface
// 626a1563-1bae-4a6e-8d2c-2dc2c13048dd
// 3459e7bb-2b22-4eb3-b60d-27d9f851b919
#define NS_IFRAME_IID \
{ 0x626a1563, 0x1bae, 0x4a6e, \
{ 0x8d, 0x2c, 0x2d, 0xc2, 0xc1, 0x30, 0x48, 0xdd } }
{ 0x3459e7bb, 0x2b22, 0x4eb3, \
{ 0xb6, 0x0d, 0x27, 0xd9, 0xf8, 0x51, 0xb9, 0x19 } }
/**
* Indication of how the frame can be split. This is used when doing runaround
@ -236,7 +236,9 @@ enum {
// to its coordinate system (e.g. CSS transform, SVG foreignObject).
// This is used primarily in GetTransformMatrix to optimize for the
// common case.
NS_FRAME_MAY_BE_TRANSFORMED = 0x00010000,
// ALSO, if this bit is set, the frame's first-continuation may
// have an associated nsSVGRenderingObserverList.
NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS = 0x00010000,
#ifdef IBMBIDI
// If this bit is set, the frame itself is a bidi continuation,
@ -1582,22 +1584,23 @@ public:
eMathML = 1 << 0,
eSVG = 1 << 1,
eSVGForeignObject = 1 << 2,
eBidiInlineContainer = 1 << 3,
eSVGContainer = 1 << 3,
eBidiInlineContainer = 1 << 4,
// the frame is for a replaced element, such as an image
eReplaced = 1 << 4,
eReplaced = 1 << 5,
// Frame that contains a block but looks like a replaced element
// from the outside
eReplacedContainsBlock = 1 << 5,
eReplacedContainsBlock = 1 << 6,
// A frame that participates in inline reflow, i.e., one that
// requires nsHTMLReflowState::mLineLayout.
eLineParticipant = 1 << 6,
eXULBox = 1 << 7,
eCanContainOverflowContainers = 1 << 8,
eBlockFrame = 1 << 9,
eLineParticipant = 1 << 7,
eXULBox = 1 << 8,
eCanContainOverflowContainers = 1 << 9,
eBlockFrame = 1 << 10,
// If this bit is set, the frame doesn't allow ignorable whitespace as
// children. For example, the whitespace between <table>\n<tr>\n<td>
// will be excluded during the construction of children.
eExcludesIgnorableWhitespace = 1 << 10,
eExcludesIgnorableWhitespace = 1 << 11,
// These are to allow nsFrame::Init to assert that IsFrameOfType
// implementations all call the base class method. They are only

View File

@ -4,7 +4,7 @@
-->
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
class="reftest-wait"
onload="setTimeout(doTest,10)"
onload="setTimeout(doTest,500)"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Testing that dynamic changes to the element for a given ID are reflected in clip-path</title>
<defs>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -19,7 +19,14 @@ include moz-only/reftest.list
== dynamic-conditions-01.svg pass.svg
== dynamic-clipPath-01.svg pass.svg
== dynamic-feFlood-01.svg pass.svg
== dynamic-filter-contents-01.svg dynamic-filter-contents-01-ref.svg
== dynamic-gradient-contents-01.svg pass.svg
== dynamic-link-style-01.svg pass.svg
== dynamic-mask-contents-01.svg pass.svg
== dynamic-pattern-01.svg pass.svg
== dynamic-pattern-02.svg pass.svg
== dynamic-pattern-contents-01.svg pass.svg
== dynamic-pattern-contents-02.svg pass.svg
== dynamic-rect-01.svg dynamic-rect-01-ref.svg
== dynamic-rect-02.svg dynamic-rect-02-ref.svg
== dynamic-rect-03.svg dynamic-rect-03-ref.svg

View File

@ -450,6 +450,7 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther)
#ifdef MOZ_SVG
maxHint = nsChangeHint(NS_STYLE_HINT_REFLOW | nsChangeHint_UpdateEffects);
DO_STRUCT_DIFFERENCE(SVGReset);
DO_STRUCT_DIFFERENCE(SVG);
#endif
// At this point, we know that the worst kind of damage we could do is
@ -475,9 +476,6 @@ nsStyleContext::CalcStyleDifference(nsStyleContext* aOther)
// re-render to occur. VISUAL Structs: Color, Background
DO_STRUCT_DIFFERENCE(Color);
DO_STRUCT_DIFFERENCE(Background);
#ifdef MOZ_SVG
DO_STRUCT_DIFFERENCE(SVG);
#endif
#undef DO_STRUCT_DIFFERENCE

View File

@ -803,12 +803,39 @@ nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
mTextRendering = aSource.mTextRendering;
}
static PRBool PaintURIChanged(const nsStyleSVGPaint& aPaint1,
const nsStyleSVGPaint& aPaint2)
{
if (aPaint1.mType != aPaint2.mType) {
return aPaint1.mType == eStyleSVGPaintType_Server ||
aPaint2.mType == eStyleSVGPaintType_Server;
}
return aPaint1.mType == eStyleSVGPaintType_Server &&
!EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer);
}
nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const
{
if ( mFill != aOther.mFill ||
mStroke != aOther.mStroke ||
nsChangeHint hint = nsChangeHint(0);
!EqualURIs(mMarkerEnd, aOther.mMarkerEnd) ||
if (mTextRendering != aOther.mTextRendering) {
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
// May be needed for non-svg frames
NS_UpdateHint(hint, nsChangeHint_ReflowFrame);
}
if (mFill != aOther.mFill ||
mStroke != aOther.mStroke) {
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
if (PaintURIChanged(mFill, aOther.mFill) ||
PaintURIChanged(mStroke, aOther.mStroke)) {
NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
}
// Nothing more to do, below we can only set "repaint"
return hint;
}
if ( !EqualURIs(mMarkerEnd, aOther.mMarkerEnd) ||
!EqualURIs(mMarkerMid, aOther.mMarkerMid) ||
!EqualURIs(mMarkerStart, aOther.mMarkerStart) ||
@ -823,28 +850,32 @@ nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const
mColorInterpolation != aOther.mColorInterpolation ||
mColorInterpolationFilters != aOther.mColorInterpolationFilters ||
mFillRule != aOther.mFillRule ||
mPointerEvents != aOther.mPointerEvents ||
mShapeRendering != aOther.mShapeRendering ||
mStrokeDasharrayLength != aOther.mStrokeDasharrayLength ||
mStrokeLinecap != aOther.mStrokeLinecap ||
mStrokeLinejoin != aOther.mStrokeLinejoin ||
mTextAnchor != aOther.mTextAnchor ||
mTextRendering != aOther.mTextRendering)
return NS_STYLE_HINT_VISUAL;
mTextAnchor != aOther.mTextAnchor) {
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
return hint;
}
// length of stroke dasharrays are the same (tested above) - check entries
for (PRUint32 i=0; i<mStrokeDasharrayLength; i++)
if (mStrokeDasharray[i] != aOther.mStrokeDasharray[i])
return NS_STYLE_HINT_VISUAL;
if (mStrokeDasharray[i] != aOther.mStrokeDasharray[i]) {
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
return hint;
}
return NS_STYLE_HINT_NONE;
return hint;
}
#ifdef DEBUG
/* static */
nsChangeHint nsStyleSVG::MaxDifference()
{
return NS_STYLE_HINT_VISUAL;
return NS_CombineHint(NS_CombineHint(nsChangeHint_UpdateEffects,
nsChangeHint_ReflowFrame),
nsChangeHint_RepaintFrame);
}
#endif
@ -891,14 +922,12 @@ nsChangeHint nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) cons
NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
NS_UpdateHint(hint, nsChangeHint_ReflowFrame);
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
}
if (mStopColor != aOther.mStopColor ||
mFloodColor != aOther.mFloodColor ||
mLightingColor != aOther.mLightingColor ||
mStopOpacity != aOther.mStopOpacity ||
mFloodOpacity != aOther.mFloodOpacity ||
mDominantBaseline != aOther.mDominantBaseline)
} else if (mStopColor != aOther.mStopColor ||
mFloodColor != aOther.mFloodColor ||
mLightingColor != aOther.mLightingColor ||
mStopOpacity != aOther.mStopOpacity ||
mFloodOpacity != aOther.mFloodOpacity ||
mDominantBaseline != aOther.mDominantBaseline)
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
return hint;

View File

@ -104,10 +104,11 @@ include $(topsrcdir)/config/config.mk
FORCE_STATIC_LIB = 1
EXPORTS = \
nsSVGIntegrationUtils.h \
nsSVGUtils.h \
nsSVGEffects.h \
nsSVGFilterInstance.h \
nsSVGForeignObjectFrame.h \
nsSVGIntegrationUtils.h \
nsSVGUtils.h \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -102,12 +102,11 @@ public:
nsIFrame *mClipParent;
nsCOMPtr<nsIDOMSVGMatrix> mClipParentMatrix;
// recursion prevention flag
PRPackedBool mInUse;
// nsSVGContainerFrame methods:
virtual already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
// recursion prevention flag
PRPackedBool mInUse;
};
#endif

View File

@ -71,7 +71,8 @@ public:
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
{
return nsSVGContainerFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
return nsSVGContainerFrameBase::IsFrameOfType(
aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
}
};

View File

@ -38,12 +38,18 @@
#include "nsSVGEffects.h"
#include "nsISupportsImpl.h"
#include "nsSVGOuterSVGFrame.h"
#include "nsSVGFilterFrame.h"
#include "nsSVGClipPathFrame.h"
#include "nsSVGMaskFrame.h"
NS_IMPL_ISUPPORTS1(nsSVGPropertyBase, nsIMutationObserver)
NS_IMPL_ISUPPORTS1(nsSVGRenderingObserver, nsIMutationObserver)
nsSVGPropertyBase::nsSVGPropertyBase(nsIURI *aURI,
nsIFrame *aFrame)
: mElement(this), mFrame(aFrame)
nsSVGRenderingObserver::nsSVGRenderingObserver(nsIURI *aURI,
nsIFrame *aFrame)
: mElement(this), mFrame(aFrame),
mFramePresShell(aFrame->PresContext()->PresShell()),
mReferencedFrame(nsnull),
mReferencedFramePresShell(nsnull)
{
// Start watching the target element
mElement.Reset(aFrame->GetContent(), aURI);
@ -52,22 +58,45 @@ nsSVGPropertyBase::nsSVGPropertyBase(nsIURI *aURI,
}
}
nsSVGPropertyBase::~nsSVGPropertyBase()
nsSVGRenderingObserver::~nsSVGRenderingObserver()
{
if (mElement.get()) {
mElement.get()->RemoveMutationObserver(this);
}
if (mReferencedFrame && !mReferencedFramePresShell->IsDestroying()) {
nsSVGEffects::RemoveRenderingObserver(mReferencedFrame, this);
}
}
nsIFrame*
nsSVGPropertyBase::GetReferencedFrame(nsIAtom* aFrameType, PRBool* aOK)
nsSVGRenderingObserver::GetReferencedFrame()
{
if (mReferencedFrame && !mReferencedFramePresShell->IsDestroying()) {
NS_ASSERTION(mElement.get() &&
static_cast<nsGenericElement*>(mElement.get())->GetPrimaryFrame() == mReferencedFrame,
"Cached frame is incorrect!");
return mReferencedFrame;
}
if (mElement.get()) {
nsIFrame *frame =
static_cast<nsGenericElement*>(mElement.get())->GetPrimaryFrame();
if (frame && frame->GetType() == aFrameType)
if (frame) {
mReferencedFrame = frame;
mReferencedFramePresShell = mReferencedFrame->PresContext()->PresShell();
nsSVGEffects::AddRenderingObserver(mReferencedFrame, this);
return frame;
}
}
return nsnull;
}
nsIFrame*
nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, PRBool* aOK)
{
nsIFrame* frame = GetReferencedFrame();
if (frame && frame->GetType() == aFrameType)
return frame;
if (aOK) {
*aOK = PR_FALSE;
}
@ -75,57 +104,93 @@ nsSVGPropertyBase::GetReferencedFrame(nsIAtom* aFrameType, PRBool* aOK)
}
void
nsSVGPropertyBase::AttributeChanged(nsIDocument *aDocument,
nsIContent *aContent,
PRInt32 aNameSpaceID,
nsIAtom *aAttribute,
PRInt32 aModType,
PRUint32 aStateMask)
nsSVGRenderingObserver::DoUpdate()
{
if (mFramePresShell->IsDestroying()) {
// 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,
PRInt32 aModType,
PRUint32 aStateMask)
{
DoUpdate();
}
void
nsSVGPropertyBase::ContentAppended(nsIDocument *aDocument,
nsIContent *aContainer,
PRInt32 aNewIndexInContainer)
nsSVGRenderingObserver::ContentAppended(nsIDocument *aDocument,
nsIContent *aContainer,
PRInt32 aNewIndexInContainer)
{
DoUpdate();
}
void
nsSVGPropertyBase::ContentInserted(nsIDocument *aDocument,
nsIContent *aContainer,
nsIContent *aChild,
PRInt32 aIndexInContainer)
nsSVGRenderingObserver::ContentInserted(nsIDocument *aDocument,
nsIContent *aContainer,
nsIContent *aChild,
PRInt32 aIndexInContainer)
{
DoUpdate();
}
void
nsSVGPropertyBase::ContentRemoved(nsIDocument *aDocument,
nsIContent *aContainer,
nsIContent *aChild,
PRInt32 aIndexInContainer)
nsSVGRenderingObserver::ContentRemoved(nsIDocument *aDocument,
nsIContent *aContainer,
nsIContent *aChild,
PRInt32 aIndexInContainer)
{
DoUpdate();
}
NS_IMPL_ISUPPORTS_INHERITED1(nsSVGFilterProperty,
nsSVGPropertyBase,
nsSVGRenderingObserver,
nsISVGFilterProperty)
nsSVGFilterProperty::nsSVGFilterProperty(nsIURI *aURI,
nsIFrame *aFilteredFrame)
: nsSVGPropertyBase(aURI, aFilteredFrame)
: nsSVGRenderingObserver(aURI, aFilteredFrame)
{
UpdateRect();
}
nsSVGFilterFrame *
nsSVGFilterProperty::GetFilterFrame() {
return static_cast<nsSVGFilterFrame *>
(GetReferencedFrame(nsGkAtoms::svgFilterFrame, nsnull));
}
void
nsSVGFilterProperty::UpdateRect()
{
nsSVGFilterFrame *filter = GetFilterFrame(nsnull);
nsSVGFilterFrame *filter = GetFilterFrame();
if (filter) {
mFilterRect = filter->GetFilterBBox(mFrame, nsnull);
mFilterRect.ScaleRoundOut(filter->PresContext()->AppUnitsPerDevPixel());
@ -134,96 +199,69 @@ nsSVGFilterProperty::UpdateRect()
}
}
static void
InvalidateAllContinuations(nsIFrame* aFrame)
{
for (nsIFrame* f = aFrame; f; f = f->GetNextContinuation()) {
f->InvalidateOverflowRect();
}
}
void
nsSVGFilterProperty::DoUpdate()
{
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
if (outerSVGFrame) {
outerSVGFrame->Invalidate(mFilterRect);
UpdateRect();
outerSVGFrame->Invalidate(mFilterRect);
}
}
void
nsSVGFilterProperty::ParentChainChanged(nsIContent *aContent)
{
if (aContent->IsInDoc())
nsSVGRenderingObserver::DoUpdate();
if (!mFrame)
return;
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
if (outerSVGFrame) {
outerSVGFrame->InvalidateCoveredRegion(mFrame);
}
mFrame->DeleteProperty(nsGkAtoms::filter);
}
void
nsSVGClipPathProperty::DoUpdate()
{
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
if (outerSVGFrame) {
outerSVGFrame->InvalidateCoveredRegion(mFrame);
if (mFrame->IsFrameOfType(nsIFrame::eSVG)) {
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
if (outerSVGFrame) {
outerSVGFrame->Invalidate(mFilterRect);
UpdateRect();
outerSVGFrame->Invalidate(mFilterRect);
}
} else {
InvalidateAllContinuations(mFrame);
// Reflow so that changes in the filter overflow area get picked up
mFramePresShell->FrameNeedsReflow(
mFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
}
}
void
nsSVGClipPathProperty::ParentChainChanged(nsIContent *aContent)
nsSVGPaintingProperty::DoUpdate()
{
if (aContent->IsInDoc())
nsSVGRenderingObserver::DoUpdate();
if (!mFrame)
return;
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
if (outerSVGFrame) {
outerSVGFrame->InvalidateCoveredRegion(mFrame);
}
mFrame->DeleteProperty(nsGkAtoms::clipPath);
}
void
nsSVGMaskProperty::DoUpdate()
{
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
if (outerSVGFrame) {
outerSVGFrame->InvalidateCoveredRegion(mFrame);
if (mFrame->IsFrameOfType(nsIFrame::eSVG)) {
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
if (outerSVGFrame) {
outerSVGFrame->InvalidateCoveredRegion(mFrame);
}
} else {
InvalidateAllContinuations(mFrame);
}
}
void
nsSVGMaskProperty::ParentChainChanged(nsIContent *aContent)
{
if (aContent->IsInDoc())
return;
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
if (outerSVGFrame) {
outerSVGFrame->InvalidateCoveredRegion(mFrame);
}
mFrame->DeleteProperty(nsGkAtoms::mask);
}
static nsSVGPropertyBase *
static nsSVGRenderingObserver *
CreateFilterProperty(nsIURI *aURI, nsIFrame *aFrame)
{ return new nsSVGFilterProperty(aURI, aFrame); }
static nsSVGPropertyBase *
CreateMaskProperty(nsIURI *aURI, nsIFrame *aFrame)
{ return new nsSVGMaskProperty(aURI, aFrame); }
static nsSVGRenderingObserver *
CreatePaintingProperty(nsIURI *aURI, nsIFrame *aFrame)
{ return new nsSVGPaintingProperty(aURI, aFrame); }
static nsSVGPropertyBase *
CreateClipPathProperty(nsIURI *aURI, nsIFrame *aFrame)
{ return new nsSVGClipPathProperty(aURI, aFrame); }
static nsSVGPropertyBase *
static nsSVGRenderingObserver *
GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp,
nsSVGPropertyBase * (* aCreate)(nsIURI *, nsIFrame *))
nsSVGRenderingObserver * (* aCreate)(nsIURI *, nsIFrame *))
{
if (!aURI)
return nsnull;
nsSVGPropertyBase *prop = static_cast<nsSVGPropertyBase*>(aFrame->GetProperty(aProp));
nsSVGRenderingObserver *prop =
static_cast<nsSVGRenderingObserver*>(aFrame->GetProperty(aProp));
if (prop)
return prop;
prop = aCreate(aURI, aFrame);
@ -236,6 +274,13 @@ GetEffectProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp,
return prop;
}
nsSVGPaintingProperty *
nsSVGEffects::GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp)
{
return static_cast<nsSVGPaintingProperty*>(
GetEffectProperty(aURI, aFrame, aProp, CreatePaintingProperty));
}
nsSVGEffects::EffectProperties
nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
{
@ -245,19 +290,36 @@ nsSVGEffects::GetEffectProperties(nsIFrame *aFrame)
const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
result.mFilter = static_cast<nsSVGFilterProperty*>
(GetEffectProperty(style->mFilter, aFrame, nsGkAtoms::filter, CreateFilterProperty));
result.mClipPath = static_cast<nsSVGClipPathProperty*>
(GetEffectProperty(style->mClipPath, aFrame, nsGkAtoms::clipPath, CreateClipPathProperty));
result.mMask = static_cast<nsSVGMaskProperty*>
(GetEffectProperty(style->mMask, aFrame, nsGkAtoms::mask, CreateMaskProperty));
result.mClipPath = GetPaintingProperty(style->mClipPath, aFrame, nsGkAtoms::clipPath);
result.mMask = GetPaintingProperty(style->mMask, aFrame, nsGkAtoms::mask);
return result;
}
nsSVGClipPathFrame *
nsSVGEffects::EffectProperties::GetClipPathFrame(PRBool *aOK) {
if (!mClipPath)
return nsnull;
return static_cast<nsSVGClipPathFrame *>
(mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
}
nsSVGMaskFrame *
nsSVGEffects::EffectProperties::GetMaskFrame(PRBool *aOK) {
if (!mMask)
return nsnull;
return static_cast<nsSVGMaskFrame *>
(mMask->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
}
void
nsSVGEffects::UpdateEffects(nsIFrame *aFrame)
{
aFrame->DeleteProperty(nsGkAtoms::filter);
aFrame->DeleteProperty(nsGkAtoms::mask);
aFrame->DeleteProperty(nsGkAtoms::clipPath);
aFrame->DeleteProperty(nsGkAtoms::stroke);
aFrame->DeleteProperty(nsGkAtoms::fill);
}
nsSVGFilterProperty *
@ -270,3 +332,98 @@ nsSVGEffects::GetFilterProperty(nsIFrame *aFrame)
return static_cast<nsSVGFilterProperty *>(aFrame->GetProperty(nsGkAtoms::filter));
}
static PLDHashOperator PR_CALLBACK
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;
mObservers.EnumerateEntries(GatherEnumerator, &observers);
for (PRUint32 i = 0; i < observers.Length(); ++i) {
observers[i]->InvalidateViaReferencedFrame();
}
}
static nsSVGRenderingObserverList *
GetObserverList(nsIFrame *aFrame)
{
if (!(aFrame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS))
return nsnull;
return static_cast<nsSVGRenderingObserverList*>(aFrame->GetProperty(nsGkAtoms::observer));
}
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);
}
aFrame->SetProperty(nsGkAtoms::observer, observerList);
}
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();
}
}

View File

@ -43,14 +43,26 @@
#include "nsReferencedElement.h"
#include "nsStubMutationObserver.h"
#include "nsSVGUtils.h"
#include "nsSVGFilterFrame.h"
#include "nsSVGClipPathFrame.h"
#include "nsSVGMaskFrame.h"
#include "nsTHashtable.h"
class nsSVGPropertyBase : public nsStubMutationObserver {
class nsSVGClipPathFrame;
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.
*/
class nsSVGRenderingObserver : public nsStubMutationObserver {
public:
nsSVGPropertyBase(nsIURI* aURI, nsIFrame *aFrame);
virtual ~nsSVGPropertyBase();
nsSVGRenderingObserver(nsIURI* aURI, nsIFrame *aFrame);
virtual ~nsSVGRenderingObserver();
// nsISupports
NS_DECL_ISUPPORTS
@ -61,13 +73,22 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
void InvalidateViaReferencedFrame();
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);
protected:
// This is called when the referenced filter/mask/clipPath changes
virtual void DoUpdate() = 0;
// This is called when the referenced resource changes.
virtual void DoUpdate();
class SourceReference : public nsReferencedElement {
public:
SourceReference(nsSVGPropertyBase* aContainer) : mContainer(aContainer) {}
SourceReference(nsSVGRenderingObserver* aContainer) : mContainer(aContainer) {}
protected:
virtual void ContentChanged(nsIContent* aFrom, nsIContent* aTo) {
if (aFrom) {
@ -85,41 +106,41 @@ protected:
*/
virtual PRBool IsPersistent() { return PR_TRUE; }
private:
nsSVGPropertyBase* mContainer;
nsSVGRenderingObserver* mContainer;
};
/**
* @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);
SourceReference mElement;
nsIFrame *mFrame;
// The frame that this property is attached to
nsIFrame *mFrame;
// When a presshell is torn down, we don't delete the properties for
// each frame until after the frames are destroyed. So here we remember
// the presshell for the frames we care about and, before we use the frame,
// 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;
nsIFrame *mReferencedFrame;
nsIPresShell *mReferencedFramePresShell;
};
class nsSVGFilterProperty :
public nsSVGPropertyBase, public nsISVGFilterProperty {
public nsSVGRenderingObserver, public nsISVGFilterProperty {
public:
nsSVGFilterProperty(nsIURI *aURI, nsIFrame *aFilteredFrame);
nsSVGFilterFrame *GetFilterFrame(PRBool *aOK) {
return static_cast<nsSVGFilterFrame *>
(GetReferencedFrame(nsGkAtoms::svgFilterFrame, aOK));
}
/**
* @return the filter frame, or null if there is no filter frame
*/
nsSVGFilterFrame *GetFilterFrame();
void UpdateRect();
// nsISupports
NS_DECL_ISUPPORTS
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
// nsISVGFilterProperty
virtual void Invalidate() { DoUpdate(); }
private:
// nsSVGPropertyBase
// nsSVGRenderingObserver
virtual void DoUpdate();
// Tracks a bounding box for the filtered mFrame. We need this so that
@ -129,69 +150,125 @@ private:
nsRect mFilterRect;
};
class nsSVGClipPathProperty : public nsSVGPropertyBase {
class nsSVGPaintingProperty : public nsSVGRenderingObserver {
public:
nsSVGClipPathProperty(nsIURI *aURI, nsIFrame *aClippedFrame)
: nsSVGPropertyBase(aURI, aClippedFrame) {}
nsSVGPaintingProperty(nsIURI *aURI, nsIFrame *aClippedFrame)
: nsSVGRenderingObserver(aURI, aClippedFrame) {}
nsSVGClipPathFrame *GetClipPathFrame(PRBool *aOK) {
return static_cast<nsSVGClipPathFrame *>
(GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
}
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
private:
protected:
virtual void DoUpdate();
};
class nsSVGMaskProperty : public nsSVGPropertyBase {
/**
* A manager for one-shot nsSVGRenderingObserver tracking.
* nsSVGRenderingObservers can be added or removed. They are not strongly
* referenced so an observer must be removed before it before it dies.
* When InvalidateAll is called, all outstanding references get
* InvalidateViaReferencedFrame()
* called on them and the list is cleared. The intent is that
* the observer will force repainting of whatever part of the document
* is needed, and then at paint time the observer will be re-added.
*
* InvalidateAll must be called before this object is destroyed, i.e.
* before the referenced frame is destroyed. This should normally happen
* via nsSVGContainerFrame::RemoveFrame, since only frames in the frame
* tree should be referenced.
*/
class nsSVGRenderingObserverList {
public:
nsSVGMaskProperty(nsIURI *aURI, nsIFrame *aMaskedFrame)
: nsSVGPropertyBase(aURI, aMaskedFrame) {}
nsSVGRenderingObserverList() { mObservers.Init(5); }
~nsSVGRenderingObserverList() { InvalidateAll(); }
nsSVGMaskFrame *GetMaskFrame(PRBool *aOK) {
return static_cast<nsSVGMaskFrame *>
(GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
}
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
void Add(nsSVGRenderingObserver* aObserver)
{ mObservers.PutEntry(aObserver); }
void Remove(nsSVGRenderingObserver* aObserver)
{ mObservers.RemoveEntry(aObserver); }
void InvalidateAll();
private:
virtual void DoUpdate();
nsTHashtable<nsVoidPtrHashKey> mObservers;
};
class nsSVGEffects {
public:
struct EffectProperties {
nsSVGFilterProperty* mFilter;
nsSVGMaskProperty* mMask;
nsSVGClipPathProperty* mClipPath;
nsSVGPaintingProperty* mMask;
nsSVGPaintingProperty* mClipPath;
/**
* @return the clip-path frame, or null if there is no clip-path frame
* @param aOK if a clip-path was specified but the designated element
* does not exist or is an element of the wrong type, *aOK is set
* to false. Otherwise *aOK is untouched.
*/
nsSVGClipPathFrame *GetClipPathFrame(PRBool *aOK);
/**
* @return the mask frame, or null if there is no mask frame
* @param aOK if a mask was specified but the designated element
* does not exist or is an element of the wrong type, *aOK is set
* to false. Otherwise *aOK is untouched.
*/
nsSVGMaskFrame *GetMaskFrame(PRBool *aOK);
/**
* @return the filter frame, or null if there is no filter frame
* @param aOK if a filter was specified but the designated element
* does not exist or is an element of the wrong type, *aOK is set
* to false. Otherwise *aOK is untouched.
*/
nsSVGFilterFrame *GetFilterFrame(PRBool *aOK) {
if (!mFilter)
return nsnull;
nsSVGFilterFrame *filter = mFilter->GetFilterFrame();
if (!filter) {
*aOK = PR_FALSE;
}
return filter;
}
};
/**
* @param aFrame should be the first continuation
*/
static EffectProperties GetEffectProperties(nsIFrame *aFrame);
/**
* Called by nsCSSFrameConstructor when style changes require the
* effect properties on aFrame to be updated
*/
static void UpdateEffects(nsIFrame *aFrame);
/**
* @param aFrame should be the first continuation
*/
static nsSVGFilterProperty *GetFilterProperty(nsIFrame *aFrame);
static nsSVGFilterFrame *GetFilterFrame(nsIFrame *aFrame) {
nsSVGFilterProperty *prop = GetFilterProperty(aFrame);
PRBool ok;
return prop ? prop->GetFilterFrame(&ok) : nsnull;
return prop ? prop->GetFilterFrame() : nsnull;
}
/**
* @param aFrame must be a first-continuation.
*/
static void AddRenderingObserver(nsIFrame *aFrame, nsSVGRenderingObserver *aObserver);
/**
* @param aFrame must be a first-continuation.
*/
static void RemoveRenderingObserver(nsIFrame *aFrame, nsSVGRenderingObserver *aObserver);
/**
* This can be called on any first-continuation frame. We walk up to
* the nearest observable frame and invalidate its observers.
*/
static void InvalidateRenderingObservers(nsIFrame *aFrame);
/**
* This can be called on any frame. Direct observers
* of this frame are all invalidated.
*/
static void InvalidateDirectRenderingObservers(nsIFrame *aFrame);
/**
* Get an nsSVGPaintingProperty for the frame, creating a fresh one if necessary
*/
static nsSVGPaintingProperty *
GetPaintingProperty(nsIURI *aURI, nsIFrame *aFrame, nsIAtom *aProp);
};
#endif /*NSSVGEFFECTS_H_*/

View File

@ -78,7 +78,8 @@ nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
mPropagateTransform(PR_TRUE),
mInReflow(PR_FALSE)
{
AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED);
AddStateBits(NS_FRAME_REFLOW_ROOT |
NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS);
}
//----------------------------------------------------------------------

View File

@ -40,26 +40,11 @@
#include "nsSVGPaintServerFrame.h"
#include "nsContentUtils.h"
#include "gfxContext.h"
//----------------------------------------------------------------------
// nsISupports methods
NS_INTERFACE_MAP_BEGIN(nsSVGGeometryFrame)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
NS_INTERFACE_MAP_END_INHERITING(nsSVGGeometryFrameBase)
#include "nsSVGEffects.h"
//----------------------------------------------------------------------
// nsIFrame methods
void
nsSVGGeometryFrame::Destroy()
{
// Remove the properties before the frame goes away, since we need it for QI
RemovePaintServerProperties();
nsSVGGeometryFrameBase::Destroy();
}
NS_IMETHODIMP
nsSVGGeometryFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
@ -71,99 +56,21 @@ nsSVGGeometryFrame::Init(nsIContent* aContent,
return rv;
}
NS_IMETHODIMP
nsSVGGeometryFrame::DidSetStyleContext()
{
// One of the styles that might have been changed are the urls that
// point to gradients, etc. Drop our cached values to those
RemovePaintServerProperties();
return NS_OK;
}
//----------------------------------------------------------------------
// nsISVGValueObserver methods:
NS_IMETHODIMP
nsSVGGeometryFrame::WillModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType)
{
return NS_OK;
}
NS_IMETHODIMP
nsSVGGeometryFrame::DidModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType)
{
if (!(GetStateBits() & NS_STATE_SVG_PSERVER_MASK))
return NS_OK;
nsIFrame *frame;
CallQueryInterface(observable, &frame);
if (!frame)
return NS_OK;
PRBool refresh = PR_FALSE;
if (GetStateBits() & NS_STATE_SVG_FILL_PSERVER) {
nsIFrame *ps = static_cast<nsIFrame*>(GetProperty(nsGkAtoms::fill));
if (frame == ps) {
if (aModType == nsISVGValue::mod_die) {
DeleteProperty(nsGkAtoms::fill);
RemoveStateBits(NS_STATE_SVG_FILL_PSERVER);
}
refresh = PR_TRUE;
}
}
if (GetStateBits() & NS_STATE_SVG_STROKE_PSERVER) {
nsIFrame *ps = static_cast<nsIFrame*>(GetProperty(nsGkAtoms::stroke));
if (frame == ps) {
if (aModType == nsISVGValue::mod_die) {
DeleteProperty(nsGkAtoms::stroke);
RemoveStateBits(NS_STATE_SVG_STROKE_PSERVER);
}
refresh = PR_TRUE;
}
}
if (refresh) {
nsISVGChildFrame* svgFrame = nsnull;
CallQueryInterface(this, &svgFrame);
if (svgFrame) {
nsSVGUtils::UpdateGraphic(svgFrame);
}
}
return NS_OK;
}
//----------------------------------------------------------------------
void
nsSVGGeometryFrame::RemovePaintServerProperties()
{
DeleteProperty(nsGkAtoms::fill);
DeleteProperty(nsGkAtoms::stroke);
RemoveStateBits(NS_STATE_SVG_PSERVER_MASK);
}
nsSVGPaintServerFrame *
nsSVGGeometryFrame::GetPaintServer(const nsStyleSVGPaint *aPaint)
nsSVGGeometryFrame::GetPaintServer(const nsStyleSVGPaint *aPaint,
nsIAtom *aType)
{
if (aPaint->mType != eStyleSVGPaintType_Server)
return nsnull;
nsIURI *uri;
uri = aPaint->mPaint.mPaintServer;
if (!uri)
nsSVGPaintingProperty *property =
nsSVGEffects::GetPaintingProperty(aPaint->mPaint.mPaintServer, this, aType);
if (!property)
return nsnull;
nsIFrame *result;
if (NS_FAILED(nsSVGUtils::GetReferencedFrame(&result, uri, mContent,
PresContext()->PresShell())))
nsIFrame *result = property->GetReferencedFrame();
if (!result)
return nsnull;
nsIAtom *type = result->GetType();
@ -172,16 +79,7 @@ nsSVGGeometryFrame::GetPaintServer(const nsStyleSVGPaint *aPaint)
type != nsGkAtoms::svgPatternFrame)
return nsnull;
// Loop check for pattern
if (type == nsGkAtoms::svgPatternFrame &&
nsContentUtils::ContentIsDescendantOf(mContent, result->GetContent()))
return nsnull;
nsSVGPaintServerFrame *server =
static_cast<nsSVGPaintServerFrame*>(result);
server->AddObserver(this);
return server;
return static_cast<nsSVGPaintServerFrame*>(result);
}
float
@ -255,60 +153,6 @@ nsSVGGeometryFrame::GetClipRule()
return GetStyleSVG()->mClipRule;
}
static void
PServerPropertyDtor(void *aObject, nsIAtom *aPropertyName,
void *aPropertyValue, void *aData)
{
nsIFrame *ps = static_cast<nsIFrame*>(aPropertyValue);
nsSVGUtils::RemoveObserver(static_cast<nsIFrame*>(aObject), ps);
}
PRBool
nsSVGGeometryFrame::HasStroke()
{
if (!(GetStateBits() & NS_STATE_SVG_STROKE_PSERVER)) {
nsIFrame *ps = GetPaintServer(&GetStyleSVG()->mStroke);
if (ps) {
SetProperty(nsGkAtoms::stroke, ps, PServerPropertyDtor);
AddStateBits(NS_STATE_SVG_STROKE_PSERVER);
}
}
// cairo will stop rendering if stroke-width is less than or equal to zero
if (GetStrokeWidth() <= 0)
return PR_FALSE;
// Check for eStyleSVGPaintType_Server as the NS_STATE_SVG_STROKE_PSERVER
// state bit is only set if we have a valid URL. If we don't, we still have
// to stroke although we will be using the fallback colour
if (GetStyleSVG()->mStroke.mType == eStyleSVGPaintType_Color ||
GetStyleSVG()->mStroke.mType == eStyleSVGPaintType_Server)
return PR_TRUE;
return PR_FALSE;
}
PRBool
nsSVGGeometryFrame::HasFill()
{
if (!(GetStateBits() & NS_STATE_SVG_FILL_PSERVER)) {
nsIFrame *ps = GetPaintServer(&GetStyleSVG()->mFill);
if (ps) {
SetProperty(nsGkAtoms::fill, ps, PServerPropertyDtor);
AddStateBits(NS_STATE_SVG_FILL_PSERVER);
}
}
// Check for eStyleSVGPaintType_Server as the NS_STATE_SVG_FILL_PSERVER
// state bit is only set if we have a valid URL. If we don't, we still have
// to fill although we will be using the fallback colour
if (GetStyleSVG()->mFill.mType == eStyleSVGPaintType_Color ||
GetStyleSVG()->mFill.mType == eStyleSVGPaintType_Server)
return PR_TRUE;
return PR_FALSE;
}
PRBool
nsSVGGeometryFrame::IsClipChild()
{
@ -357,17 +201,14 @@ nsSVGGeometryFrame::SetupCairoFill(gfxContext *aContext)
float opacity = MaybeOptimizeOpacity(GetStyleSVG()->mFillOpacity);
if (GetStateBits() & NS_STATE_SVG_FILL_PSERVER) {
nsSVGPaintServerFrame *ps = static_cast<nsSVGPaintServerFrame*>
(GetProperty(nsGkAtoms::fill));
if (ps->SetupPaintServer(aContext, this, opacity))
return PR_TRUE;
// On failure, use the fallback colour in case we have an
// objectBoundingBox where the width or height of the object is zero.
// See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
}
nsSVGPaintServerFrame *ps =
GetPaintServer(&GetStyleSVG()->mFill, nsGkAtoms::fill);
if (ps && ps->SetupPaintServer(aContext, this, opacity))
return PR_TRUE;
// On failure, use the fallback colour in case we have an
// objectBoundingBox where the width or height of the object is zero.
// See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
if (GetStyleSVG()->mFill.mType == eStyleSVGPaintType_Server) {
SetupCairoColor(aContext,
GetStyleSVG()->mFill.mFallbackColor,
@ -380,12 +221,19 @@ nsSVGGeometryFrame::SetupCairoFill(gfxContext *aContext)
return PR_TRUE;
}
void
PRBool
nsSVGGeometryFrame::SetupCairoStrokeGeometry(gfxContext *aContext)
{
aContext->SetLineWidth(GetStrokeWidth());
const nsStyleSVG* style = GetStyleSVG();
if (style->mStroke.mType == eStyleSVGPaintType_None)
return PR_FALSE;
float width = GetStrokeWidth();
if (width <= 0)
return PR_FALSE;
aContext->SetLineWidth(width);
switch (GetStyleSVG()->mStrokeLinecap) {
switch (style->mStrokeLinecap) {
case NS_STYLE_STROKE_LINECAP_BUTT:
aContext->SetLineCap(gfxContext::LINE_CAP_BUTT);
break;
@ -397,9 +245,9 @@ nsSVGGeometryFrame::SetupCairoStrokeGeometry(gfxContext *aContext)
break;
}
aContext->SetMiterLimit(GetStyleSVG()->mStrokeMiterlimit);
aContext->SetMiterLimit(style->mStrokeMiterlimit);
switch (GetStyleSVG()->mStrokeLinejoin) {
switch (style->mStrokeLinejoin) {
case NS_STYLE_STROKE_LINEJOIN_MITER:
aContext->SetLineJoin(gfxContext::LINE_JOIN_MITER);
break;
@ -410,12 +258,15 @@ nsSVGGeometryFrame::SetupCairoStrokeGeometry(gfxContext *aContext)
aContext->SetLineJoin(gfxContext::LINE_JOIN_BEVEL);
break;
}
return PR_TRUE;
}
void
PRBool
nsSVGGeometryFrame::SetupCairoStrokeHitGeometry(gfxContext *aContext)
{
SetupCairoStrokeGeometry(aContext);
if (!SetupCairoStrokeGeometry(aContext))
return PR_FALSE;
gfxFloat *dashArray;
PRUint32 count;
@ -424,26 +275,25 @@ nsSVGGeometryFrame::SetupCairoStrokeHitGeometry(gfxContext *aContext)
aContext->SetDash(dashArray, count, GetStrokeDashoffset());
delete [] dashArray;
}
return PR_TRUE;
}
PRBool
nsSVGGeometryFrame::SetupCairoStroke(gfxContext *aContext)
{
SetupCairoStrokeHitGeometry(aContext);
if (!SetupCairoStrokeHitGeometry(aContext))
return PR_FALSE;
float opacity = MaybeOptimizeOpacity(GetStyleSVG()->mStrokeOpacity);
if (GetStateBits() & NS_STATE_SVG_STROKE_PSERVER) {
nsSVGPaintServerFrame *ps = static_cast<nsSVGPaintServerFrame*>
(GetProperty(nsGkAtoms::stroke));
if (ps->SetupPaintServer(aContext, this, opacity))
return PR_TRUE;
// On failure, use the fallback colour in case we have an
// objectBoundingBox where the width or height of the object is zero.
// See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
}
nsSVGPaintServerFrame *ps =
GetPaintServer(&GetStyleSVG()->mStroke, nsGkAtoms::stroke);
if (ps && ps->SetupPaintServer(aContext, this, opacity))
return PR_TRUE;
// On failure, use the fallback colour in case we have an
// objectBoundingBox where the width or height of the object is zero.
// See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
if (GetStyleSVG()->mStroke.mType == eStyleSVGPaintType_Server) {
SetupCairoColor(aContext,
GetStyleSVG()->mStroke.mFallbackColor,

View File

@ -38,8 +38,6 @@
#define __NS_SVGGEOMETRYFRAME_H__
#include "nsFrame.h"
#include "nsWeakReference.h"
#include "nsISVGValueObserver.h"
class nsSVGPaintServerFrame;
class gfxContext;
@ -52,34 +50,22 @@ typedef nsFrame nsSVGGeometryFrameBase;
* cairo context information and stores the fill/stroke paint
* servers. */
class nsSVGGeometryFrame : public nsSVGGeometryFrameBase,
public nsISVGValueObserver
class nsSVGGeometryFrame : public nsSVGGeometryFrameBase
{
protected:
nsSVGGeometryFrame(nsStyleContext *aContext) : nsSVGGeometryFrameBase(aContext) {}
public:
// nsIFrame interface:
virtual void Destroy();
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow);
NS_IMETHOD DidSetStyleContext();
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
{
return nsSVGGeometryFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
}
// nsISupports interface:
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
// nsISVGValueObserver interface:
NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType);
NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType);
// nsSVGGeometryFrame methods:
NS_IMETHOD GetCanvasTM(nsIDOMSVGMatrix * *aCanvasTM) = 0;
PRUint16 GetClipRule();
@ -87,25 +73,21 @@ public:
float GetStrokeWidth();
// Check if this geometry needs to be filled or stroked. These also
// have the side effect of looking up the paint server if that is
// the indicated type and storing it in a property, so need to be
// called before SetupCairo{Fill,Stroke}.
PRBool HasFill();
PRBool HasStroke();
/*
* Set up a cairo context for filling a path
* @return PR_FALSE to skip rendering
*/
PRBool SetupCairoFill(gfxContext *aContext);
// Set up a cairo context for measuring a stroked path
void SetupCairoStrokeGeometry(gfxContext *aContext);
// Set up a cairo context for hit testing a stroked path
void SetupCairoStrokeHitGeometry(gfxContext *aContext);
/*
* Set up a cairo context for measuring a stroked path
* @return PR_FALSE if there is no stroke
*/
PRBool SetupCairoStrokeGeometry(gfxContext *aContext);
/*
* Set up a cairo context for hit testing a stroked path
* @return PR_FALSE if there is no stroke
*/
PRBool SetupCairoStrokeHitGeometry(gfxContext *aContext);
/*
* Set up a cairo context for stroking a path
* @return PR_FALSE to skip rendering
@ -113,12 +95,12 @@ public:
PRBool SetupCairoStroke(gfxContext *aContext);
protected:
nsSVGPaintServerFrame *GetPaintServer(const nsStyleSVGPaint *aPaint);
nsSVGPaintServerFrame *GetPaintServer(const nsStyleSVGPaint *aPaint,
nsIAtom *aType);
private:
nsresult GetStrokeDashArray(double **arr, PRUint32 *count);
float GetStrokeDashoffset();
void RemovePaintServerProperties();
// Returns opacity that should be used in rendering this primitive.
// In the general case the return value is just the passed opacity.

View File

@ -338,7 +338,7 @@ nsSVGGlyphFrame::PaintSVG(nsSVGRenderState *aContext, nsIntRect *aDirtyRect)
gfx->Save();
SetupGlobalTransform(gfx);
if (HasFill() && SetupCairoFill(gfx)) {
if (SetupCairoFill(gfx)) {
gfxMatrix matrix = gfx->CurrentMatrix();
CharacterIterator iter(this, PR_TRUE);
iter.SetInitialMatrix(gfx);
@ -347,7 +347,7 @@ nsSVGGlyphFrame::PaintSVG(nsSVGRenderState *aContext, nsIntRect *aDirtyRect)
gfx->SetMatrix(matrix);
}
if (HasStroke() && SetupCairoStroke(gfx)) {
if (SetupCairoStroke(gfx)) {
// SetupCairoStroke will clear mTextRun whenever
// there is a pattern or gradient on the text
CharacterIterator iter(this, PR_TRUE);
@ -433,11 +433,10 @@ nsSVGGlyphFrame::UpdateCoveredRegion()
gfxRect extent;
if (HasStroke()) {
if (SetupCairoStrokeGeometry(tmpCtx)) {
AddCharactersToPath(&iter, tmpCtx);
SetupCairoStrokeGeometry(tmpCtx);
extent = tmpCtx->UserToDevice(tmpCtx->GetUserStrokeExtent());
} else if (HasFill()) {
} else if (GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None) {
AddBoundingBoxesToPath(&iter, tmpCtx);
tmpCtx->IdentityMatrix();
extent = tmpCtx->GetUserPathExtent();

View File

@ -41,6 +41,7 @@
#include "nsIDOMSVGAnimTransformList.h"
#include "nsSVGTransformList.h"
#include "nsSVGMatrix.h"
#include "nsSVGEffects.h"
#include "nsIDOMSVGStopElement.h"
#include "nsSVGGradientElement.h"
#include "nsSVGGeometryFrame.h"
@ -55,9 +56,8 @@
nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext,
nsIDOMSVGURIReference *aRef) :
nsSVGGradientFrameBase(aContext),
mNextGrad(nsnull),
mLoopFlag(PR_FALSE),
mInitialized(PR_FALSE)
mNoHRefURI(PR_FALSE)
{
if (aRef) {
// Get the href
@ -65,97 +65,14 @@ nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext,
}
}
nsSVGGradientFrame::~nsSVGGradientFrame()
{
WillModify(mod_die);
// Notify the world that we're dying
DidModify(mod_die);
if (mNextGrad)
mNextGrad->RemoveObserver(this);
}
//----------------------------------------------------------------------
// nsISupports methods:
NS_INTERFACE_MAP_BEGIN(nsSVGGradientFrame)
NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END_INHERITING(nsSVGGradientFrameBase)
//----------------------------------------------------------------------
// nsISVGValueObserver methods:
NS_IMETHODIMP
nsSVGGradientFrame::WillModifySVGObservable(nsISVGValue* observable,
modificationType aModType)
{
// return if we have an mObservers loop
if (mLoopFlag) {
// XXXjwatt: we should really send an error to the JavaScript Console here:
NS_WARNING("gradient reference loop detected while notifying observers!");
return NS_OK;
}
// Don't pass on mod_die - our gradient observers would stop observing us!
if (aModType == mod_die)
aModType = mod_other;
WillModify(aModType);
return NS_OK;
}
NS_IMETHODIMP
nsSVGGradientFrame::DidModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType)
{
// return if we have an mObservers loop
if (mLoopFlag) {
// XXXjwatt: we should really send an error to the JavaScript Console here:
NS_WARNING("gradient reference loop detected while notifying observers!");
return NS_OK;
}
// If we reference another gradient and it's going away, null out mNextGrad
if (mNextGrad && aModType == nsISVGValue::mod_die) {
nsIFrame *gradient = nsnull;
CallQueryInterface(observable, &gradient);
if (mNextGrad == gradient)
mNextGrad = nsnull;
}
// Don't pass on mod_die - our gradient observers would stop observing us!
if (aModType == mod_die)
aModType = mod_other;
DidModify(aModType);
return NS_OK;
}
//----------------------------------------------------------------------
// nsIFrame methods:
NS_IMETHODIMP
nsSVGGradientFrame::DidSetStyleContext()
{
WillModify();
DidModify();
return NS_OK;
}
NS_IMETHODIMP
nsSVGGradientFrame::RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame)
{
WillModify();
DidModify();
PRBool result = mFrames.DestroyFrame(aOldFrame);
return result ? NS_OK : NS_ERROR_FAILURE;
}
nsIAtom*
nsSVGGradientFrame::GetType() const
{
return nsGkAtoms::svgGradientFrame;
nsSVGEffects::InvalidateRenderingObservers(this);
return nsSVGGradientFrameBase::DidSetStyleContext();
}
NS_IMETHODIMP
@ -167,19 +84,14 @@ nsSVGGradientFrame::AttributeChanged(PRInt32 aNameSpaceID,
(aAttribute == nsGkAtoms::gradientUnits ||
aAttribute == nsGkAtoms::gradientTransform ||
aAttribute == nsGkAtoms::spreadMethod)) {
WillModify();
DidModify();
return NS_OK;
}
if (aNameSpaceID == kNameSpaceID_XLink &&
aAttribute == nsGkAtoms::href) {
if (mNextGrad)
mNextGrad->RemoveObserver(this);
WillModify();
GetRefedGradientFromHref();
DidModify();
return NS_OK;
nsSVGEffects::InvalidateRenderingObservers(this);
} else if (aNameSpaceID == kNameSpaceID_XLink &&
aAttribute == nsGkAtoms::href) {
// Blow away our reference, if any
DeleteProperty(nsGkAtoms::href);
mNoHRefURI = PR_FALSE;
// And update whoever references us
nsSVGEffects::InvalidateRenderingObservers(this);
}
return nsSVGGradientFrameBase::AttributeChanged(aNameSpaceID,
@ -289,14 +201,11 @@ nsSVGGradientFrame::GetGradientTransform(nsSVGGeometryFrame *aSource)
}
}
nsIContent *gradient = GetGradientWithAttr(nsGkAtoms::gradientTransform);
if (!gradient)
gradient = mContent; // use our gradient to get the correct default value
nsSVGGradientElement *element =
GetGradientWithAttr(nsGkAtoms::gradientTransform, mContent);
nsSVGGradientElement *gradElement = static_cast<nsSVGGradientElement*>
(gradient);
nsCOMPtr<nsIDOMSVGTransformList> trans;
gradElement->mGradientTransform->GetAnimVal(getter_AddRefs(trans));
element->mGradientTransform->GetAnimVal(getter_AddRefs(trans));
nsCOMPtr<nsIDOMSVGMatrix> gradientTransform =
nsSVGTransformList::GetConsolidationMatrix(trans);
@ -309,14 +218,10 @@ nsSVGGradientFrame::GetGradientTransform(nsSVGGeometryFrame *aSource)
PRUint16
nsSVGGradientFrame::GetSpreadMethod()
{
nsIContent *gradient = GetGradientWithAttr(nsGkAtoms::spreadMethod);
if (!gradient)
gradient = mContent; // use our gradient to get the correct default value
nsSVGGradientElement *element =
GetGradientWithAttr(nsGkAtoms::spreadMethod, mContent);
nsSVGGradientElement *gradElement = static_cast<nsSVGGradientElement*>
(gradient);
return gradElement->mEnumAttributes[nsSVGGradientElement::SPREADMETHOD].GetAnimValue();
return element->mEnumAttributes[nsSVGGradientElement::SPREADMETHOD].GetAnimValue();
}
//----------------------------------------------------------------------
@ -387,101 +292,97 @@ nsSVGGradientFrame::SetupPaintServer(gfxContext *aContext,
// Private (helper) methods
void
nsSVGGradientFrame::GetRefedGradientFromHref()
nsSVGGradientFrame *
nsSVGGradientFrame::GetReferencedGradient()
{
mNextGrad = nsnull;
mInitialized = PR_TRUE;
if (mNoHRefURI)
return nsnull;
// Fetch our gradient element's xlink:href attribute
nsAutoString href;
mHref->GetAnimVal(href);
if (href.IsEmpty()) {
return; // no URL
}
nsSVGPaintingProperty *property =
static_cast<nsSVGPaintingProperty*>(GetProperty(nsGkAtoms::href));
// Convert href to an nsIURI
nsCOMPtr<nsIURI> targetURI;
nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
mContent->GetCurrentDoc(), base);
// Fetch and store a pointer to the referenced gradient element's frame.
// Note that we are using *our* frame tree for this call, otherwise we're
// going to have to get the PresShell in each call
nsIFrame *nextGrad;
if (NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&nextGrad, targetURI, mContent,
PresContext()->PresShell()))) {
nsIAtom* frameType = nextGrad->GetType();
if (frameType != nsGkAtoms::svgLinearGradientFrame &&
frameType != nsGkAtoms::svgRadialGradientFrame)
return;
mNextGrad = reinterpret_cast<nsSVGGradientFrame*>(nextGrad);
// Add ourselves to the observer list
if (mNextGrad) {
// Can't use the NS_ADD macro here because of nsISupports ambiguity
mNextGrad->AddObserver(this);
if (!property) {
// Fetch our gradient element's xlink:href attribute
nsAutoString href;
mHref->GetAnimVal(href);
if (href.IsEmpty()) {
mNoHRefURI = PR_TRUE;
return nsnull; // no URL
}
// Convert href to an nsIURI
nsCOMPtr<nsIURI> targetURI;
nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
mContent->GetCurrentDoc(), base);
property = nsSVGEffects::GetPaintingProperty(targetURI, this, nsGkAtoms::href);
if (!property)
return nsnull;
}
nsIFrame *result = property->GetReferencedFrame();
if (!result)
return nsnull;
nsIAtom* frameType = result->GetType();
if (frameType != nsGkAtoms::svgLinearGradientFrame &&
frameType != nsGkAtoms::svgRadialGradientFrame)
return nsnull;
return static_cast<nsSVGGradientFrame*>(result);
}
// This is implemented to return nsnull if the attribute is not set so that
// GetFx and GetFy can use the values of cx and cy instead of the defaults.
nsIContent*
nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName)
nsSVGGradientElement *
nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
{
if (mContent->HasAttr(kNameSpaceID_None, aAttrName))
return mContent;
return static_cast<nsSVGGradientElement *>(mContent);
if (!mInitialized) // make sure mNextGrad has been initialized
GetRefedGradientFromHref();
nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(aDefault);
if (!mNextGrad)
return nsnull;
nsIContent *grad = nsnull;
nsSVGGradientFrame *next = GetReferencedGradient();
if (!next)
return grad;
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
mLoopFlag = PR_TRUE;
// XXXjwatt: we should really send an error to the JavaScript Console here:
NS_WARN_IF_FALSE(!mNextGrad->mLoopFlag, "gradient reference loop detected "
"while inheriting attribute!");
if (!mNextGrad->mLoopFlag)
grad = mNextGrad->GetGradientWithAttr(aAttrName);
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
"while inheriting attribute!");
if (!next->mLoopFlag)
grad = next->GetGradientWithAttr(aAttrName, aDefault);
mLoopFlag = PR_FALSE;
return grad;
}
nsIContent*
nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName, nsIAtom *aGradType)
nsSVGGradientElement *
nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName, nsIAtom *aGradType,
nsIContent *aDefault)
{
if (GetType() == aGradType && mContent->HasAttr(kNameSpaceID_None, aAttrName))
return mContent;
return static_cast<nsSVGGradientElement *>(mContent);
if (!mInitialized)
GetRefedGradientFromHref(); // make sure mNextGrad has been initialized
nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(aDefault);
if (!mNextGrad)
return nsnull;
nsIContent *grad = nsnull;
nsSVGGradientFrame *next = GetReferencedGradient();
if (!next)
return grad;
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
mLoopFlag = PR_TRUE;
// XXXjwatt: we should really send an error to the JavaScript Console here:
NS_WARN_IF_FALSE(!mNextGrad->mLoopFlag, "gradient reference loop detected "
"while inheriting attribute!");
if (!mNextGrad->mLoopFlag)
grad = mNextGrad->GetGradientWithAttr(aAttrName, aGradType);
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
"while inheriting attribute!");
if (!next->mLoopFlag)
grad = next->GetGradientWithAttr(aAttrName, aGradType, aDefault);
mLoopFlag = PR_FALSE;
return grad;
}
PRInt32
PRInt32
nsSVGGradientFrame::GetStopFrame(PRInt32 aIndex, nsIFrame * *aStopFrame)
{
PRInt32 stopCount = 0;
@ -502,10 +403,8 @@ nsSVGGradientFrame::GetStopFrame(PRInt32 aIndex, nsIFrame * *aStopFrame)
// Our gradient element doesn't have stops - try to "inherit" them
if (!mInitialized)
GetRefedGradientFromHref(); // make sure mNextGrad has been initialized
if (!mNextGrad) {
nsSVGGradientFrame *next = GetReferencedGradient();
if (!next) {
if (aStopFrame)
*aStopFrame = nsnull;
return 0;
@ -514,10 +413,10 @@ nsSVGGradientFrame::GetStopFrame(PRInt32 aIndex, nsIFrame * *aStopFrame)
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
mLoopFlag = PR_TRUE;
// XXXjwatt: we should really send an error to the JavaScript Console here:
NS_WARN_IF_FALSE(!mNextGrad->mLoopFlag, "gradient reference loop detected "
"while inheriting stop!");
if (!mNextGrad->mLoopFlag)
stopCount = mNextGrad->GetStopFrame(aIndex, aStopFrame);
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
"while inheriting stop!");
if (!next->mLoopFlag)
stopCount = next->GetStopFrame(aIndex, aStopFrame);
mLoopFlag = PR_FALSE;
return stopCount;
@ -528,14 +427,9 @@ nsSVGGradientFrame::GetGradientUnits()
{
// This getter is called every time the others are called - maybe cache it?
nsIContent *gradient = GetGradientWithAttr(nsGkAtoms::gradientUnits);
if (!gradient)
gradient = mContent; // use our gradient to get the correct default value
nsSVGGradientElement *gradElement = static_cast<nsSVGGradientElement*>
(gradient);
return gradElement->mEnumAttributes[nsSVGGradientElement::GRADIENTUNITS].GetAnimValue();
nsSVGGradientElement *element =
GetGradientWithAttr(nsGkAtoms::gradientUnits, mContent);
return element->mEnumAttributes[nsSVGGradientElement::GRADIENTUNITS].GetAnimValue();
}
// -------------------------------------------------------------------------
@ -558,9 +452,7 @@ nsSVGLinearGradientFrame::AttributeChanged(PRInt32 aNameSpaceID,
aAttribute == nsGkAtoms::y1 ||
aAttribute == nsGkAtoms::x2 ||
aAttribute == nsGkAtoms::y2)) {
WillModify();
DidModify();
return NS_OK;
nsSVGEffects::InvalidateRenderingObservers(this);
}
return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
@ -573,12 +465,8 @@ float
nsSVGLinearGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
PRUint16 aEnumName)
{
nsIContent *gradient = GetLinearGradientWithAttr(aAtomName);
if (!gradient)
gradient = mContent; // use our gradient to get the correct default value
nsSVGLinearGradientElement *element =
static_cast<nsSVGLinearGradientElement*>(gradient);
GetLinearGradientWithAttr(aAtomName, mContent);
// Object bounding box units are handled by setting the appropriate
// transform in GetGradientTransform, but we need to handle user
@ -633,9 +521,7 @@ nsSVGRadialGradientFrame::AttributeChanged(PRInt32 aNameSpaceID,
aAttribute == nsGkAtoms::cy ||
aAttribute == nsGkAtoms::fx ||
aAttribute == nsGkAtoms::fy)) {
WillModify();
DidModify();
return NS_OK;
nsSVGEffects::InvalidateRenderingObservers(this);
}
return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
@ -647,21 +533,16 @@ nsSVGRadialGradientFrame::AttributeChanged(PRInt32 aNameSpaceID,
float
nsSVGRadialGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
PRUint16 aEnumName,
nsIContent *aElement)
nsSVGRadialGradientElement *aElement)
{
nsIContent *gradient;
nsSVGRadialGradientElement *element;
if (aElement) {
gradient = aElement;
element = aElement;
} else {
gradient = GetRadialGradientWithAttr(aAtomName);
if (!gradient)
gradient = mContent; // use our gradient to get the correct default value
element = GetRadialGradientWithAttr(aAtomName, mContent);
}
nsSVGRadialGradientElement *element =
static_cast<nsSVGRadialGradientElement*>(gradient);
// Object bounding box units are handled by setting the appropriate
// transform in GetGradientTransform, but we need to handle user
// space units as part of the individual Get* routines. Fixes 323669.
@ -688,14 +569,14 @@ nsSVGRadialGradientFrame::CreateGradient()
cy = GradientLookupAttribute(nsGkAtoms::cy, nsSVGRadialGradientElement::CY);
r = GradientLookupAttribute(nsGkAtoms::r, nsSVGRadialGradientElement::R);
nsIContent *gradient;
nsSVGRadialGradientElement *gradient;
if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fx)))
if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fx, nsnull)))
fx = cx; // if fx isn't set, we must use cx
else
fx = GradientLookupAttribute(nsGkAtoms::fx, nsSVGRadialGradientElement::FX, gradient);
if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fy)))
if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fy, nsnull)))
fy = cy; // if fy isn't set, we must use cy
else
fy = GradientLookupAttribute(nsGkAtoms::fy, nsSVGRadialGradientElement::FY, gradient);
@ -728,7 +609,7 @@ nsSVGRadialGradientFrame::CreateGradient()
// Public functions
// -------------------------------------------------------------------------
nsIFrame*
nsIFrame*
NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell,
nsIContent* aContent,
nsStyleContext* aContext)
@ -738,7 +619,7 @@ NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell,
NS_ERROR("Can't create frame! Content is not an SVG linearGradient");
return nsnull;
}
nsCOMPtr<nsIDOMSVGURIReference> aRef = do_QueryInterface(aContent);
NS_ASSERTION(aRef, "NS_NewSVGLinearGradientFrame -- Content doesn't support nsIDOMSVGURIReference");
@ -755,7 +636,7 @@ NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell,
NS_ERROR("Can't create frame! Content is not an SVG radialGradient");
return nsnull;
}
nsCOMPtr<nsIDOMSVGURIReference> aRef = do_QueryInterface(aContent);
NS_ASSERTION(aRef, "NS_NewSVGRadialGradientFrame -- Content doesn't support nsIDOMSVGURIReference");

View File

@ -48,42 +48,26 @@
class nsIDOMSVGStopElement;
typedef nsSVGPaintServerFrame nsSVGGradientFrameBase;
typedef nsSVGPaintServerFrame nsSVGGradientFrameBase;
class nsSVGGradientFrame : public nsSVGGradientFrameBase,
public nsISVGValueObserver
/**
* Gradients can refer to other gradients. We create an nsSVGPaintingProperty
* with property type nsGkAtoms::href to track the referenced gradient.
*/
class nsSVGGradientFrame : public nsSVGGradientFrameBase
{
protected:
nsSVGGradientFrame(nsStyleContext* aContext,
nsIDOMSVGURIReference *aRef);
virtual ~nsSVGGradientFrame();
public:
// nsSVGPaintServerFrame methods:
virtual PRBool SetupPaintServer(gfxContext *aContext,
nsSVGGeometryFrame *aSource,
float aGraphicOpacity);
// nsISupports interface:
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
private:
NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }
NS_IMETHOD_(nsrefcnt) Release() { return 1; }
public:
// nsISVGValueObserver interface:
NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType);
NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType);
// nsIFrame interface:
NS_IMETHOD DidSetStyleContext();
NS_IMETHOD RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame);
virtual nsIAtom* GetType() const; // frame type: nsGkAtoms::svgGradientFrame
NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
@ -102,26 +86,24 @@ public:
{
return NS_OK; // override - our frames don't directly render
}
private:
// Helper methods to aid gradient implementation
// ---------------------------------------------
// The SVG specification allows gradient elements to reference another
// gradient element to "inherit" its attributes or gradient stops. Reference
// chains of arbitrary length are allowed, and loop checking is essential!
// Use the following helpers to safely get attributes and stops.
// Parse our xlink:href and set mNextGrad if we reference another gradient.
void GetRefedGradientFromHref();
// Parse our xlink:href and set up our nsSVGPaintingProperty if we
// reference another gradient and we don't have a property. Return
// the referenced gradient's frame if available, null otherwise.
nsSVGGradientFrame* GetReferencedGradient();
// Helpers to look at our gradient and then along its reference chain (if any)
// to find the first gradient with the specified attribute.
nsIContent* GetGradientWithAttr(nsIAtom *aAttrName);
// Returns aDefault if no content with that attribute is found
nsSVGGradientElement* GetGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault);
// Some attributes are only valid on one type of gradient, and we *must* get
// the right type or we won't have the data structures we require.
nsIContent* GetGradientWithAttr(nsIAtom *aAttrName, nsIAtom *aGradType);
// Returns aDefault if no content with that attribute is found
nsSVGGradientElement* GetGradientWithAttr(nsIAtom *aAttrName, nsIAtom *aGradType,
nsIContent *aDefault);
// Optionally get a stop frame (returns stop index/count)
PRInt32 GetStopFrame(PRInt32 aIndex, nsIFrame * *aStopFrame);
@ -136,28 +118,15 @@ protected:
virtual already_AddRefed<gfxPattern> CreateGradient() = 0;
// Use these inline methods instead of GetGradientWithAttr(..., aGradType)
nsIContent* GetLinearGradientWithAttr(nsIAtom *aAttrName)
nsSVGLinearGradientElement* GetLinearGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
{
return GetGradientWithAttr(aAttrName, nsGkAtoms::svgLinearGradientFrame);
return static_cast<nsSVGLinearGradientElement*>(
GetGradientWithAttr(aAttrName, nsGkAtoms::svgLinearGradientFrame, aDefault));
}
nsIContent* GetRadialGradientWithAttr(nsIAtom *aAttrName)
nsSVGRadialGradientElement* GetRadialGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
{
return GetGradientWithAttr(aAttrName, nsGkAtoms::svgRadialGradientFrame);
}
// We must loop check notifications too: see bug 330387 comment 18 + testcase
// and comment 19. The mLoopFlag check is in Will/DidModifySVGObservable.
void WillModify(modificationType aModType = mod_other)
{
mLoopFlag = PR_TRUE;
nsSVGValue::WillModify(aModType);
mLoopFlag = PR_FALSE;
}
void DidModify(modificationType aModType = mod_other)
{
mLoopFlag = PR_TRUE;
nsSVGValue::DidModify(aModType);
mLoopFlag = PR_FALSE;
return static_cast<nsSVGRadialGradientElement*>(
GetGradientWithAttr(aAttrName, nsGkAtoms::svgRadialGradientFrame, aDefault));
}
// Get the value of our gradientUnits attribute
@ -168,22 +137,16 @@ protected:
private:
// href of the other gradient we reference (if any)
// XXX this should go away, we can watch our content directly
nsCOMPtr<nsIDOMSVGAnimatedString> mHref;
// Frame of the gradient we reference (if any). Do NOT use this directly.
// Use Get[Xxx]GradientWithAttr instead to ensure proper loop checking.
nsSVGGradientFrame *mNextGrad;
// Flag to mark this frame as "in use" during recursive calls along our
// gradient's reference chain so we can detect reference loops. See:
// http://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementHrefAttribute
PRPackedBool mLoopFlag;
// Ideally we'd set mNextGrad by implementing Init(), but the frame of the
// gradient we reference isn't available at that stage. Our only option is to
// set mNextGrad lazily in GetGradientWithAttr, and to make that efficient
// we need this flag. Our class size is the same since it just fills padding.
PRPackedBool mInitialized;
// Gradients often don't reference other gradients, so here we cache
// the fact that that isn't happening.
PRPackedBool mNoHRefURI;
};
@ -195,7 +158,7 @@ typedef nsSVGGradientFrame nsSVGLinearGradientFrameBase;
class nsSVGLinearGradientFrame : public nsSVGLinearGradientFrameBase
{
friend nsIFrame* NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell,
friend nsIFrame* NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell,
nsIContent* aContent,
nsStyleContext* aContext);
protected:
@ -232,7 +195,7 @@ typedef nsSVGGradientFrame nsSVGRadialGradientFrameBase;
class nsSVGRadialGradientFrame : public nsSVGRadialGradientFrameBase
{
friend nsIFrame* NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell,
friend nsIFrame* NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell,
nsIContent* aContent,
nsStyleContext* aContext);
protected:
@ -258,7 +221,7 @@ public:
protected:
float GradientLookupAttribute(nsIAtom *aAtomName, PRUint16 aEnumName,
nsIContent *aElement = nsnull);
nsSVGRadialGradientElement *aElement = nsnull);
virtual already_AddRefed<gfxPattern> CreateGradient();
};

View File

@ -44,6 +44,9 @@
#include "nsDisplayList.h"
#include "nsSVGMatrix.h"
#include "nsSVGFilterPaintCallback.h"
#include "nsSVGFilterFrame.h"
#include "nsSVGClipPathFrame.h"
#include "nsSVGMaskFrame.h"
// ----------------------------------------------------------------------
@ -106,13 +109,12 @@ nsRect
nsSVGIntegrationUtils::ComputeFrameEffectsRect(nsIFrame* aFrame,
const nsRect& aOverflowRect)
{
PRBool isOK;
nsIFrame* firstFrame =
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
nsSVGEffects::EffectProperties effectProperties =
nsSVGEffects::GetEffectProperties(firstFrame);
nsSVGFilterFrame *filterFrame = effectProperties.mFilter ?
effectProperties.mFilter->GetFilterFrame(&isOK) : nsnull;
effectProperties.mFilter->GetFilterFrame() : nsnull;
if (!filterFrame)
return aOverflowRect;
@ -270,12 +272,9 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsIRenderingContext* aCtx,
*/
PRBool isOK = PR_TRUE;
nsSVGClipPathFrame *clipPathFrame = effectProperties.mClipPath ?
effectProperties.mClipPath->GetClipPathFrame(&isOK) : nsnull;
nsSVGFilterFrame *filterFrame = effectProperties.mFilter ?
effectProperties.mFilter->GetFilterFrame(&isOK) : nsnull;
nsSVGMaskFrame *maskFrame = effectProperties.mMask ?
effectProperties.mMask->GetMaskFrame(&isOK) : nsnull;
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK);
nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK);
PRBool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : PR_TRUE;

View File

@ -35,6 +35,7 @@
* ***** END LICENSE BLOCK ***** */
#include "nsFrame.h"
#include "nsSVGEffects.h"
class nsSVGLeafFrame : public nsFrame
{
@ -56,6 +57,7 @@ public:
}
#endif
NS_IMETHOD DidSetStyleContext();
};
nsIFrame*
@ -63,3 +65,11 @@ NS_NewSVGLeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
return new (aPresShell) nsSVGLeafFrame(aContext);
}
NS_IMETHODIMP
nsSVGLeafFrame::DidSetStyleContext()
{
nsresult rv = nsFrame::DidSetStyleContext();
nsSVGEffects::InvalidateRenderingObservers(this);
return rv;
}

View File

@ -35,7 +35,3 @@
* ***** END LICENSE BLOCK ***** */
#include "nsSVGPaintServerFrame.h"
NS_INTERFACE_MAP_BEGIN(nsSVGPaintServerFrame)
NS_INTERFACE_MAP_ENTRY(nsISVGValue)
NS_INTERFACE_MAP_END_INHERITING(nsSVGPaintServerFrameBase)

View File

@ -38,15 +38,13 @@
#define __NS_SVGPAINTSERVERFRAME_H__
#include "nsSVGContainerFrame.h"
#include "nsSVGValue.h"
class gfxContext;
class nsSVGGeometryFrame;
typedef nsSVGContainerFrame nsSVGPaintServerFrameBase;
class nsSVGPaintServerFrame : public nsSVGPaintServerFrameBase,
public nsSVGValue
class nsSVGPaintServerFrame : public nsSVGPaintServerFrameBase
{
protected:
nsSVGPaintServerFrame(nsStyleContext* aContext) :
@ -60,12 +58,6 @@ public:
virtual PRBool SetupPaintServer(gfxContext *aContext,
nsSVGGeometryFrame *aSource,
float aOpacity) = 0;
// nsISupports interface:
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
// nsISVGValue interface:
NS_IMETHOD SetValueString(const nsAString &aValue) { return NS_OK; }
NS_IMETHOD GetValueString(nsAString& aValue) { return NS_ERROR_NOT_IMPLEMENTED; }
};
#endif // __NS_SVGPAINTSERVERFRAME_H__

View File

@ -363,8 +363,8 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint)
if (mask & HITTEST_MASK_FILL)
isHit = context.PointInFill(userSpacePoint);
if (!isHit && (mask & HITTEST_MASK_STROKE)) {
SetupCairoStrokeHitGeometry(&context);
if (!isHit && (mask & HITTEST_MASK_STROKE) &&
SetupCairoStrokeHitGeometry(&context)) {
isHit = context.PointInStroke(userSpacePoint);
}
@ -431,8 +431,7 @@ nsSVGPathGeometryFrame::UpdateCoveredRegion()
gfxRect extent;
if (HasStroke()) {
SetupCairoStrokeGeometry(&context);
if (SetupCairoStrokeGeometry(&context)) {
extent = context.GetUserStrokeExtent();
if (!IsDegeneratePath(extent)) {
extent = context.UserToDevice(extent);
@ -653,11 +652,11 @@ nsSVGPathGeometryFrame::Render(nsSVGRenderState *aContext)
break;
}
if (HasFill() && SetupCairoFill(gfx)) {
if (SetupCairoFill(gfx)) {
gfx->Fill();
}
if (HasStroke() && SetupCairoStroke(gfx)) {
if (SetupCairoStroke(gfx)) {
gfx->Stroke();
}

View File

@ -48,6 +48,7 @@
#include "nsSVGMatrix.h"
#include "nsSVGRect.h"
#include "nsSVGUtils.h"
#include "nsSVGEffects.h"
#include "nsSVGOuterSVGFrame.h"
#include "nsSVGPatternElement.h"
#include "nsSVGGeometryFrame.h"
@ -68,8 +69,8 @@ static void printRect(char *msg, nsIDOMSVGRect *aRect);
nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext,
nsIDOMSVGURIReference *aRef) :
nsSVGPatternFrameBase(aContext),
mNextPattern(nsnull),
mLoopFlag(PR_FALSE)
mLoopFlag(PR_FALSE), mPaintLoopFlag(PR_FALSE),
mNoHRefURI(PR_FALSE)
{
if (aRef) {
// Get the hRef
@ -77,61 +78,14 @@ nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext,
}
}
nsSVGPatternFrame::~nsSVGPatternFrame()
{
WillModify(mod_die);
if (mNextPattern)
mNextPattern->RemoveObserver(this);
// Notify the world that we're dying
DidModify(mod_die);
}
//----------------------------------------------------------------------
// nsISupports methods:
NS_INTERFACE_MAP_BEGIN(nsSVGPatternFrame)
NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END_INHERITING(nsSVGPatternFrameBase)
//----------------------------------------------------------------------
// nsISVGValueObserver methods:
NS_IMETHODIMP
nsSVGPatternFrame::WillModifySVGObservable(nsISVGValue* observable,
modificationType aModType)
{
WillModify(aModType);
return NS_OK;
}
NS_IMETHODIMP
nsSVGPatternFrame::DidModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType)
{
nsIFrame *pattern = nsnull;
CallQueryInterface(observable, &pattern);
// Is this a pattern we are observing that is going away?
if (mNextPattern && aModType == nsISVGValue::mod_die && pattern) {
// Yes, we need to handle this differently
if (mNextPattern == pattern) {
mNextPattern = nsnull;
}
}
// Something we depend on was modified -- pass it on!
DidModify(aModType);
return NS_OK;
}
//----------------------------------------------------------------------
// nsIFrame methods:
NS_IMETHODIMP
nsSVGPatternFrame::DidSetStyleContext()
{
WillModify();
DidModify();
return NS_OK;
nsSVGEffects::InvalidateRenderingObservers(this);
return nsSVGPatternFrameBase::DidSetStyleContext();
}
NS_IMETHODIMP
@ -149,19 +103,16 @@ nsSVGPatternFrame::AttributeChanged(PRInt32 aNameSpaceID,
aAttribute == nsGkAtoms::height ||
aAttribute == nsGkAtoms::preserveAspectRatio ||
aAttribute == nsGkAtoms::viewBox)) {
WillModify();
DidModify();
return NS_OK;
}
nsSVGEffects::InvalidateRenderingObservers(this);
}
if (aNameSpaceID == kNameSpaceID_XLink &&
aAttribute == nsGkAtoms::href) {
if (mNextPattern)
mNextPattern->RemoveObserver(this);
mNextPattern = nsnull;
WillModify();
DidModify();
return NS_OK;
// Blow away our reference, if any
DeleteProperty(nsGkAtoms::href);
mNoHRefURI = PR_FALSE;
// And update whoever references us
nsSVGEffects::InvalidateRenderingObservers(this);
}
return nsSVGPatternFrameBase::AttributeChanged(aNameSpaceID,
@ -181,11 +132,11 @@ nsSVGPatternFrame::GetType() const
// need to return *our current* transformation
// matrix, which depends on our units parameters
// and X, Y, Width, and Height
already_AddRefed<nsIDOMSVGMatrix>
already_AddRefed<nsIDOMSVGMatrix>
nsSVGPatternFrame::GetCanvasTM()
{
nsIDOMSVGMatrix *rCTM;
if (mCTM) {
rCTM = mCTM;
NS_IF_ADDREF(rCTM);
@ -200,7 +151,7 @@ nsSVGPatternFrame::GetCanvasTM()
NS_NewSVGMatrix(&rCTM);
}
}
return rCTM;
return rCTM;
}
nsresult
@ -212,7 +163,7 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
/*
* General approach:
* Set the content geometry stuff
* Calculate our bbox (using x,y,width,height & patternUnits &
* Calculate our bbox (using x,y,width,height & patternUnits &
* patternTransform)
* Create the surface
* Calculate the content transformation matrix
@ -341,10 +292,17 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
// Set our geometrical parent
mSource = aSource;
for (nsIFrame* kid = firstKid; kid;
kid = kid->GetNextSibling()) {
nsSVGUtils::PaintChildWithEffects(&tmpState, nsnull, kid);
// Delay checking mPaintLoopFlag until here so we can give back a clear
// surface if there's a loop
if (!mPaintLoopFlag) {
mPaintLoopFlag = PR_TRUE;
for (nsIFrame* kid = firstKid; kid;
kid = kid->GetNextSibling()) {
nsSVGUtils::PaintChildWithEffects(&tmpState, nsnull, kid);
}
mPaintLoopFlag = PR_FALSE;
}
mSource = nsnull;
if (aGraphicOpacity != 1.0f) {
@ -365,16 +323,21 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
NS_IMETHODIMP
nsSVGPatternFrame::GetPatternFirstChild(nsIFrame **kid)
{
nsresult rv = NS_OK;
// Do we have any children ourselves?
if (!(*kid = mFrames.FirstChild())) {
// No, see if we chain to someone who does
if (checkURITarget())
rv = mNextPattern->GetPatternFirstChild(kid);
else
rv = NS_ERROR_FAILURE; // No children = error
*kid = mFrames.FirstChild();
if (*kid)
return NS_OK;
// No, see if we chain to someone who does
nsSVGPatternFrame *next = GetReferencedPattern();
mLoopFlag = PR_TRUE;
if (!next || next->mLoopFlag) {
mLoopFlag = PR_FALSE;
return NS_ERROR_FAILURE;
}
nsresult rv = next->GetPatternFirstChild(kid);
mLoopFlag = PR_FALSE;
return rv;
}
@ -382,246 +345,157 @@ nsSVGPatternFrame::GetPatternFirstChild(nsIFrame **kid)
PRUint16
nsSVGPatternFrame::GetPatternUnits()
{
PRUint16 rv;
// See if we need to get the value from another pattern
if (!checkURITarget(nsGkAtoms::patternUnits)) {
// No, return the values
nsSVGPatternElement *patternElement = static_cast<nsSVGPatternElement*>
(mContent);
rv = patternElement->mEnumAttributes[nsSVGPatternElement::PATTERNUNITS].GetAnimValue();
} else {
// Yes, get it from the target
rv = mNextPattern->GetPatternUnits();
}
mLoopFlag = PR_FALSE;
return rv;
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::patternUnits, mContent);
return patternElement->mEnumAttributes[nsSVGPatternElement::PATTERNUNITS].GetAnimValue();
}
PRUint16
nsSVGPatternFrame::GetPatternContentUnits()
{
PRUint16 rv;
// See if we need to get the value from another pattern
if (!checkURITarget(nsGkAtoms::patternContentUnits)) {
// No, return the values
nsSVGPatternElement *patternElement = static_cast<nsSVGPatternElement*>
(mContent);
rv = patternElement->mEnumAttributes[nsSVGPatternElement::PATTERNCONTENTUNITS].GetAnimValue();
} else {
// Yes, get it from the target
rv = mNextPattern->GetPatternContentUnits();
}
mLoopFlag = PR_FALSE;
return rv;
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::patternContentUnits, mContent);
return patternElement->mEnumAttributes[nsSVGPatternElement::PATTERNCONTENTUNITS].GetAnimValue();
}
gfxMatrix
nsSVGPatternFrame::GetPatternTransform()
{
gfxMatrix matrix;
// See if we need to get the value from another pattern
if (!checkURITarget(nsGkAtoms::patternTransform)) {
// No, return the values
nsSVGPatternElement *patternElement = static_cast<nsSVGPatternElement*>
(mContent);
nsCOMPtr<nsIDOMSVGTransformList> lTrans;
patternElement->mPatternTransform->GetAnimVal(getter_AddRefs(lTrans));
nsCOMPtr<nsIDOMSVGMatrix> patternTransform =
nsSVGTransformList::GetConsolidationMatrix(lTrans);
if (patternTransform) {
matrix = nsSVGUtils::ConvertSVGMatrixToThebes(patternTransform);
}
} else {
// Yes, get it from the target
matrix = mNextPattern->GetPatternTransform();
}
mLoopFlag = PR_FALSE;
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::patternTransform, mContent);
gfxMatrix matrix;
nsCOMPtr<nsIDOMSVGTransformList> lTrans;
patternElement->mPatternTransform->GetAnimVal(getter_AddRefs(lTrans));
nsCOMPtr<nsIDOMSVGMatrix> patternTransform =
nsSVGTransformList::GetConsolidationMatrix(lTrans);
if (patternTransform) {
matrix = nsSVGUtils::ConvertSVGMatrixToThebes(patternTransform);
}
return matrix;
}
NS_IMETHODIMP
nsSVGPatternFrame::GetViewBox(nsIDOMSVGRect **aViewBox)
{
// See if we need to get the value from another pattern
if (!checkURITarget(nsGkAtoms::viewBox)) {
// No, return the values
nsCOMPtr<nsIDOMSVGFitToViewBox> patternElement =
do_QueryInterface(mContent);
nsCOMPtr<nsIDOMSVGAnimatedRect> viewBox;
patternElement->GetViewBox(getter_AddRefs(viewBox));
viewBox->GetAnimVal(aViewBox);
} else {
// Yes, get it from the target
mNextPattern->GetViewBox(aViewBox);
}
mLoopFlag = PR_FALSE;
return NS_OK;
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::viewBox, mContent);
nsCOMPtr<nsIDOMSVGAnimatedRect> viewBox;
patternElement->GetViewBox(getter_AddRefs(viewBox));
return viewBox->GetAnimVal(aViewBox);
}
NS_IMETHODIMP
nsSVGPatternFrame::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
nsSVGPatternFrame::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
**aPreserveAspectRatio)
{
// See if we need to get the value from another pattern
if (!checkURITarget(nsGkAtoms::preserveAspectRatio)) {
// No, return the values
nsCOMPtr<nsIDOMSVGFitToViewBox> patternElement =
do_QueryInterface(mContent);
patternElement->GetPreserveAspectRatio(aPreserveAspectRatio);
} else {
// Yes, get it from the target
mNextPattern->GetPreserveAspectRatio(aPreserveAspectRatio);
}
mLoopFlag = PR_FALSE;
return NS_OK;
nsSVGPatternElement *patternElement =
GetPatternWithAttr(nsGkAtoms::preserveAspectRatio, mContent);
return patternElement->GetPreserveAspectRatio(aPreserveAspectRatio);
}
nsSVGLength2 *
nsSVGPatternFrame::GetX()
{
nsSVGLength2 *rv = nsnull;
// See if we need to get the value from another pattern
if (checkURITarget(nsGkAtoms::x)) {
// Yes, get it from the target
rv = mNextPattern->GetX();
} else {
// No, return the values
nsSVGPatternElement *pattern =
static_cast<nsSVGPatternElement*>(mContent);
rv = &pattern->mLengthAttributes[nsSVGPatternElement::X];
}
mLoopFlag = PR_FALSE;
return rv;
nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::x, mContent);
return &pattern->mLengthAttributes[nsSVGPatternElement::X];
}
nsSVGLength2 *
nsSVGPatternFrame::GetY()
{
nsSVGLength2 *rv = nsnull;
// See if we need to get the value from another pattern
if (checkURITarget(nsGkAtoms::y)) {
// Yes, get it from the target
rv = mNextPattern->GetY();
} else {
// No, return the values
nsSVGPatternElement *pattern =
static_cast<nsSVGPatternElement*>(mContent);
rv = &pattern->mLengthAttributes[nsSVGPatternElement::Y];
}
mLoopFlag = PR_FALSE;
return rv;
nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::y, mContent);
return &pattern->mLengthAttributes[nsSVGPatternElement::Y];
}
nsSVGLength2 *
nsSVGPatternFrame::GetWidth()
{
nsSVGLength2 *rv = nsnull;
// See if we need to get the value from another pattern
if (checkURITarget(nsGkAtoms::width)) {
// Yes, get it from the target
rv = mNextPattern->GetWidth();
} else {
// No, return the values
nsSVGPatternElement *pattern =
static_cast<nsSVGPatternElement*>(mContent);
rv = &pattern->mLengthAttributes[nsSVGPatternElement::WIDTH];
}
mLoopFlag = PR_FALSE;
return rv;
nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::width, mContent);
return &pattern->mLengthAttributes[nsSVGPatternElement::WIDTH];
}
nsSVGLength2 *
nsSVGPatternFrame::GetHeight()
{
nsSVGLength2 *rv = nsnull;
// See if we need to get the value from another pattern
if (checkURITarget(nsGkAtoms::height)) {
// Yes, get it from the target
rv = mNextPattern->GetHeight();
} else {
// No, return the values
nsSVGPatternElement *pattern =
static_cast<nsSVGPatternElement*>(mContent);
rv = &pattern->mLengthAttributes[nsSVGPatternElement::HEIGHT];
}
mLoopFlag = PR_FALSE;
return rv;
nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::height, mContent);
return &pattern->mLengthAttributes[nsSVGPatternElement::HEIGHT];
}
// Private (helper) methods
PRBool
nsSVGPatternFrame::checkURITarget(nsIAtom *attr) {
// Was the attribute explicitly set?
if (mContent->HasAttr(kNameSpaceID_None, attr)) {
// Yes, just return
return PR_FALSE;
nsSVGPatternFrame *
nsSVGPatternFrame::GetReferencedPattern()
{
if (mNoHRefURI)
return nsnull;
nsSVGPaintingProperty *property =
static_cast<nsSVGPaintingProperty*>(GetProperty(nsGkAtoms::href));
if (!property) {
// Fetch our pattern element's xlink:href attribute
nsAutoString href;
mHref->GetAnimVal(href);
if (href.IsEmpty()) {
mNoHRefURI = PR_TRUE;
return nsnull; // no URL
}
// Convert href to an nsIURI
nsCOMPtr<nsIURI> targetURI;
nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
mContent->GetCurrentDoc(), base);
property = nsSVGEffects::GetPaintingProperty(targetURI, this, nsGkAtoms::href);
if (!property)
return nsnull;
}
return checkURITarget();
nsIFrame *result = property->GetReferencedFrame();
if (!result)
return nsnull;
nsIAtom* frameType = result->GetType();
if (frameType != nsGkAtoms::svgPatternFrame)
return nsnull;
return static_cast<nsSVGPatternFrame*>(result);
}
PRBool
nsSVGPatternFrame::checkURITarget(void) {
nsIFrame *nextPattern;
mLoopFlag = PR_TRUE; // Set our loop detection flag
// Have we already figured out the next Pattern?
if (mNextPattern != nsnull) {
return PR_TRUE;
}
nsSVGPatternElement *
nsSVGPatternFrame::GetPatternWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
{
if (mContent->HasAttr(kNameSpaceID_None, aAttrName))
return static_cast<nsSVGPatternElement *>(mContent);
// check if we reference another pattern to "inherit" its children
// or attributes
nsAutoString href;
mHref->GetAnimVal(href);
// Do we have URI?
if (href.IsEmpty()) {
return PR_FALSE; // No, return the default
}
nsSVGPatternElement *pattern = static_cast<nsSVGPatternElement *>(aDefault);
nsCOMPtr<nsIURI> targetURI;
nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI),
href, mContent->GetCurrentDoc(), base);
nsSVGPatternFrame *next = GetReferencedPattern();
if (!next)
return pattern;
// Note that we are using *our* frame tree for this call,
// otherwise we're going to have to get the PresShell in each call
if (NS_SUCCEEDED(
nsSVGUtils::GetReferencedFrame(&nextPattern, targetURI,
mContent,
PresContext()->PresShell()))) {
nsIAtom* frameType = nextPattern->GetType();
if (frameType != nsGkAtoms::svgPatternFrame)
return PR_FALSE;
mNextPattern = (nsSVGPatternFrame *)nextPattern;
// Are we looping?
if (mNextPattern->mLoopFlag) {
// Yes, remove the reference and return an error
NS_WARNING("Pattern loop detected!");
mNextPattern = nsnull;
return PR_FALSE;
}
// Add ourselves to the observer list
if (mNextPattern) {
// Can't use the NS_ADD macro here because of nsISupports ambiguity
mNextPattern->AddObserver(this);
}
return PR_TRUE;
}
return PR_FALSE;
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
mLoopFlag = PR_TRUE;
// XXXjwatt: we should really send an error to the JavaScript Console here:
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
"while inheriting attribute!");
if (!next->mLoopFlag)
pattern = next->GetPatternWithAttr(aAttrName, aDefault);
mLoopFlag = PR_FALSE;
return pattern;
}
// -------------------------------------------------------------------------
// Helper functions
// -------------------------------------------------------------------------
nsresult
nsSVGPatternFrame::GetPatternRect(nsIDOMSVGRect **patternRect,
nsresult
nsSVGPatternFrame::GetPatternRect(nsIDOMSVGRect **patternRect,
nsIDOMSVGRect *bbox,
nsIDOMSVGMatrix *callerCTM,
nsSVGElement *content)
@ -677,7 +551,7 @@ nsSVGPatternFrame::ConstructCTM(nsIDOMSVGMatrix **aCTM,
float width, height;
callerBBox->GetWidth(&width);
callerBBox->GetHeight(&height);
NS_NewSVGMatrix(getter_AddRefs(tCTM), width, 0.0f, 0.0f,
NS_NewSVGMatrix(getter_AddRefs(tCTM), width, 0.0f, 0.0f,
height, 0.0f, 0.0f);
} else {
float scale = nsSVGUtils::MaxExpansion(callerCTM);
@ -748,7 +622,7 @@ nsSVGPatternFrame::GetPatternMatrix(nsIDOMSVGRect *bbox,
}
nsresult
nsSVGPatternFrame::GetCallerGeometry(nsIDOMSVGMatrix **aCTM,
nsSVGPatternFrame::GetCallerGeometry(nsIDOMSVGMatrix **aCTM,
nsIDOMSVGRect **aBBox,
nsSVGElement **aContent,
nsSVGGeometryFrame *aSource)
@ -781,7 +655,7 @@ nsSVGPatternFrame::GetCallerGeometry(nsIDOMSVGMatrix **aCTM,
CallQueryInterface(aSource, &callerSVGFrame);
callerSVGFrame->SetMatrixPropagation(PR_FALSE);
callerSVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
callerSVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
nsISVGChildFrame::TRANSFORM_CHANGED );
callerSVGFrame->GetBBox(aBBox);
callerSVGFrame->SetMatrixPropagation(PR_TRUE);
@ -888,7 +762,7 @@ nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell,
}
nsCOMPtr<nsIDOMSVGURIReference> ref = do_QueryInterface(aContent);
NS_ASSERTION(ref,
NS_ASSERTION(ref,
"NS_NewSVGPatternFrame -- Content doesn't support nsIDOMSVGURIReference");
#ifdef DEBUG_scooter
@ -907,11 +781,11 @@ static void printCTM(char *msg, gfxMatrix aCTM)
static void printCTM(char *msg, nsIDOMSVGMatrix *aCTM)
{
float a,b,c,d,e,f;
aCTM->GetA(&a);
aCTM->GetB(&b);
aCTM->GetA(&a);
aCTM->GetB(&b);
aCTM->GetC(&c);
aCTM->GetD(&d);
aCTM->GetE(&e);
aCTM->GetD(&d);
aCTM->GetE(&e);
aCTM->GetF(&f);
printf("%s {%f,%f,%f,%f,%f,%f}\n",msg,a,b,c,d,e,f);
}
@ -919,10 +793,10 @@ static void printCTM(char *msg, nsIDOMSVGMatrix *aCTM)
static void printRect(char *msg, nsIDOMSVGRect *aRect)
{
float x,y,width,height;
aRect->GetX(&x);
aRect->GetY(&y);
aRect->GetWidth(&width);
aRect->GetHeight(&height);
aRect->GetX(&x);
aRect->GetY(&y);
aRect->GetWidth(&width);
aRect->GetHeight(&height);
printf("%s {%f,%f,%f,%f}\n",msg,x,y,width,height);
}
#endif

View File

@ -39,8 +39,6 @@
#ifndef __NS_SVGPATTERNFRAME_H__
#define __NS_SVGPATTERNFRAME_H__
#include "nsISVGValueObserver.h"
#include "nsWeakReference.h"
#include "nsIDOMSVGAnimatedString.h"
#include "nsIDOMSVGMatrix.h"
#include "nsSVGPaintServerFrame.h"
@ -55,11 +53,14 @@ class gfxASurface;
typedef nsSVGPaintServerFrame nsSVGPatternFrameBase;
class nsSVGPatternFrame : public nsSVGPatternFrameBase,
public nsISVGValueObserver
/**
* Patterns can refer to other patterns. We create an nsSVGPaintingProperty
* with property type nsGkAtoms::href to track the referenced pattern.
*/
class nsSVGPatternFrame : public nsSVGPatternFrameBase
{
public:
friend nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell,
friend nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell,
nsIContent* aContent,
nsStyleContext* aContext);
@ -75,19 +76,7 @@ public:
nsSVGGeometryFrame *aSource,
float aGraphicOpacity);
// nsISupports interface:
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
private:
NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }
NS_IMETHOD_(nsrefcnt) Release() { return 1; }
public:
// nsISVGValueObserver interface:
NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType);
NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable,
nsISVGValue::modificationType aModType);
// nsSVGContainerFrame methods:
virtual already_AddRefed<nsIDOMSVGMatrix> GetCanvasTM();
@ -117,11 +106,13 @@ protected:
nsSVGPatternFrame(nsStyleContext* aContext,
nsIDOMSVGURIReference *aRef);
virtual ~nsSVGPatternFrame();
// Internal methods for handling referenced patterns
PRBool checkURITarget(nsIAtom *);
PRBool checkURITarget();
nsSVGPatternFrame* GetReferencedPattern();
// Helper to look at our pattern and then along its reference chain (if any)
// to find the first pattern with the specified attribute. Returns
// null if there isn't one.
nsSVGPatternElement* GetPatternWithAttr(nsIAtom *aAttrName, nsIContent *aDefault);
//
nsSVGLength2 *GetX();
nsSVGLength2 *GetY();
@ -132,7 +123,7 @@ protected:
PRUint16 GetPatternContentUnits();
gfxMatrix GetPatternTransform();
NS_IMETHOD GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
NS_IMETHOD GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
**aPreserveAspectRatio);
NS_IMETHOD GetPatternFirstChild(nsIFrame **kid);
NS_IMETHOD GetViewBox(nsIDOMSVGRect * *aMatrix);
@ -146,23 +137,26 @@ protected:
nsresult ConstructCTM(nsIDOMSVGMatrix **ctm,
nsIDOMSVGRect *callerBBox,
nsIDOMSVGMatrix *callerCTM);
nsresult GetCallerGeometry(nsIDOMSVGMatrix **aCTM,
nsresult GetCallerGeometry(nsIDOMSVGMatrix **aCTM,
nsIDOMSVGRect **aBBox,
nsSVGElement **aContent,
nsSVGElement **aContent,
nsSVGGeometryFrame *aSource);
private:
// this is a *temporary* reference to the frame of the element currently
// referencing our pattern. This must be temporary because different
// referencing frames will all reference this one frame
nsSVGGeometryFrame *mSource;
nsCOMPtr<nsIDOMSVGMatrix> mCTM;
nsSVGGeometryFrame *mSource;
nsCOMPtr<nsIDOMSVGMatrix> mCTM;
protected:
nsSVGPatternFrame *mNextPattern;
nsCOMPtr<nsIDOMSVGAnimatedString> mHref;
PRPackedBool mLoopFlag;
nsCOMPtr<nsIDOMSVGAnimatedString> mHref;
// This flag is used to detect loops in xlink:href processing
PRPackedBool mLoopFlag;
// This flag is used to detect loops when painting this pattern
// ends up recursively painting itself
PRPackedBool mPaintLoopFlag;
PRPackedBool mNoHRefURI;
};
#endif

View File

@ -40,7 +40,7 @@
#include "nsStyleContext.h"
#include "nsFrame.h"
#include "nsGkAtoms.h"
#include "nsISVGValue.h"
#include "nsSVGEffects.h"
// This is a very simple frame whose only purpose is to capture style change
// events and propagate them to the parent. Most of the heavy lifting is done
@ -94,9 +94,8 @@ public:
NS_IMETHODIMP
nsSVGStopFrame::DidSetStyleContext()
{
// Tell our parent
if (mParent)
mParent->DidSetStyleContext();
nsSVGStopFrameBase::DidSetStyleContext();
nsSVGEffects::InvalidateRenderingObservers(this);
return NS_OK;
}
@ -113,21 +112,8 @@ nsSVGStopFrame::AttributeChanged(PRInt32 aNameSpaceID,
{
if (aNameSpaceID == kNameSpaceID_None &&
aAttribute == nsGkAtoms::offset) {
// Need to tell our parent gradients that something happened.
// Calling {Begin,End}Update on an nsISVGValue, which
// nsSVGGradientFrame implements, causes its observers (the
// referencing graphics frames) to be notified.
if (mParent) {
nsISVGValue *svgParent;
CallQueryInterface(mParent, &svgParent);
if (svgParent) {
svgParent->BeginBatchUpdate();
svgParent->EndBatchUpdate();
}
}
return NS_OK;
}
nsSVGEffects::InvalidateRenderingObservers(this);
}
return nsSVGStopFrameBase::AttributeChanged(aNameSpaceID,
aAttribute, aModType);

View File

@ -594,7 +594,7 @@ nsSVGUtils::FindFilterInvalidation(nsIFrame *aFrame, const nsRect& aRect)
nsSVGFilterProperty *property = nsSVGEffects::GetFilterProperty(aFrame);
if (property) {
nsSVGFilterFrame *filter = property->GetFilterFrame(nsnull);
nsSVGFilterFrame *filter = property->GetFilterFrame();
if (filter) {
rect = filter->GetInvalidationBBox(aFrame, rect);
}
@ -622,6 +622,8 @@ nsSVGUtils::UpdateGraphic(nsISVGChildFrame *aSVGFrame)
nsIFrame *frame;
CallQueryInterface(aSVGFrame, &frame);
nsSVGEffects::InvalidateRenderingObservers(frame);
if (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
return;
@ -985,8 +987,7 @@ nsSVGUtils::PaintChildWithEffects(nsSVGRenderState *aContext,
nsSVGEffects::GetEffectProperties(aFrame);
PRBool isOK = PR_TRUE;
nsSVGFilterFrame *filterFrame = effectProperties.mFilter ?
effectProperties.mFilter->GetFilterFrame(&isOK) : nsnull;
nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK);
/* Check if we need to draw anything. HasValidCoveredRect only returns
* true for path geometry and glyphs, so basically we're traversing
@ -1024,10 +1025,8 @@ nsSVGUtils::PaintChildWithEffects(nsSVGRenderState *aContext,
gfxContext *gfx = aContext->GetGfxContext();
PRBool complexEffects = PR_FALSE;
nsSVGClipPathFrame *clipPathFrame = effectProperties.mClipPath ?
effectProperties.mClipPath->GetClipPathFrame(&isOK) : nsnull;
nsSVGMaskFrame *maskFrame = effectProperties.mMask ?
effectProperties.mMask->GetMaskFrame(&isOK) : nsnull;
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK);
PRBool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : PR_TRUE;
@ -1105,14 +1104,6 @@ nsSVGUtils::PaintChildWithEffects(nsSVGRenderState *aContext,
gfx->Restore();
}
void
nsSVGUtils::UpdateEffects(nsIFrame *aFrame)
{
aFrame->DeleteProperty(nsGkAtoms::filter);
aFrame->DeleteProperty(nsGkAtoms::mask);
aFrame->DeleteProperty(nsGkAtoms::clipPath);
}
PRBool
nsSVGUtils::HitTestClip(nsIFrame *aFrame, const nsPoint &aPoint)
{
@ -1121,7 +1112,7 @@ nsSVGUtils::HitTestClip(nsIFrame *aFrame, const nsPoint &aPoint)
if (!props.mClipPath)
return PR_TRUE;
nsSVGClipPathFrame *clipPathFrame = props.mClipPath->GetClipPathFrame(nsnull);
nsSVGClipPathFrame *clipPathFrame = props.GetClipPathFrame(nsnull);
if (!clipPathFrame) {
// clipPath is not a valid resource, so nothing gets painted, so
// hit-testing must fail.
@ -1435,8 +1426,9 @@ nsSVGUtils::CanOptimizeOpacity(nsIFrame *aFrame)
if (type == nsGkAtoms::svgImageFrame)
return PR_TRUE;
if (type == nsGkAtoms::svgPathGeometryFrame) {
nsSVGGeometryFrame *geom = static_cast<nsSVGGeometryFrame*>(aFrame);
if (!(geom->HasFill() && geom->HasStroke()))
const nsStyleSVG *style = aFrame->GetStyleSVG();
if (style->mFill.mType == eStyleSVGPaintType_None &&
style->mStroke.mType == eStyleSVGPaintType_None)
return PR_TRUE;
}
}

View File

@ -90,17 +90,10 @@ class nsISVGChildFrame;
#define NS_STATE_SVG_DIRTY 0x00400000
/* Do we have a paint server for fill with a valid URL? */
#define NS_STATE_SVG_FILL_PSERVER 0x00800000
/* Do we have a paint server for stroke with a valid URL? */
#define NS_STATE_SVG_STROKE_PSERVER 0x01000000
/* Do we have any paint servers with valid URLs? */
#define NS_STATE_SVG_PSERVER_MASK 0x01800000
/* are we the child of a non-display container? */
#define NS_STATE_SVG_NONDISPLAY_CHILD 0x02000000
#define NS_STATE_SVG_NONDISPLAY_CHILD 0x00800000
#define NS_STATE_SVG_PROPAGATE_TRANSFORM 0x04000000
#define NS_STATE_SVG_PROPAGATE_TRANSFORM 0x01000000
/**
* Byte offsets of channels in a native packed gfxColor or cairo image surface.
@ -353,13 +346,6 @@ public:
nsIntRect *aDirtyRect,
nsIFrame *aFrame);
/**
* Called by nsCSSFrameConstructor when style changes require the
* effect properties on aFrame to be updated
*/
static void
UpdateEffects(nsIFrame *aFrame);
/* Hit testing - check if point hits the clipPath of indicated
* frame. Returns true if no clipPath set. */
static PRBool