Bug 336803 - Remove nsISVGGradient. r=jwatt, sr=roc

This commit is contained in:
tor%cs.brown.edu 2006-05-11 20:01:12 +00:00
parent 314fa97a97
commit ebdff7da40
12 changed files with 410 additions and 780 deletions

View File

@ -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;

View File

@ -42,7 +42,7 @@
#include "nsISVGValueObserver.h"
#include <cairo.h>
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;
};

View File

@ -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);

View File

@ -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<nsSVGElement> mSourceContent;
private:
// href of the other gradient we reference (if any)
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;
};
// -------------------------------------------------------------------------
// 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<nsISVGGradient> 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<nsIDOMSVGAnimatedNumber> 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<nsIDOMSVGGradientElement> gradElement = do_QueryInterface(gradient);
nsCOMPtr<nsIDOMSVGAnimatedEnumeration> 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;
}

View File

@ -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<nsSVGElement> mSourceContent;
private:
// href of the other gradient we reference (if any)
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;
};
// -------------------------------------------------------------------------
// 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,

View File

@ -47,7 +47,6 @@ XPIDL_MODULE = gksvgrenderer
XPIDLSRCS = \
nsISVGGlyphGeometrySource.idl \
nsISVGGlyphMetricsSource.idl \
nsISVGGradient.idl \
nsISVGPathGeometrySource.idl \
nsISVGRectangleSink.idl \
nsISVGRenderer.idl \

View File

@ -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 <scootermorris@comcast.net> (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;
/** @} */
};
/** @} */

View File

@ -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

View File

@ -56,7 +56,6 @@
#include "nsMemory.h"
#include <cairo.h>
#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);

View File

@ -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<nsIDOMSVGMatrix> 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)

View File

@ -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

View File

@ -52,7 +52,6 @@
#include <float.h>
#include <cairo.h>
#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);