mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
1c324609bd
commit
09cfc5fa8c
@ -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) {
|
||||
|
@ -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).
|
||||
|
@ -2629,7 +2629,6 @@ nsLayoutUtils::CalculateContentBottom(nsIFrame* aFrame)
|
||||
childList = aFrame->GetAdditionalChildListName(nextListID);
|
||||
nextListID++;
|
||||
} while (childList);
|
||||
|
||||
}
|
||||
|
||||
return contentBottom;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 |
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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_*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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__
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user