diff --git a/layout/svg/base/src/nsSVGGeometryFrame.cpp b/layout/svg/base/src/nsSVGGeometryFrame.cpp index d746b2ceb887..13795d456198 100644 --- a/layout/svg/base/src/nsSVGGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGGeometryFrame.cpp @@ -37,10 +37,9 @@ #include "nsPresContext.h" #include "nsSVGGradient.h" #include "nsSVGPattern.h" -#include "nsISVGValueUtils.h" #include "nsSVGUtils.h" #include "nsSVGGeometryFrame.h" -#include "nsISVGGradient.h" +#include "nsSVGGradientFrame.h" #include "nsSVGPatternFrame.h" //---------------------------------------------------------------------- @@ -63,10 +62,10 @@ nsSVGGeometryFrame::nsSVGGeometryFrame(nsStyleContext* aContext) nsSVGGeometryFrame::~nsSVGGeometryFrame() { if (mFillGradient) { - NS_REMOVE_SVGVALUE_OBSERVER(mFillGradient); + mFillGradient->RemoveObserver(this); } if (mStrokeGradient) { - NS_REMOVE_SVGVALUE_OBSERVER(mStrokeGradient); + mStrokeGradient->RemoveObserver(this); } if (mFillPattern) { mFillPattern->RemoveObserver(this); @@ -82,11 +81,11 @@ 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 if (mFillGradient) { - NS_REMOVE_SVGVALUE_OBSERVER(mFillGradient); + mFillGradient->RemoveObserver(this); mFillGradient = nsnull; } if (mStrokeGradient) { - NS_REMOVE_SVGVALUE_OBSERVER(mStrokeGradient); + mStrokeGradient->RemoveObserver(this); mStrokeGradient = nsnull; } if (mFillPattern) { @@ -112,45 +111,32 @@ NS_IMETHODIMP nsSVGGeometryFrame::DidModifySVGObservable(nsISVGValue* observable, nsISVGValue::modificationType aModType) { - nsISVGGradient *gradient; - CallQueryInterface(observable, &gradient); - - if (gradient) { - // Yes, we need to handle this differently - if (mFillGradient == gradient) { - if (aModType == nsISVGValue::mod_die) { - mFillGradient = nsnull; - } - UpdateGraphic(nsSVGGeometryFrame::UPDATEMASK_FILL_PAINT); - } else { - // No real harm in assuming a stroke gradient at this point - if (aModType == nsISVGValue::mod_die) { - mStrokeGradient = nsnull; - } - UpdateGraphic(nsSVGGeometryFrame::UPDATEMASK_STROKE_PAINT); - } + nsIFrame *frame; + CallQueryInterface(observable, &frame); + if (!frame) return NS_OK; + + if (frame == mFillGradient) { + if (aModType == nsISVGValue::mod_die) + mFillGradient = nsnull; + UpdateGraphic(nsSVGGeometryFrame::UPDATEMASK_FILL_PAINT); + } + else if (frame == mFillPattern) { + if (aModType == nsISVGValue::mod_die) + mFillPattern = nsnull; + UpdateGraphic(nsSVGGeometryFrame::UPDATEMASK_FILL_PAINT); } - nsIFrame *pval; - CallQueryInterface(observable, &pval); - - if (pval && pval->GetType() == nsLayoutAtoms::svgPatternFrame) { - // Handle Patterns - if (mFillPattern == pval) { - if (aModType == nsISVGValue::mod_die) { - mFillPattern = nsnull; - } - UpdateGraphic(nsSVGGeometryFrame::UPDATEMASK_FILL_PAINT); - } else { - // Assume stroke pattern - if (aModType == nsISVGValue::mod_die) { - mStrokePattern = nsnull; - } - UpdateGraphic(nsSVGGeometryFrame::UPDATEMASK_STROKE_PAINT); - } - return NS_OK; + if (frame == mStrokeGradient) { + if (aModType == nsISVGValue::mod_die) + mStrokeGradient = nsnull; + UpdateGraphic(nsSVGGeometryFrame::UPDATEMASK_STROKE_PAINT); + } + else if (frame == mStrokePattern) { + if (aModType == nsISVGValue::mod_die) + mStrokePattern = nsnull; + UpdateGraphic(nsSVGGeometryFrame::UPDATEMASK_STROKE_PAINT); } return NS_OK; @@ -251,7 +237,7 @@ nsSVGGeometryFrame::GetStrokePaintServerType(PRUint16 *aStrokePaintServerType) { } nsresult -nsSVGGeometryFrame::GetStrokeGradient(nsISVGGradient **aGrad) +nsSVGGeometryFrame::GetStrokeGradient(nsSVGGradientFrame **aGrad) { nsresult rv = NS_OK; *aGrad = nsnull; @@ -263,7 +249,8 @@ nsSVGGeometryFrame::GetStrokeGradient(nsISVGGradient **aGrad) // Now have the URI. Get the gradient rv = NS_GetSVGGradient(&mStrokeGradient, aServer, mContent, GetPresContext()->PresShell()); - NS_ADD_SVGVALUE_OBSERVER(mStrokeGradient); + if (mStrokeGradient) + mStrokeGradient->AddObserver(this); } *aGrad = mStrokeGradient; return rv; @@ -304,7 +291,7 @@ nsSVGGeometryFrame::GetFillPaintServerType(PRUint16 *aFillPaintServerType) } nsresult -nsSVGGeometryFrame::GetFillGradient(nsISVGGradient **aGrad) +nsSVGGeometryFrame::GetFillGradient(nsSVGGradientFrame **aGrad) { nsresult rv = NS_OK; *aGrad = nsnull; @@ -316,7 +303,8 @@ nsSVGGeometryFrame::GetFillGradient(nsISVGGradient **aGrad) // Now have the URI. Get the gradient rv = NS_GetSVGGradient(&mFillGradient, aServer, mContent, GetPresContext()->PresShell()); - NS_ADD_SVGVALUE_OBSERVER(mFillGradient); + if (mFillGradient) + mFillGradient->AddObserver(this); } *aGrad = mFillGradient; return rv; diff --git a/layout/svg/base/src/nsSVGGeometryFrame.h b/layout/svg/base/src/nsSVGGeometryFrame.h index fd978e77c8c5..598b5f419fd6 100644 --- a/layout/svg/base/src/nsSVGGeometryFrame.h +++ b/layout/svg/base/src/nsSVGGeometryFrame.h @@ -42,7 +42,7 @@ #include "nsISVGValueObserver.h" #include -class nsISVGGradient; +class nsSVGGradientFrame; class nsSVGPatternFrame; typedef nsFrame nsSVGGeometryFrameBase; @@ -84,11 +84,11 @@ public: PRUint16 GetStrokePaintType(); nsresult GetStrokePaintServerType(PRUint16 *aStrokePaintServerType); - nsresult GetStrokeGradient(nsISVGGradient **aGrad); + nsresult GetStrokeGradient(nsSVGGradientFrame **aGrad); nsresult GetStrokePattern(nsSVGPatternFrame **aPat); PRUint16 GetFillPaintType(); nsresult GetFillPaintServerType(PRUint16 *aFillPaintServerType); - nsresult GetFillGradient(nsISVGGradient **aGrad); + nsresult GetFillGradient(nsSVGGradientFrame **aGrad); nsresult GetFillPattern(nsSVGPatternFrame **aPat); // Set up a cairo context for filling a path @@ -132,8 +132,8 @@ private: nsresult GetStrokeDashArray(double **arr, PRUint32 *count); float GetStrokeDashoffset(); - nsISVGGradient* mFillGradient; - nsISVGGradient* mStrokeGradient; + nsSVGGradientFrame* mFillGradient; + nsSVGGradientFrame* mStrokeGradient; nsSVGPatternFrame* mFillPattern; nsSVGPatternFrame* mStrokePattern; }; diff --git a/layout/svg/base/src/nsSVGGradient.h b/layout/svg/base/src/nsSVGGradient.h index 98e9534e0402..10242556809f 100644 --- a/layout/svg/base/src/nsSVGGradient.h +++ b/layout/svg/base/src/nsSVGGradient.h @@ -41,14 +41,14 @@ #include "nscore.h" -class nsISVGGradient; +class nsSVGGradientFrame; class nsIURI; class nsIContent; class nsIPresShell; class nsStyleContext; class nsIFrame; -nsresult NS_GetSVGGradient(nsISVGGradient** result, +nsresult NS_GetSVGGradient(nsSVGGradientFrame** result, nsIURI* aURI, nsIContent* aContent, nsIPresShell* aPresShell); diff --git a/layout/svg/base/src/nsSVGGradientFrame.cpp b/layout/svg/base/src/nsSVGGradientFrame.cpp index 60da40568d4d..ddf326fe07f7 100644 --- a/layout/svg/base/src/nsSVGGradientFrame.cpp +++ b/layout/svg/base/src/nsSVGGradientFrame.cpp @@ -37,255 +37,15 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsSVGGenericContainerFrame.h" #include "nsIDOMSVGAnimatedNumber.h" #include "nsIDOMSVGAnimatedString.h" #include "nsIDOMSVGAnimTransformList.h" #include "nsIDOMSVGTransformList.h" #include "nsSVGMatrix.h" -#include "nsISVGGradient.h" -#include "nsIURI.h" #include "nsIDOMSVGStopElement.h" -#include "nsSVGDefsFrame.h" #include "nsSVGGradientElement.h" #include "nsSVGGeometryFrame.h" - -class nsSVGLinearGradientFrame; -class nsSVGRadialGradientFrame; - -typedef nsSVGDefsFrame nsSVGGradientFrameBase; - -class nsSVGGradientFrame : public nsSVGGradientFrameBase, - public nsSVGValue, - public nsISVGValueObserver, - public nsSupportsWeakReference, - public nsISVGGradient -{ -public: - friend nsIFrame* NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, - nsIContent* aContent, - nsStyleContext* aContext); - - friend nsIFrame* NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, - nsIContent* aContent, - nsStyleContext* aContext); - - friend nsIFrame* NS_NewSVGStopFrame(nsIPresShell* aPresShell, - nsIContent* aContent, - nsIFrame* aParentFrame, - nsStyleContext* aContext); - - friend nsresult NS_GetSVGGradientFrame(nsIFrame** result, - nsIURI* aURI, - nsIContent* aContent, - nsIPresShell* aPresShell); - - nsSVGGradientFrame(nsStyleContext* aContext) : - nsSVGGradientFrameBase(aContext) {} - - // nsISupports interface: - NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); - NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } - NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } - - // nsISVGGradient interface: - NS_DECL_NSISVGGRADIENT - - // nsISVGValue interface: - NS_IMETHOD SetValueString(const nsAString &aValue) { return NS_OK; } - NS_IMETHOD GetValueString(nsAString& aValue) { return NS_ERROR_NOT_IMPLEMENTED; } - - // 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, - PRInt32 aModType); - -#ifdef DEBUG - // nsIFrameDebug interface: - NS_IMETHOD GetFrameName(nsAString& aResult) const - { - return MakeFrameName(NS_LITERAL_STRING("SVGGradient"), aResult); - } -#endif // DEBUG - - // nsISVGChildFrame interface: - NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas) - { - 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(); - - // 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); - - // 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); - - // Get a stop element and (optionally) its frame (returns stop index/count) - PRInt32 GetStopElement(PRInt32 aIndex, - nsIDOMSVGStopElement * *aStopElement, - nsIFrame * *aStopFrame); - -protected: - - // Use these inline methods instead of GetGradientWithAttr(..., aGradType) - nsIContent* GetLinearGradientWithAttr(nsIAtom *aAttrName) - { - return GetGradientWithAttr(aAttrName, nsGkAtoms::svgLinearGradientFrame); - } - nsIContent* GetRadialGradientWithAttr(nsIAtom *aAttrName) - { - 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; - } - - // Get the value of our gradientUnits attribute - PRUint16 GetGradientUnits(); - - virtual ~nsSVGGradientFrame(); - - // The graphic element our gradient is (currently) being applied to - nsRefPtr mSourceContent; - -private: - - // href of the other gradient we reference (if any) - nsCOMPtr 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; -}; - - -// ------------------------------------------------------------------------- -// Linear Gradients -// ------------------------------------------------------------------------- - -typedef nsSVGGradientFrame nsSVGLinearGradientFrameBase; - -class nsSVGLinearGradientFrame : public nsSVGLinearGradientFrameBase, - public nsISVGLinearGradient -{ -public: - nsSVGLinearGradientFrame(nsStyleContext* aContext) : - nsSVGLinearGradientFrameBase(aContext) {} - - // nsISupports interface: - NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); - NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } - NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } - - // nsISVGLinearGradient interface: - NS_DECL_NSISVGLINEARGRADIENT - - // nsISVGGradient interface gets inherited from nsSVGGradientFrame - - // nsIFrame interface: - virtual nsIAtom* GetType() const; // frame type: nsGkAtoms::svgLinearGradientFrame - - NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID, - nsIAtom* aAttribute, - PRInt32 aModType); - -#ifdef DEBUG - // nsIFrameDebug interface: - NS_IMETHOD GetFrameName(nsAString& aResult) const - { - return MakeFrameName(NS_LITERAL_STRING("SVGLinearGradient"), aResult); - } -#endif // DEBUG - -}; - -// ------------------------------------------------------------------------- -// Radial Gradients -// ------------------------------------------------------------------------- - -typedef nsSVGGradientFrame nsSVGRadialGradientFrameBase; - -class nsSVGRadialGradientFrame : public nsSVGRadialGradientFrameBase, - public nsISVGRadialGradient -{ -public: - nsSVGRadialGradientFrame(nsStyleContext* aContext) : - nsSVGRadialGradientFrameBase(aContext) {} - - // nsISupports interface: - NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); - NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } - NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } - - // nsISVGRadialGradient interface: - NS_DECL_NSISVGRADIALGRADIENT - - // nsISVGGradient interface gets inherited from nsSVGGradientFrame - - // nsIFrame interface: - virtual nsIAtom* GetType() const; // frame type: nsGkAtoms::svgRadialGradientFrame - - NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID, - nsIAtom* aAttribute, - PRInt32 aModType); - -#ifdef DEBUG - // nsIFrameDebug interface: - NS_IMETHOD GetFrameName(nsAString& aResult) const - { - return MakeFrameName(NS_LITERAL_STRING("SVGRadialGradient"), aResult); - } -#endif // DEBUG -}; +#include "nsSVGGradientFrame.h" //---------------------------------------------------------------------- // Implementation @@ -305,7 +65,6 @@ nsSVGGradientFrame::~nsSVGGradientFrame() NS_INTERFACE_MAP_BEGIN(nsSVGGradientFrame) NS_INTERFACE_MAP_ENTRY(nsISVGValue) - NS_INTERFACE_MAP_ENTRY(nsISVGGradient) NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue) @@ -344,14 +103,11 @@ nsSVGGradientFrame::DidModifySVGObservable(nsISVGValue* observable, } // If we reference another gradient and it's going away, null out mNextGrad - nsCOMPtr gradient; - if (mNextGrad && aModType == nsISVGValue::mod_die && - (gradient = do_QueryInterface(observable))) { - nsISVGGradient *grad; - CallQueryInterface(mNextGrad, &grad); - if (grad == gradient) { + 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! @@ -417,55 +173,45 @@ nsSVGGradientFrame::AttributeChanged(PRInt32 aNameSpaceID, aAttribute, aModType); } -//---------------------------------------------------------------------- -// nsISVGGradient implementation //---------------------------------------------------------------------- -NS_IMETHODIMP -nsSVGGradientFrame::GetStopCount(PRUint32 *aStopCount) +PRUint32 +nsSVGGradientFrame::GetStopCount() { nsIDOMSVGStopElement *stopElement = nsnull; - *aStopCount = GetStopElement(-1, &stopElement, nsnull); - return NS_OK; // no stops is valid - paint as for 'none' + return GetStopElement(-1, &stopElement, nsnull); } -NS_IMETHODIMP -nsSVGGradientFrame::GetStopOffset(PRInt32 aIndex, float *aOffset) +void +nsSVGGradientFrame::GetStopInformation(PRInt32 aIndex, + float *aOffset, nscolor *aColor, float *aOpacity) { + *aOffset = 0.0f; + *aColor = 0; + *aOpacity = 1.0f; + nsIDOMSVGStopElement *stopElement = nsnull; - PRInt32 stopCount = GetStopElement(aIndex, &stopElement, nsnull); + nsIFrame *stopFrame = nsnull; + GetStopElement(aIndex, &stopElement, &stopFrame); if (stopElement) { nsCOMPtr aNum; stopElement->GetOffset(getter_AddRefs(aNum)); + aNum->GetAnimVal(aOffset); if (*aOffset < 0.0f) *aOffset = 0.0f; else if (*aOffset > 1.0f) *aOffset = 1.0f; - - return NS_OK; } - NS_ASSERTION(stopCount == 0, "Don't call me with an invalid stop index!"); - *aOffset = 0.0f; - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsSVGGradientFrame::GetStopColor(PRInt32 aIndex, nscolor *aStopColor) -{ - nsIDOMSVGStopElement *stopElement = nsnull; - nsIFrame *stopFrame = nsnull; - PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame); if (stopFrame) { - *aStopColor = stopFrame->GetStyleSVGReset()->mStopColor.mPaint.mColor; - return NS_OK; + *aColor = stopFrame->GetStyleSVGReset()->mStopColor.mPaint.mColor; + *aOpacity = stopFrame->GetStyleSVGReset()->mStopOpacity; } - - // One way or another we have an implementation problem if we get here #ifdef DEBUG - if (stopElement) { + // One way or another we have an implementation problem if we get here + else if (stopElement) { NS_WARNING("We *do* have a stop but can't use it because it doesn't have " "a frame - we need frame free gradients and stops!"); } @@ -473,54 +219,9 @@ nsSVGGradientFrame::GetStopColor(PRInt32 aIndex, nscolor *aStopColor) NS_ERROR("Don't call me with an invalid stop index!"); } #endif - - *aStopColor = 0; - return NS_ERROR_FAILURE; } -NS_IMETHODIMP -nsSVGGradientFrame::GetStopOpacity(PRInt32 aIndex, float *aStopOpacity) -{ - nsIDOMSVGStopElement *stopElement = nsnull; - nsIFrame *stopFrame = nsnull; - PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame); - if (stopFrame) { - *aStopOpacity = stopFrame->GetStyleSVGReset()->mStopOpacity; - return NS_OK; - } - - // One way or another we have an implementation problem if we get here -#ifdef DEBUG - if (stopElement) { - NS_WARNING("We *do* have a stop but can't use it because it doesn't have " - "a frame - we need frame free gradients and stops!"); - } - else { - NS_ERROR("Don't call me with an invalid stop index!"); - } -#endif - - *aStopOpacity = 1; - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsSVGGradientFrame::GetGradientType(PRUint32 *aType) -{ - if (GetType() == nsGkAtoms::svgLinearGradientFrame) { - *aType = nsISVGGradient::SVG_LINEAR_GRADIENT; - return NS_OK; - } - if (GetType() == nsGkAtoms::svgRadialGradientFrame) { - *aType = nsISVGGradient::SVG_RADIAL_GRADIENT; - return NS_OK; - } - NS_NOTREACHED("Unknown gradient type!"); - *aType = nsISVGGradient::SVG_UNKNOWN_GRADIENT; - return NS_ERROR_UNEXPECTED; -} - -NS_IMETHODIMP +nsresult nsSVGGradientFrame::GetGradientTransform(nsIDOMSVGMatrix **aGradientTransform, nsSVGGeometryFrame *aSource) { @@ -591,8 +292,8 @@ nsSVGGradientFrame::GetGradientTransform(nsIDOMSVGMatrix **aGradientTransform, return bboxTransform->Multiply(gradientTransform, aGradientTransform); } -NS_IMETHODIMP -nsSVGGradientFrame::GetSpreadMethod(PRUint16 *aSpreadMethod) +PRUint16 +nsSVGGradientFrame::GetSpreadMethod() { nsIContent *gradient = GetGradientWithAttr(nsGkAtoms::spreadMethod); if (!gradient) @@ -601,7 +302,10 @@ nsSVGGradientFrame::GetSpreadMethod(PRUint16 *aSpreadMethod) nsCOMPtr gradElement = do_QueryInterface(gradient); nsCOMPtr method; gradElement->GetSpreadMethod(getter_AddRefs(method)); - return method->GetAnimVal(aSpreadMethod); + + PRUint16 val; + method->GetAnimVal(&val); + return val; } @@ -795,17 +499,12 @@ nsSVGLinearGradientFrame::AttributeChanged(PRInt32 aNameSpaceID, } //---------------------------------------------------------------------- -// nsISupports methods -NS_INTERFACE_MAP_BEGIN(nsSVGLinearGradientFrame) - NS_INTERFACE_MAP_ENTRY(nsISVGLinearGradient) -NS_INTERFACE_MAP_END_INHERITING(nsSVGLinearGradientFrameBase) - -// nsISVGLinearGradient -NS_IMETHODIMP -nsSVGLinearGradientFrame::GetX1(float *aX1) +float +nsSVGLinearGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName, + PRUint16 aEnumName) { - nsIContent *gradient = GetLinearGradientWithAttr(nsGkAtoms::x1); + nsIContent *gradient = GetLinearGradientWithAttr(aAtomName); if (!gradient) gradient = mContent; // use our gradient to get the correct default value @@ -818,108 +517,24 @@ nsSVGLinearGradientFrame::GetX1(float *aX1) PRUint16 gradientUnits = GetGradientUnits(); if (gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_USERSPACEONUSE) { - *aX1 = nsSVGUtils::UserSpace(mSourceContent, - &element->mLengthAttributes[nsSVGLinearGradientElement::X1]); - return NS_OK; + return nsSVGUtils::UserSpace(mSourceContent, + &element->mLengthAttributes[aEnumName]); } NS_ASSERTION(gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX, "Unknown gradientUnits type"); - *aX1 = element->mLengthAttributes[nsSVGLinearGradientElement::X1]. + return element->mLengthAttributes[aEnumName]. GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull)); - - return NS_OK; } -nsresult -nsSVGLinearGradientFrame::GetY1(float *aY1) +void +nsSVGLinearGradientFrame::GetParameters(float *aX1, float *aY1, float *aX2, float *aY2) { - nsIContent *gradient = GetLinearGradientWithAttr(nsGkAtoms::y1); - if (!gradient) - gradient = mContent; // use our gradient to get the correct default value - - nsSVGLinearGradientElement *element = - NS_STATIC_CAST(nsSVGLinearGradientElement*, gradient); - - // Object bounding box units are handled by setting the appropriate - // transform in GetGradientTransfrom, but we need to handle user - // space units as part of the individual Get* routines. Fixes 323669. - - PRUint16 gradientUnits = GetGradientUnits(); - if (gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_USERSPACEONUSE) { - *aY1 = nsSVGUtils::UserSpace(mSourceContent, - &element->mLengthAttributes[nsSVGLinearGradientElement::Y1]); - return NS_OK; - } - - NS_ASSERTION(gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX, - "Unknown gradientUnits type"); - - *aY1 = element->mLengthAttributes[nsSVGLinearGradientElement::Y1]. - GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull)); - - return NS_OK; -} - -NS_IMETHODIMP -nsSVGLinearGradientFrame::GetX2(float *aX2) -{ - nsIContent *gradient = GetLinearGradientWithAttr(nsGkAtoms::x2); - if (!gradient) - gradient = mContent; // use our gradient to get the correct default value - - nsSVGLinearGradientElement *element = - NS_STATIC_CAST(nsSVGLinearGradientElement*, gradient); - - // Object bounding box units are handled by setting the appropriate - // transform in GetGradientTransfrom, but we need to handle user - // space units as part of the individual Get* routines. Fixes 323669. - - PRUint16 gradientUnits = GetGradientUnits(); - if (gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_USERSPACEONUSE) { - *aX2 = nsSVGUtils::UserSpace(mSourceContent, - &element->mLengthAttributes[nsSVGLinearGradientElement::X2]); - return NS_OK; - } - - NS_ASSERTION(gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX, - "Unknown gradientUnits type"); - - *aX2 = element->mLengthAttributes[nsSVGLinearGradientElement::X2]. - GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull)); - - return NS_OK; -} - -NS_IMETHODIMP -nsSVGLinearGradientFrame::GetY2(float *aY2) -{ - nsIContent *gradient = GetLinearGradientWithAttr(nsGkAtoms::y2); - if (!gradient) - gradient = mContent; // use our gradient to get the correct default value - - nsSVGLinearGradientElement *element = - NS_STATIC_CAST(nsSVGLinearGradientElement*, gradient); - - // Object bounding box units are handled by setting the appropriate - // transform in GetGradientTransfrom, but we need to handle user - // space units as part of the individual Get* routines. Fixes 323669. - - PRUint16 gradientUnits = GetGradientUnits(); - if (gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_USERSPACEONUSE) { - *aY2 = nsSVGUtils::UserSpace(mSourceContent, - &element->mLengthAttributes[nsSVGLinearGradientElement::Y2]); - return NS_OK; - } - - NS_ASSERTION(gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX, - "Unknown gradientUnits type"); - - *aY2 = element->mLengthAttributes[nsSVGLinearGradientElement::Y2]. - GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull)); - - return NS_OK; + *aX1 = GradientLookupAttribute(nsGkAtoms::x1, nsSVGLinearGradientElement::X1); + *aY1 = GradientLookupAttribute(nsGkAtoms::y1, nsSVGLinearGradientElement::Y1); + *aX2 = GradientLookupAttribute(nsGkAtoms::x2, nsSVGLinearGradientElement::X2); + *aY2 = GradientLookupAttribute(nsGkAtoms::y2, nsSVGLinearGradientElement::Y2); } // ------------------------------------------------------------------------- @@ -953,19 +568,21 @@ nsSVGRadialGradientFrame::AttributeChanged(PRInt32 aNameSpaceID, } //---------------------------------------------------------------------- -// nsISupports methods -NS_INTERFACE_MAP_BEGIN(nsSVGRadialGradientFrame) - NS_INTERFACE_MAP_ENTRY(nsISVGRadialGradient) -NS_INTERFACE_MAP_END_INHERITING(nsSVGRadialGradientFrameBase) - -// nsISVGRadialGradient -NS_IMETHODIMP -nsSVGRadialGradientFrame::GetFx(float *aFx) +float +nsSVGRadialGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName, + PRUint16 aEnumName, + nsIContent *aElement) { - nsIContent *gradient = GetRadialGradientWithAttr(nsGkAtoms::fx); - if (!gradient) - return GetCx(aFx); // if fx isn't set, we must use cx + nsIContent *gradient; + + if (aElement) { + gradient = aElement; + } else { + gradient = GetRadialGradientWithAttr(aAtomName); + if (!gradient) + gradient = mContent; // use our gradient to get the correct default value + } nsSVGRadialGradientElement *element = NS_STATIC_CAST(nsSVGRadialGradientElement*, gradient); @@ -976,138 +593,36 @@ nsSVGRadialGradientFrame::GetFx(float *aFx) PRUint16 gradientUnits = GetGradientUnits(); if (gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_USERSPACEONUSE) { - *aFx = nsSVGUtils::UserSpace(mSourceContent, - &element->mLengthAttributes[nsSVGRadialGradientElement::FX]); - return NS_OK; + return nsSVGUtils::UserSpace(mSourceContent, + &element->mLengthAttributes[aEnumName]); } NS_ASSERTION(gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX, "Unknown gradientUnits type"); - *aFx = element->mLengthAttributes[nsSVGRadialGradientElement::FX]. + return element->mLengthAttributes[aEnumName]. GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull)); - - return NS_OK; } -NS_IMETHODIMP -nsSVGRadialGradientFrame::GetFy(float *aFy) +void +nsSVGRadialGradientFrame::GetParameters(float *aCx, float *aCy, float *aR, + float *aFx, float *aFy) { - nsIContent *gradient = GetRadialGradientWithAttr(nsGkAtoms::fy); - if (!gradient) - return GetCy(aFy); // if fy isn't set, we must use cy + *aCx = GradientLookupAttribute(nsGkAtoms::cx, nsSVGRadialGradientElement::CX); + *aCy = GradientLookupAttribute(nsGkAtoms::cy, nsSVGRadialGradientElement::CY); + *aR = GradientLookupAttribute(nsGkAtoms::r, nsSVGRadialGradientElement::R); - nsSVGRadialGradientElement *element = - NS_STATIC_CAST(nsSVGRadialGradientElement*, gradient); + nsIContent *gradient; - // Object bounding box units are handled by setting the appropriate - // transform in GetGradientTransfrom, but we need to handle user - // space units as part of the individual Get* routines. Fixes 323669. + if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fx))) + *aFx = *aCx; // if fx isn't set, we must use cx + else + *aFx = GradientLookupAttribute(nsGkAtoms::fx, nsSVGRadialGradientElement::FX, gradient); - PRUint16 gradientUnits = GetGradientUnits(); - if (gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_USERSPACEONUSE) { - *aFy = nsSVGUtils::UserSpace(mSourceContent, - &element->mLengthAttributes[nsSVGRadialGradientElement::FY]); - return NS_OK; - } - - NS_ASSERTION(gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX, - "Unknown gradientUnits type"); - - *aFy = element->mLengthAttributes[nsSVGRadialGradientElement::FY]. - GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull)); - - return NS_OK; -} - -NS_IMETHODIMP -nsSVGRadialGradientFrame::GetCx(float *aCx) -{ - nsIContent *gradient = GetRadialGradientWithAttr(nsGkAtoms::cx); - if (!gradient) - gradient = mContent; // use our gradient to get the correct default value - - nsSVGRadialGradientElement *element = - NS_STATIC_CAST(nsSVGRadialGradientElement*, gradient); - - // Object bounding box units are handled by setting the appropriate - // transform in GetGradientTransfrom, but we need to handle user - // space units as part of the individual Get* routines. Fixes 323669. - - PRUint16 gradientUnits = GetGradientUnits(); - if (gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_USERSPACEONUSE) { - *aCx = nsSVGUtils::UserSpace(mSourceContent, - &element->mLengthAttributes[nsSVGRadialGradientElement::CX]); - return NS_OK; - } - - NS_ASSERTION(gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX, - "Unknown gradientUnits type"); - - *aCx = element->mLengthAttributes[nsSVGRadialGradientElement::CX]. - GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull)); - - return NS_OK; -} - -NS_IMETHODIMP -nsSVGRadialGradientFrame::GetCy(float *aCy) -{ - nsIContent *gradient = GetRadialGradientWithAttr(nsGkAtoms::cy); - if (!gradient) - gradient = mContent; // use our gradient to get the correct default value - - nsSVGRadialGradientElement *element = - NS_STATIC_CAST(nsSVGRadialGradientElement*, gradient); - - // Object bounding box units are handled by setting the appropriate - // transform in GetGradientTransfrom, but we need to handle user - // space units as part of the individual Get* routines. Fixes 323669. - - PRUint16 gradientUnits = GetGradientUnits(); - if (gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_USERSPACEONUSE) { - *aCy = nsSVGUtils::UserSpace(mSourceContent, - &element->mLengthAttributes[nsSVGRadialGradientElement::CY]); - return NS_OK; - } - - NS_ASSERTION(gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX, - "Unknown gradientUnits type"); - - *aCy = element->mLengthAttributes[nsSVGRadialGradientElement::CY]. - GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull)); - - return NS_OK; -} - -NS_IMETHODIMP -nsSVGRadialGradientFrame::GetR(float *aR) -{ - nsIContent *gradient = GetRadialGradientWithAttr(nsGkAtoms::r); - if (!gradient) - gradient = mContent; // use our gradient to get the correct default value - - nsSVGRadialGradientElement *element = - NS_STATIC_CAST(nsSVGRadialGradientElement*, gradient); - - // Object bounding box units are handled by setting the appropriate - // transform in GetGradientTransfrom, but we need to handle user - // space units as part of the individual Get* routines. Fixes 323669. - - PRUint16 gradientUnits = GetGradientUnits(); - if (gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_USERSPACEONUSE) { - *aR = nsSVGUtils::UserSpace(mSourceContent, - &element->mLengthAttributes[nsSVGRadialGradientElement::R]); - return NS_OK; - } - - NS_ASSERTION(gradientUnits == nsIDOMSVGGradientElement::SVG_GRUNITS_OBJECTBOUNDINGBOX, - "Unknown gradientUnits type"); - - *aR = element->mLengthAttributes[nsSVGRadialGradientElement::R]. - GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull)); - - return NS_OK; + if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fy))) + *aFy = *aCy; // if fy isn't set, we must use cy + else + *aFy = GradientLookupAttribute(nsGkAtoms::fy, nsSVGRadialGradientElement::FY, gradient); } // ------------------------------------------------------------------------- @@ -1167,9 +682,9 @@ NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, } // Public function to locate the SVGGradientFrame structure pointed to by a URI -// and return a nsISVGGradient -nsresult NS_GetSVGGradient(nsISVGGradient **aGrad, nsIURI *aURI, nsIContent *aContent, - nsIPresShell *aPresShell) +// and return a nsSVGGradientFrame +nsresult NS_GetSVGGradient(nsSVGGradientFrame **aGrad, nsIURI *aURI, + nsIContent *aContent, nsIPresShell *aPresShell) { *aGrad = nsnull; @@ -1182,5 +697,11 @@ nsresult NS_GetSVGGradient(nsISVGGradient **aGrad, nsIURI *aURI, nsIContent *aCo if (!NS_SUCCEEDED(nsSVGUtils::GetReferencedFrame(&result, aURI, aContent, aPresShell))) { return NS_ERROR_FAILURE; } - return result->QueryInterface(NS_GET_IID(nsISVGGradient), (void **)aGrad); + if (result->GetType() == nsGkAtoms::svgLinearGradientFrame || + result->GetType() == nsGkAtoms::svgRadialGradientFrame) { + *aGrad = NS_STATIC_CAST(nsSVGGradientFrame*, result); + return NS_OK; + } + + return NS_ERROR_FAILURE; } diff --git a/layout/svg/base/src/nsSVGGradientFrame.h b/layout/svg/base/src/nsSVGGradientFrame.h index fb263a285fe7..20a5ccb72a23 100644 --- a/layout/svg/base/src/nsSVGGradientFrame.h +++ b/layout/svg/base/src/nsSVGGradientFrame.h @@ -39,9 +39,253 @@ #ifndef __NS_SVGGRADIENTFRAME_H__ #define __NS_SVGGRADIENTFRAME_H__ -#include "nsIFrame.h" -#include "nsIContent.h" -#include "nsIPresShell.h" +#include "nsSVGDefsFrame.h" +#include "nsSVGValue.h" +#include "nsISVGValueObserver.h" +#include "nsWeakReference.h" +#include "nsIDOMSVGAnimatedString.h" +#include "nsSVGElement.h" + +class nsIDOMSVGStopElement; + +typedef nsSVGDefsFrame nsSVGGradientFrameBase; + +class nsSVGGradientFrame : public nsSVGGradientFrameBase, + public nsSVGValue, + public nsISVGValueObserver, + public nsSupportsWeakReference +{ +public: + friend nsIFrame* NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, + nsIContent* aContent, + nsStyleContext* aContext); + + friend nsIFrame* NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, + nsIContent* aContent, + nsStyleContext* aContext); + + friend nsIFrame* NS_NewSVGStopFrame(nsIPresShell* aPresShell, + nsIContent* aContent, + nsIFrame* aParentFrame, + nsStyleContext* aContext); + + friend nsresult NS_GetSVGGradientFrame(nsIFrame** result, + nsIURI* aURI, + nsIContent* aContent, + nsIPresShell* aPresShell); + + nsSVGGradientFrame(nsStyleContext* aContext) : + nsSVGGradientFrameBase(aContext) {} + + enum { + SVG_LINEAR_GRADIENT = 0, + SVG_RADIAL_GRADIENT = 1 + }; + + virtual PRUint16 GetGradientType() = 0; + PRUint16 GetSpreadMethod(); + PRUint32 GetStopCount(); + + void GetStopInformation(PRInt32 aIndex, + float *aOffset, nscolor *aColor, float *aOpacity); + + nsresult GetGradientTransform(nsIDOMSVGMatrix **retval, + nsSVGGeometryFrame *aSource); + + // nsISupports interface: + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } + NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } + + // nsISVGValue interface: + NS_IMETHOD SetValueString(const nsAString &aValue) { return NS_OK; } + NS_IMETHOD GetValueString(nsAString& aValue) { return NS_ERROR_NOT_IMPLEMENTED; } + + // 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, + PRInt32 aModType); + +#ifdef DEBUG + // nsIFrameDebug interface: + NS_IMETHOD GetFrameName(nsAString& aResult) const + { + return MakeFrameName(NS_LITERAL_STRING("SVGGradient"), aResult); + } +#endif // DEBUG + + // nsISVGChildFrame interface: + NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas) + { + 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(); + + // 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); + + // 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); + + // Get a stop element and (optionally) its frame (returns stop index/count) + PRInt32 GetStopElement(PRInt32 aIndex, + nsIDOMSVGStopElement * *aStopElement, + nsIFrame * *aStopFrame); + +protected: + + // Use these inline methods instead of GetGradientWithAttr(..., aGradType) + nsIContent* GetLinearGradientWithAttr(nsIAtom *aAttrName) + { + return GetGradientWithAttr(aAttrName, nsGkAtoms::svgLinearGradientFrame); + } + nsIContent* GetRadialGradientWithAttr(nsIAtom *aAttrName) + { + 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; + } + + // Get the value of our gradientUnits attribute + PRUint16 GetGradientUnits(); + + virtual ~nsSVGGradientFrame(); + + // The graphic element our gradient is (currently) being applied to + nsRefPtr mSourceContent; + +private: + + // href of the other gradient we reference (if any) + nsCOMPtr 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; +}; + + +// ------------------------------------------------------------------------- +// Linear Gradients +// ------------------------------------------------------------------------- + +typedef nsSVGGradientFrame nsSVGLinearGradientFrameBase; + +class nsSVGLinearGradientFrame : public nsSVGLinearGradientFrameBase +{ +public: + nsSVGLinearGradientFrame(nsStyleContext* aContext) : + nsSVGLinearGradientFrameBase(aContext) {} + + void GetParameters(float *aX1, float *aY1, float *aX2, float *aY2); + + virtual PRUint16 GetGradientType() { return SVG_LINEAR_GRADIENT; } + + // nsIFrame interface: + virtual nsIAtom* GetType() const; // frame type: nsGkAtoms::svgLinearGradientFrame + + NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType); + +#ifdef DEBUG + // nsIFrameDebug interface: + NS_IMETHOD GetFrameName(nsAString& aResult) const + { + return MakeFrameName(NS_LITERAL_STRING("SVGLinearGradient"), aResult); + } +#endif // DEBUG + +protected: + float GradientLookupAttribute(nsIAtom *aAtomName, PRUint16 aEnumName); +}; + +// ------------------------------------------------------------------------- +// Radial Gradients +// ------------------------------------------------------------------------- + +typedef nsSVGGradientFrame nsSVGRadialGradientFrameBase; + +class nsSVGRadialGradientFrame : public nsSVGRadialGradientFrameBase +{ +public: + nsSVGRadialGradientFrame(nsStyleContext* aContext) : + nsSVGRadialGradientFrameBase(aContext) {} + + void GetParameters(float *aCx, float *aCy, float *aR, + float *aFx, float *aFy); + + virtual PRUint16 GetGradientType() { return SVG_RADIAL_GRADIENT; } + + // nsIFrame interface: + virtual nsIAtom* GetType() const; // frame type: nsGkAtoms::svgRadialGradientFrame + + NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID, + nsIAtom* aAttribute, + PRInt32 aModType); + +#ifdef DEBUG + // nsIFrameDebug interface: + NS_IMETHOD GetFrameName(nsAString& aResult) const + { + return MakeFrameName(NS_LITERAL_STRING("SVGRadialGradient"), aResult); + } +#endif // DEBUG + +protected: + float GradientLookupAttribute(nsIAtom *aAtomName, PRUint16 aEnumName, + nsIContent *aElement = nsnull); +}; + nsIFrame* NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, nsIContent* aContent, diff --git a/layout/svg/renderer/public/Makefile.in b/layout/svg/renderer/public/Makefile.in index 8a9498466e69..0a13ba5d2b85 100644 --- a/layout/svg/renderer/public/Makefile.in +++ b/layout/svg/renderer/public/Makefile.in @@ -47,7 +47,6 @@ XPIDL_MODULE = gksvgrenderer XPIDLSRCS = \ nsISVGGlyphGeometrySource.idl \ nsISVGGlyphMetricsSource.idl \ - nsISVGGradient.idl \ nsISVGPathGeometrySource.idl \ nsISVGRectangleSink.idl \ nsISVGRenderer.idl \ diff --git a/layout/svg/renderer/public/nsISVGGradient.idl b/layout/svg/renderer/public/nsISVGGradient.idl deleted file mode 100644 index 3e8434369597..000000000000 --- a/layout/svg/renderer/public/nsISVGGradient.idl +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Mozilla SVG project. - * - * The Initial Developer of the Original Code is - * Crocodile Clips Ltd. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Scooter Morris (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsISupports.idl" - -%{C++ -#include "nsColor.h" -%} - -native nscolor(nscolor); - -interface nsIDOMSVGMatrix; -interface nsISVGLinearGradient; -interface nsISVGRadialGradient; -interface nsIFrame; -interface nsSVGGeometryFrame; - -/** - * \addtogroup rendering_backend_interfaces Rendering Backend Interfaces - * @{ - */ - -/** - * Describes the 'gradient' objects (either linear or a radial) to the - * rendering backends. - * - * @nosubgrouping - */ -[uuid(9966f240-8515-4d60-a931-628b201524e1)] -interface nsISVGGradient : nsISupports -{ - const unsigned long SVG_UNKNOWN_GRADIENT = 0; - const unsigned long SVG_LINEAR_GRADIENT = 1; - const unsigned long SVG_RADIAL_GRADIENT = 2; - - readonly attribute PRUint32 gradientType; - readonly attribute PRUint16 spreadMethod; - - void GetStopCount(out PRUint32 aStopCount); - void GetStopOffset(in PRInt32 aIndex, out float aOffset); - void GetStopColor(in PRInt32 aIndex, out nscolor aStopColor); - void GetStopOpacity(in PRInt32 aIndex, out float aStopOpacity); - void GetGradientTransform(out nsIDOMSVGMatrix retval, - in nsSVGGeometryFrame aSource); - /** @} */ -}; - -[uuid(995ad9e6-6bb1-47c5-b402-fc93ce12f5e7)] -interface nsISVGLinearGradient : nsISupports -{ - readonly attribute float X1; - readonly attribute float X2; - readonly attribute float Y1; - readonly attribute float Y2; - - /** @} */ -}; - -[uuid(446435ff-6699-4b4d-85c1-09c18145f5ce)] -interface nsISVGRadialGradient : nsISupports -{ - readonly attribute float Cx; - readonly attribute float Cy; - readonly attribute float R; - readonly attribute float Fx; - readonly attribute float Fy; - - /** @} */ -}; - -/** @} */ - - diff --git a/layout/svg/renderer/src/cairo/Makefile.in b/layout/svg/renderer/src/cairo/Makefile.in index 8fe25656d0c5..3752ecd0e03f 100644 --- a/layout/svg/renderer/src/cairo/Makefile.in +++ b/layout/svg/renderer/src/cairo/Makefile.in @@ -67,6 +67,8 @@ REQUIRES = \ layout \ cairo \ libpixman \ + js \ + webshell \ $(NULL) CPPSRCS = \ @@ -95,6 +97,7 @@ LOCAL_INCLUDES = \ -I$(topsrcdir)/layout/svg/base/src \ -I$(topsrcdir)/layout/xul/base/src \ -I$(topsrcdir)/content/svg/content/src \ + -I$(topsrcdir)/content/base/src \ $(NULL) ifdef MOZ_ENABLE_GTK diff --git a/layout/svg/renderer/src/cairo/nsSVGCairoGlyphGeometry.cpp b/layout/svg/renderer/src/cairo/nsSVGCairoGlyphGeometry.cpp index 5b0987f344d8..5d3e8e400eee 100644 --- a/layout/svg/renderer/src/cairo/nsSVGCairoGlyphGeometry.cpp +++ b/layout/svg/renderer/src/cairo/nsSVGCairoGlyphGeometry.cpp @@ -56,7 +56,6 @@ #include "nsMemory.h" #include -#include "nsISVGGradient.h" #include "nsSVGCairoGradient.h" #include "nsISVGCairoSurface.h" #include "nsSVGCairoPattern.h" @@ -247,7 +246,7 @@ nsSVGCairoGlyphGeometry::Render(nsSVGGlyphFrame *aSource, LOOP_CHARS(cairo_show_text) } else if (filltype == eStyleSVGPaintType_Server) { if (fillServerType == nsSVGGeometryFrame::PAINT_TYPE_GRADIENT) { - nsISVGGradient *aGrad; + nsSVGGradientFrame *aGrad; aSource->GetFillGradient(&aGrad); cairo_pattern_t *gradient = CairoGradient(ctx, aGrad, aSource); @@ -285,7 +284,7 @@ nsSVGCairoGlyphGeometry::Render(nsSVGGlyphFrame *aSource, cairo_stroke(ctx); } else if (stroketype == eStyleSVGPaintType_Server) { if (strokeServerType == nsSVGGeometryFrame::PAINT_TYPE_GRADIENT) { - nsISVGGradient *aGrad; + nsSVGGradientFrame *aGrad; aSource->GetStrokeGradient(&aGrad); cairo_pattern_t *gradient = CairoGradient(ctx, aGrad, aSource); diff --git a/layout/svg/renderer/src/cairo/nsSVGCairoGradient.cpp b/layout/svg/renderer/src/cairo/nsSVGCairoGradient.cpp index 302723cb712f..8adabde1bfe6 100644 --- a/layout/svg/renderer/src/cairo/nsSVGCairoGradient.cpp +++ b/layout/svg/renderer/src/cairo/nsSVGCairoGradient.cpp @@ -47,7 +47,7 @@ #include "nsISVGPathGeometrySource.h" #include "nsSVGCairoGradient.h" #include "nsSVGGeometryFrame.h" -#include "nsISVGGradient.h" +#include "nsSVGGradientFrame.h" static cairo_matrix_t SVGToMatrix(nsIDOMSVGMatrix *ctm) { @@ -64,20 +64,17 @@ static cairo_matrix_t SVGToMatrix(nsIDOMSVGMatrix *ctm) static void -CairoSetStops(cairo_pattern_t *aPattern, nsISVGGradient *aGrad, float aOpacity) +CairoSetStops(cairo_pattern_t *aPattern, + nsSVGGradientFrame *aGrad, float aOpacity) { - PRUint32 nStops; + PRUint32 nStops = aGrad->GetStopCount(); float lastOffset = 0.0f; - aGrad->GetStopCount(&nStops); for (PRUint32 i = 0; i < nStops; i++) { + float offset, opacity; nscolor rgba; - float offset; - float opacity; - aGrad->GetStopOffset(i, &offset); - aGrad->GetStopColor(i, &rgba); - aGrad->GetStopOpacity(i, &opacity); + aGrad->GetStopInformation(i, &offset, &rgba, &opacity); if (offset < lastOffset) offset = lastOffset; @@ -94,40 +91,28 @@ CairoSetStops(cairo_pattern_t *aPattern, nsISVGGradient *aGrad, float aOpacity) static cairo_pattern_t * -CairoLinearGradient(cairo_t *ctx, nsISVGGradient *aGrad) +CairoLinearGradient(cairo_t *ctx, nsSVGGradientFrame *aGrad) { - float fX1, fY1, fX2, fY2; - - nsISVGLinearGradient *aLgrad; - CallQueryInterface(aGrad, &aLgrad); - NS_ASSERTION(aLgrad, "error gradient did not provide a Linear Gradient interface"); + nsSVGLinearGradientFrame *aLgrad = + NS_STATIC_CAST(nsSVGLinearGradientFrame*, aGrad); - aLgrad->GetX1(&fX1); - aLgrad->GetX2(&fX2); - aLgrad->GetY1(&fY1); - aLgrad->GetY2(&fY2); + float x1, y1, x2, y2; + aLgrad->GetParameters(&x1, &y1, &x2, &y2); - return cairo_pattern_create_linear(fX1, fY1, fX2, fY2); + return cairo_pattern_create_linear(x1, y1, x2, y2); } static cairo_pattern_t * -CairoRadialGradient(cairo_t *ctx, nsISVGGradient *aGrad) +CairoRadialGradient(cairo_t *ctx, nsSVGGradientFrame *aGrad) { - float fCx, fCy, fR, fFx, fFy; + nsSVGRadialGradientFrame *aRgrad = + NS_STATIC_CAST(nsSVGRadialGradientFrame*, aGrad); - // Get the Radial Gradient interface - nsISVGRadialGradient *aRgrad; - CallQueryInterface(aGrad, &aRgrad); - NS_ASSERTION(aRgrad, "error gradient did not provide a Linear Gradient interface"); + float cx, cy, r, fx, fy; + aRgrad->GetParameters(&cx, &cy, &r, &fx, &fy); - aRgrad->GetCx(&fCx); - aRgrad->GetCy(&fCy); - aRgrad->GetR(&fR); - aRgrad->GetFx(&fFx); - aRgrad->GetFy(&fFy); - - if (fFx != fCx || fFy != fCy) { + if (fx != cx || fy != cy) { // The focal point (fFx and fFy) must be clamped to be *inside* - not on - // the circumference of the gradient or we'll get rendering anomalies. We // calculate the distance from the focal point to the gradient center and @@ -135,23 +120,23 @@ CairoRadialGradient(cairo_t *ctx, nsISVGGradient *aGrad) // factor of the radius because it's close enough to 1 that we won't get a // fringe at the edge of the gradient if we clamp, but not so close to 1 // that rounding error will give us the same results as using fR itself. - double dMax = 0.999 * fR; - float dx = fFx - fCx; - float dy = fFy - fCy; + double dMax = 0.999 * r; + float dx = fx - cx; + float dy = fy - cy; double d = sqrt((dx * dx) + (dy * dy)); if (d > dMax) { double angle = atan2(dy, dx); - fFx = (float)(dMax * cos(angle)) + fCx; - fFy = (float)(dMax * sin(angle)) + fCy; + fx = (float)(dMax * cos(angle)) + cx; + fy = (float)(dMax * sin(angle)) + cy; } } - return cairo_pattern_create_radial(fFx, fFy, 0, fCx, fCy, fR); + return cairo_pattern_create_radial(fx, fy, 0, cx, cy, r); } cairo_pattern_t * -CairoGradient(cairo_t *ctx, nsISVGGradient *aGrad, +CairoGradient(cairo_t *ctx, nsSVGGradientFrame *aGrad, nsSVGGeometryFrame *aSource) { NS_ASSERTION(aGrad, "Called CairoGradient without a gradient!"); @@ -162,6 +147,8 @@ CairoGradient(cairo_t *ctx, nsISVGGradient *aGrad, nsCOMPtr svgMatrix; aGrad->GetGradientTransform(getter_AddRefs(svgMatrix), aSource); NS_ASSERTION(svgMatrix, "CairoGradient: GetGradientTransform returns null"); + if (!svgMatrix) + return nsnull; cairo_matrix_t patternMatrix = SVGToMatrix(svgMatrix); if (cairo_matrix_invert(&patternMatrix)) { @@ -171,17 +158,15 @@ CairoGradient(cairo_t *ctx, nsISVGGradient *aGrad, cairo_pattern_t *gradient; // Linear or Radial? - PRUint32 type; - aGrad->GetGradientType(&type); - if (type == nsISVGGradient::SVG_LINEAR_GRADIENT) + PRUint16 type = aGrad->GetGradientType(); + if (type == nsSVGGradientFrame::SVG_LINEAR_GRADIENT) gradient = CairoLinearGradient(ctx, aGrad); - else if (type == nsISVGGradient::SVG_RADIAL_GRADIENT) + else if (type == nsSVGGradientFrame::SVG_RADIAL_GRADIENT) gradient = CairoRadialGradient(ctx, aGrad); else return nsnull; // Shouldn't happen - PRUint16 aSpread; - aGrad->GetSpreadMethod(&aSpread); + PRUint16 aSpread = aGrad->GetSpreadMethod(); if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_PAD) cairo_pattern_set_extend(gradient, CAIRO_EXTEND_PAD); else if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_REFLECT) diff --git a/layout/svg/renderer/src/cairo/nsSVGCairoGradient.h b/layout/svg/renderer/src/cairo/nsSVGCairoGradient.h index c393ef243861..d4e491a4984d 100644 --- a/layout/svg/renderer/src/cairo/nsSVGCairoGradient.h +++ b/layout/svg/renderer/src/cairo/nsSVGCairoGradient.h @@ -44,12 +44,12 @@ #include "cairo.h" -class nsISVGGradient; +class nsSVGGradientFrame; class nsSVGGeometryFrame; cairo_pattern_t * CairoGradient(cairo_t *ctx, - nsISVGGradient *aGrad, + nsSVGGradientFrame *aGrad, nsSVGGeometryFrame *aSource); #endif diff --git a/layout/svg/renderer/src/cairo/nsSVGCairoPathGeometry.cpp b/layout/svg/renderer/src/cairo/nsSVGCairoPathGeometry.cpp index a8f2abeb82f4..a28b11f040cf 100644 --- a/layout/svg/renderer/src/cairo/nsSVGCairoPathGeometry.cpp +++ b/layout/svg/renderer/src/cairo/nsSVGCairoPathGeometry.cpp @@ -52,7 +52,6 @@ #include #include #include "nsSVGCairoRegion.h" -#include "nsISVGGradient.h" #include "nsSVGCairoGradient.h" #include "nsISVGCairoSurface.h" #include "nsSVGCairoPattern.h" @@ -250,7 +249,7 @@ nsSVGCairoPathGeometry::Render(nsSVGPathGeometryFrame *aSource, cairo_fill_preserve(ctx); } else if (fillType == eStyleSVGPaintType_Server) { if (fillServerType == nsSVGGeometryFrame::PAINT_TYPE_GRADIENT) { - nsISVGGradient *aGrad; + nsSVGGradientFrame *aGrad; aSource->GetFillGradient(&aGrad); cairo_pattern_t *gradient = CairoGradient(ctx, aGrad, aSource); @@ -287,7 +286,7 @@ nsSVGCairoPathGeometry::Render(nsSVGPathGeometryFrame *aSource, cairo_stroke(ctx); } else if (strokeType == eStyleSVGPaintType_Server) { if (strokeServerType == nsSVGGeometryFrame::PAINT_TYPE_GRADIENT) { - nsISVGGradient *aGrad; + nsSVGGradientFrame *aGrad; aSource->GetStrokeGradient(&aGrad); cairo_pattern_t *gradient = CairoGradient(ctx, aGrad, aSource);