2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-03-26 04:58:59 -07:00
|
|
|
// Main header first:
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsSVGGradientFrame.h"
|
2013-01-15 04:22:03 -08:00
|
|
|
#include <algorithm>
|
2012-03-26 04:58:59 -07:00
|
|
|
|
|
|
|
// Keep others in (case-insensitive) order:
|
2007-04-27 07:28:39 -07:00
|
|
|
#include "gfxPattern.h"
|
2013-01-11 00:43:01 -08:00
|
|
|
#include "mozilla/dom/SVGGradientElement.h"
|
|
|
|
#include "mozilla/dom/SVGStopElement.h"
|
2011-08-11 06:29:50 -07:00
|
|
|
#include "nsContentUtils.h"
|
2012-03-26 04:58:59 -07:00
|
|
|
#include "nsSVGEffects.h"
|
2013-04-14 15:56:34 -07:00
|
|
|
#include "nsSVGAnimatedTransformList.h"
|
2013-10-07 16:15:59 -07:00
|
|
|
#include "gfxColor.h"
|
2013-01-11 00:43:01 -08:00
|
|
|
|
|
|
|
// XXX Tight coupling with content classes ahead!
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-01-07 19:22:41 -08:00
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::dom;
|
2011-09-25 14:04:32 -07:00
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Helper classes
|
|
|
|
|
|
|
|
class nsSVGGradientFrame::AutoGradientReferencer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AutoGradientReferencer(nsSVGGradientFrame *aFrame)
|
|
|
|
: mFrame(aFrame)
|
|
|
|
{
|
|
|
|
// Reference loops should normally be detected in advance and handled, so
|
|
|
|
// we're not expecting to encounter them here
|
|
|
|
NS_ABORT_IF_FALSE(!mFrame->mLoopFlag, "Undetected reference loop!");
|
|
|
|
mFrame->mLoopFlag = true;
|
|
|
|
}
|
|
|
|
~AutoGradientReferencer() {
|
|
|
|
mFrame->mLoopFlag = false;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
nsSVGGradientFrame *mFrame;
|
|
|
|
};
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Implementation
|
|
|
|
|
2008-10-11 04:29:35 -07:00
|
|
|
nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext) :
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSVGGradientFrameBase(aContext),
|
2011-10-17 07:59:28 -07:00
|
|
|
mLoopFlag(false),
|
|
|
|
mNoHRefURI(false)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-09-12 09:49:24 -07:00
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSVGGradientFrame)
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIFrame methods:
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGGradientFrame::AttributeChanged(int32_t aNameSpaceID,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIAtom* aAttribute,
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t aModType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::gradientUnits ||
|
|
|
|
aAttribute == nsGkAtoms::gradientTransform ||
|
|
|
|
aAttribute == nsGkAtoms::spreadMethod)) {
|
2012-06-23 07:19:00 -07:00
|
|
|
nsSVGEffects::InvalidateDirectRenderingObservers(this);
|
2008-09-30 17:51:05 -07:00
|
|
|
} else if (aNameSpaceID == kNameSpaceID_XLink &&
|
|
|
|
aAttribute == nsGkAtoms::href) {
|
|
|
|
// Blow away our reference, if any
|
2010-03-28 18:46:55 -07:00
|
|
|
Properties().Delete(nsSVGEffects::HrefProperty());
|
2011-10-17 07:59:28 -07:00
|
|
|
mNoHRefURI = false;
|
2008-09-30 17:51:05 -07:00
|
|
|
// And update whoever references us
|
2012-06-23 07:19:00 -07:00
|
|
|
nsSVGEffects::InvalidateDirectRenderingObservers(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsSVGGradientFrameBase::AttributeChanged(aNameSpaceID,
|
|
|
|
aAttribute, aModType);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint16_t
|
|
|
|
nsSVGGradientFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
|
2012-03-05 22:58:40 -08:00
|
|
|
{
|
|
|
|
const nsSVGEnum& thisEnum =
|
2013-01-11 00:43:01 -08:00
|
|
|
static_cast<dom::SVGGradientElement*>(mContent)->mEnumAttributes[aIndex];
|
2012-03-05 22:58:40 -08:00
|
|
|
|
|
|
|
if (thisEnum.IsExplicitlySet())
|
|
|
|
return thisEnum.GetAnimValue();
|
|
|
|
|
|
|
|
AutoGradientReferencer gradientRef(this);
|
|
|
|
|
|
|
|
nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
|
|
|
|
return next ? next->GetEnumValue(aIndex, aDefault) :
|
2013-01-11 00:43:01 -08:00
|
|
|
static_cast<dom::SVGGradientElement*>(aDefault)->
|
2012-03-05 22:58:40 -08:00
|
|
|
mEnumAttributes[aIndex].GetAnimValue();
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint16_t
|
2012-03-20 05:15:55 -07:00
|
|
|
nsSVGGradientFrame::GetGradientUnits()
|
|
|
|
{
|
|
|
|
// This getter is called every time the others are called - maybe cache it?
|
2013-01-11 00:43:01 -08:00
|
|
|
return GetEnumValue(dom::SVGGradientElement::GRADIENTUNITS);
|
2012-03-20 05:15:55 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint16_t
|
2012-03-20 05:15:55 -07:00
|
|
|
nsSVGGradientFrame::GetSpreadMethod()
|
|
|
|
{
|
2013-01-11 00:43:01 -08:00
|
|
|
return GetEnumValue(dom::SVGGradientElement::SPREADMETHOD);
|
2012-03-20 05:15:55 -07:00
|
|
|
}
|
|
|
|
|
2013-04-14 15:56:34 -07:00
|
|
|
const nsSVGAnimatedTransformList*
|
2012-03-05 22:58:40 -08:00
|
|
|
nsSVGGradientFrame::GetGradientTransformList(nsIContent* aDefault)
|
|
|
|
{
|
2013-04-14 15:56:34 -07:00
|
|
|
nsSVGAnimatedTransformList *thisTransformList =
|
2013-01-11 00:43:01 -08:00
|
|
|
static_cast<dom::SVGGradientElement*>(mContent)->GetAnimatedTransformList();
|
2012-03-05 22:58:40 -08:00
|
|
|
|
2012-07-29 17:35:26 -07:00
|
|
|
if (thisTransformList && thisTransformList->IsExplicitlySet())
|
2012-03-05 22:58:40 -08:00
|
|
|
return thisTransformList;
|
|
|
|
|
|
|
|
AutoGradientReferencer gradientRef(this);
|
|
|
|
|
|
|
|
nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
|
|
|
|
return next ? next->GetGradientTransformList(aDefault) :
|
2013-01-11 00:43:01 -08:00
|
|
|
static_cast<const dom::SVGGradientElement*>(aDefault)
|
2012-03-05 22:58:40 -08:00
|
|
|
->mGradientTransform.get();
|
|
|
|
}
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
gfxMatrix
|
2010-07-01 09:40:30 -07:00
|
|
|
nsSVGGradientFrame::GetGradientTransform(nsIFrame *aSource,
|
|
|
|
const gfxRect *aOverrideBounds)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-27 07:28:39 -07:00
|
|
|
gfxMatrix bboxMatrix;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint16_t gradientUnits = GetGradientUnits();
|
2013-05-27 00:31:39 -07:00
|
|
|
if (gradientUnits != SVG_UNIT_TYPE_USERSPACEONUSE) {
|
|
|
|
NS_ASSERTION(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
|
|
|
"Unknown gradientUnits type");
|
2007-03-22 10:30:00 -07:00
|
|
|
// objectBoundingBox is the default anyway
|
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
gfxRect bbox =
|
|
|
|
aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(aSource);
|
|
|
|
bboxMatrix =
|
|
|
|
gfxMatrix(bbox.Width(), 0, 0, bbox.Height(), bbox.X(), bbox.Y());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-04-14 15:56:34 -07:00
|
|
|
const nsSVGAnimatedTransformList* animTransformList =
|
2012-03-05 22:58:40 -08:00
|
|
|
GetGradientTransformList(mContent);
|
2011-09-25 14:04:32 -07:00
|
|
|
if (!animTransformList)
|
2007-04-27 07:28:39 -07:00
|
|
|
return bboxMatrix;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-09-25 14:04:32 -07:00
|
|
|
gfxMatrix gradientTransform =
|
|
|
|
animTransformList->GetAnimValue().GetConsolidationMatrix();
|
|
|
|
return bboxMatrix.PreMultiply(gradientTransform);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGLinearGradientElement*
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGGradientFrame::GetLinearGradientWithLength(uint32_t aIndex,
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGLinearGradientElement* aDefault)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-03-05 22:58:40 -08:00
|
|
|
// If this was a linear gradient with the required length, we would have
|
|
|
|
// already found it in nsSVGLinearGradientFrame::GetLinearGradientWithLength.
|
|
|
|
// Since we didn't find the length, continue looking down the chain.
|
|
|
|
|
|
|
|
AutoGradientReferencer gradientRef(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
|
|
|
|
return next ? next->GetLinearGradientWithLength(aIndex, aDefault) : aDefault;
|
|
|
|
}
|
|
|
|
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGRadialGradientElement*
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGGradientFrame::GetRadialGradientWithLength(uint32_t aIndex,
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGRadialGradientElement* aDefault)
|
2012-03-05 22:58:40 -08:00
|
|
|
{
|
|
|
|
// If this was a radial gradient with the required length, we would have
|
|
|
|
// already found it in nsSVGRadialGradientFrame::GetRadialGradientWithLength.
|
|
|
|
// Since we didn't find the length, continue looking down the chain.
|
|
|
|
|
|
|
|
AutoGradientReferencer gradientRef(this);
|
|
|
|
|
|
|
|
nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
|
|
|
|
return next ? next->GetRadialGradientWithLength(aIndex, aDefault) : aDefault;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsSVGPaintServerFrame methods:
|
|
|
|
|
2013-05-27 00:34:01 -07:00
|
|
|
//helper
|
|
|
|
static void GetStopInformation(nsIFrame* aStopFrame,
|
|
|
|
float *aOffset,
|
|
|
|
nscolor *aStopColor,
|
|
|
|
float *aStopOpacity)
|
|
|
|
{
|
|
|
|
nsIContent* stopContent = aStopFrame->GetContent();
|
|
|
|
MOZ_ASSERT(stopContent && stopContent->IsSVG(nsGkAtoms::stop));
|
|
|
|
|
|
|
|
static_cast<SVGStopElement*>(stopContent)->
|
|
|
|
GetAnimatedNumberValues(aOffset, nullptr);
|
|
|
|
|
|
|
|
*aOffset = mozilla::clamped(*aOffset, 0.0f, 1.0f);
|
|
|
|
*aStopColor = aStopFrame->StyleSVGReset()->mStopColor;
|
|
|
|
*aStopOpacity = aStopFrame->StyleSVGReset()->mStopOpacity;
|
|
|
|
}
|
|
|
|
|
2010-07-01 09:40:30 -07:00
|
|
|
already_AddRefed<gfxPattern>
|
|
|
|
nsSVGGradientFrame::GetPaintServerPattern(nsIFrame *aSource,
|
2012-07-13 16:18:38 -07:00
|
|
|
const gfxMatrix& aContextMatrix,
|
2012-05-18 01:34:25 -07:00
|
|
|
nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
|
|
|
|
float aGraphicOpacity,
|
|
|
|
const gfxRect *aOverrideBounds)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-05-27 00:31:39 -07:00
|
|
|
uint16_t gradientUnits = GetGradientUnits();
|
|
|
|
MOZ_ASSERT(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX ||
|
|
|
|
gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE);
|
|
|
|
if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
|
|
|
|
// Set mSource for this consumer.
|
|
|
|
// If this gradient is applied to text, our caller will be the glyph, which
|
|
|
|
// is not an element, so we need to get the parent
|
|
|
|
mSource = aSource->GetContent()->IsNodeOfType(nsINode::eTEXT) ?
|
|
|
|
aSource->GetParent() : aSource;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-05-27 00:34:01 -07:00
|
|
|
nsAutoTArray<nsIFrame*,8> stopFrames;
|
|
|
|
GetStopFrames(&stopFrames);
|
|
|
|
|
|
|
|
uint32_t nStops = stopFrames.Length();
|
2008-02-08 13:52:04 -08:00
|
|
|
|
|
|
|
// SVG specification says that no stops should be treated like
|
|
|
|
// the corresponding fill or stroke had "none" specified.
|
|
|
|
if (nStops == 0) {
|
2010-07-01 09:40:30 -07:00
|
|
|
nsRefPtr<gfxPattern> pattern = new gfxPattern(gfxRGBA(0, 0, 0, 0));
|
|
|
|
return pattern.forget();
|
2008-02-08 13:52:04 -08:00
|
|
|
}
|
2012-10-06 05:52:32 -07:00
|
|
|
|
2013-05-27 00:34:01 -07:00
|
|
|
if (nStops == 1 || GradientVectorLengthIsZero()) {
|
|
|
|
// The gradient paints a single colour, using the stop-color of the last
|
|
|
|
// gradient step if there are more than one.
|
|
|
|
float stopOpacity = stopFrames[nStops-1]->StyleSVGReset()->mStopOpacity;
|
|
|
|
nscolor stopColor = stopFrames[nStops-1]->StyleSVGReset()->mStopColor;
|
|
|
|
|
2012-10-06 05:52:32 -07:00
|
|
|
nsRefPtr<gfxPattern> pattern = new gfxPattern(
|
|
|
|
gfxRGBA(NS_GET_R(stopColor)/255.0,
|
|
|
|
NS_GET_G(stopColor)/255.0,
|
|
|
|
NS_GET_B(stopColor)/255.0,
|
|
|
|
NS_GET_A(stopColor)/255.0 *
|
|
|
|
stopOpacity * aGraphicOpacity));
|
|
|
|
return pattern.forget();
|
|
|
|
}
|
2008-02-08 13:52:04 -08:00
|
|
|
|
2013-05-27 00:31:39 -07:00
|
|
|
// Get the transform list (if there is one). We do this after the returns
|
|
|
|
// above since this call can be expensive when "gradientUnits" is set to
|
|
|
|
// "objectBoundingBox" (since that requiring a GetBBox() call).
|
|
|
|
gfxMatrix patternMatrix = GetGradientTransform(aSource, aOverrideBounds);
|
|
|
|
|
|
|
|
if (patternMatrix.IsSingular()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2012-05-18 01:34:25 -07:00
|
|
|
// revert the vector effect transform so that the gradient appears unchanged
|
|
|
|
if (aFillOrStroke == &nsStyleSVG::mStroke) {
|
|
|
|
patternMatrix.Multiply(nsSVGUtils::GetStrokeTransform(aSource).Invert());
|
|
|
|
}
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
patternMatrix.Invert();
|
|
|
|
|
|
|
|
nsRefPtr<gfxPattern> gradient = CreateGradient();
|
2008-03-17 10:15:43 -07:00
|
|
|
if (!gradient || gradient->CairoStatus())
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint16_t aSpread = GetSpreadMethod();
|
2013-02-02 12:23:16 -08:00
|
|
|
if (aSpread == SVG_SPREADMETHOD_PAD)
|
2007-04-27 07:28:39 -07:00
|
|
|
gradient->SetExtend(gfxPattern::EXTEND_PAD);
|
2013-02-02 12:23:16 -08:00
|
|
|
else if (aSpread == SVG_SPREADMETHOD_REFLECT)
|
2007-04-27 07:28:39 -07:00
|
|
|
gradient->SetExtend(gfxPattern::EXTEND_REFLECT);
|
2013-02-02 12:23:16 -08:00
|
|
|
else if (aSpread == SVG_SPREADMETHOD_REPEAT)
|
2007-04-27 07:28:39 -07:00
|
|
|
gradient->SetExtend(gfxPattern::EXTEND_REPEAT);
|
|
|
|
|
|
|
|
gradient->SetMatrix(patternMatrix);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// setup stops
|
|
|
|
float lastOffset = 0.0f;
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < nStops; i++) {
|
2007-04-24 01:11:22 -07:00
|
|
|
float offset, stopOpacity;
|
|
|
|
nscolor stopColor;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-05-27 00:34:01 -07:00
|
|
|
GetStopInformation(stopFrames[i], &offset, &stopColor, &stopOpacity);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (offset < lastOffset)
|
|
|
|
offset = lastOffset;
|
|
|
|
else
|
|
|
|
lastOffset = offset;
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
gradient->AddColorStop(offset,
|
|
|
|
gfxRGBA(NS_GET_R(stopColor)/255.0,
|
|
|
|
NS_GET_G(stopColor)/255.0,
|
|
|
|
NS_GET_B(stopColor)/255.0,
|
|
|
|
NS_GET_A(stopColor)/255.0 *
|
|
|
|
stopOpacity * aGraphicOpacity));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-07-01 09:40:30 -07:00
|
|
|
return gradient.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Private (helper) methods
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientFrame *
|
|
|
|
nsSVGGradientFrame::GetReferencedGradient()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-09-30 17:51:05 -07:00
|
|
|
if (mNoHRefURI)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2008-09-30 01:47:20 -07:00
|
|
|
|
2010-03-28 18:46:55 -07:00
|
|
|
nsSVGPaintingProperty *property = static_cast<nsSVGPaintingProperty*>
|
|
|
|
(Properties().Get(nsSVGEffects::HrefProperty()));
|
2008-09-30 17:51:05 -07:00
|
|
|
|
|
|
|
if (!property) {
|
|
|
|
// Fetch our gradient element's xlink:href attribute
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGGradientElement*grad = static_cast<dom::SVGGradientElement*>(mContent);
|
2009-01-21 16:56:51 -08:00
|
|
|
nsAutoString href;
|
2013-01-11 00:43:01 -08:00
|
|
|
grad->mStringAttributes[dom::SVGGradientElement::HREF].GetAnimValue(href, grad);
|
2008-09-30 17:51:05 -07:00
|
|
|
if (href.IsEmpty()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
mNoHRefURI = true;
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr; // no URL
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-09-30 17:51:05 -07:00
|
|
|
|
|
|
|
// Convert href to an nsIURI
|
|
|
|
nsCOMPtr<nsIURI> targetURI;
|
|
|
|
nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
|
|
|
|
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
|
|
|
|
mContent->GetCurrentDoc(), base);
|
|
|
|
|
2010-03-28 18:46:55 -07:00
|
|
|
property =
|
|
|
|
nsSVGEffects::GetPaintingProperty(targetURI, this, nsSVGEffects::HrefProperty());
|
2008-09-30 17:51:05 -07:00
|
|
|
if (!property)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-09-30 17:51:05 -07:00
|
|
|
|
|
|
|
nsIFrame *result = property->GetReferencedFrame();
|
|
|
|
if (!result)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2008-09-30 17:51:05 -07:00
|
|
|
|
|
|
|
nsIAtom* frameType = result->GetType();
|
|
|
|
if (frameType != nsGkAtoms::svgLinearGradientFrame &&
|
|
|
|
frameType != nsGkAtoms::svgRadialGradientFrame)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2008-09-30 17:51:05 -07:00
|
|
|
|
|
|
|
return static_cast<nsSVGGradientFrame*>(result);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
nsSVGGradientFrame *
|
|
|
|
nsSVGGradientFrame::GetReferencedGradientIfNotInUse()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-03-05 22:58:40 -08:00
|
|
|
nsSVGGradientFrame *referenced = GetReferencedGradient();
|
|
|
|
if (!referenced)
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
if (referenced->mLoopFlag) {
|
|
|
|
// XXXjwatt: we should really send an error to the JavaScript Console here:
|
|
|
|
NS_WARNING("gradient reference loop detected while inheriting attribute!");
|
2012-07-30 07:20:58 -07:00
|
|
|
return nullptr;
|
2012-03-05 22:58:40 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
return referenced;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-05-27 00:34:01 -07:00
|
|
|
void
|
|
|
|
nsSVGGradientFrame::GetStopFrames(nsTArray<nsIFrame*>* aStopFrames)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-30 07:20:58 -07:00
|
|
|
nsIFrame *stopFrame = nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
for (stopFrame = mFrames.FirstChild(); stopFrame;
|
|
|
|
stopFrame = stopFrame->GetNextSibling()) {
|
|
|
|
if (stopFrame->GetType() == nsGkAtoms::svgStopFrame) {
|
2013-05-27 00:34:01 -07:00
|
|
|
aStopFrames->AppendElement(stopFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2013-05-27 00:34:01 -07:00
|
|
|
if (aStopFrames->Length() > 0) {
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Our gradient element doesn't have stops - try to "inherit" them
|
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
AutoGradientReferencer gradientRef(this);
|
|
|
|
nsSVGGradientFrame* next = GetReferencedGradientIfNotInUse();
|
2013-05-27 00:34:01 -07:00
|
|
|
if (!next) {
|
|
|
|
return;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-05-27 00:34:01 -07:00
|
|
|
return next->GetStopFrames(aStopFrames);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Linear Gradients
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
2009-01-19 10:31:34 -08:00
|
|
|
#ifdef DEBUG
|
2013-03-19 18:47:48 -07:00
|
|
|
void
|
2009-01-19 10:31:34 -08:00
|
|
|
nsSVGLinearGradientFrame::Init(nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow)
|
|
|
|
{
|
2013-01-07 19:22:41 -08:00
|
|
|
NS_ASSERTION(aContent->IsSVG(nsGkAtoms::linearGradient),
|
|
|
|
"Content is not an SVG linearGradient");
|
2009-01-19 10:31:34 -08:00
|
|
|
|
2013-03-19 18:47:48 -07:00
|
|
|
nsSVGLinearGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
|
2009-01-19 10:31:34 -08:00
|
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIAtom*
|
|
|
|
nsSVGLinearGradientFrame::GetType() const
|
|
|
|
{
|
|
|
|
return nsGkAtoms::svgLinearGradientFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGLinearGradientFrame::AttributeChanged(int32_t aNameSpaceID,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIAtom* aAttribute,
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t aModType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::x1 ||
|
|
|
|
aAttribute == nsGkAtoms::y1 ||
|
|
|
|
aAttribute == nsGkAtoms::x2 ||
|
|
|
|
aAttribute == nsGkAtoms::y2)) {
|
2012-06-23 07:19:00 -07:00
|
|
|
nsSVGEffects::InvalidateDirectRenderingObservers(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
|
|
|
|
aAttribute, aModType);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
float
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGLinearGradientFrame::GetLengthValue(uint32_t aIndex)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGLinearGradientElement* lengthElement =
|
2012-03-05 22:58:40 -08:00
|
|
|
GetLinearGradientWithLength(aIndex,
|
2013-01-11 00:43:01 -08:00
|
|
|
static_cast<dom::SVGLinearGradientElement*>(mContent));
|
2012-03-05 22:58:40 -08:00
|
|
|
// We passed in mContent as a fallback, so, assuming mContent is non-null, the
|
|
|
|
// return value should also be non-null.
|
|
|
|
NS_ABORT_IF_FALSE(lengthElement,
|
|
|
|
"Got unexpected null element from GetLinearGradientWithLength");
|
|
|
|
const nsSVGLength2 &length = lengthElement->mLengthAttributes[aIndex];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Object bounding box units are handled by setting the appropriate
|
2007-08-27 16:11:14 -07:00
|
|
|
// transform in GetGradientTransform, but we need to handle user
|
2007-03-22 10:30:00 -07:00
|
|
|
// space units as part of the individual Get* routines. Fixes 323669.
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint16_t gradientUnits = GetGradientUnits();
|
2013-02-17 18:14:02 -08:00
|
|
|
if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
|
2012-03-05 22:58:40 -08:00
|
|
|
return nsSVGUtils::UserSpace(mSource, &length);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
NS_ASSERTION(
|
2013-02-17 18:14:02 -08:00
|
|
|
gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
2012-03-05 22:58:40 -08:00
|
|
|
"Unknown gradientUnits type");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-01-09 15:02:45 -08:00
|
|
|
return length.GetAnimValue(static_cast<SVGSVGElement*>(nullptr));
|
2012-03-05 22:58:40 -08:00
|
|
|
}
|
|
|
|
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGLinearGradientElement*
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGLinearGradientFrame::GetLinearGradientWithLength(uint32_t aIndex,
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGLinearGradientElement* aDefault)
|
2012-03-05 22:58:40 -08:00
|
|
|
{
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGLinearGradientElement* thisElement =
|
|
|
|
static_cast<dom::SVGLinearGradientElement*>(mContent);
|
2012-03-05 22:58:40 -08:00
|
|
|
const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
|
|
|
|
|
|
|
|
if (length.IsExplicitlySet()) {
|
|
|
|
return thisElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsSVGLinearGradientFrameBase::GetLinearGradientWithLength(aIndex,
|
|
|
|
aDefault);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-10-06 05:52:32 -07:00
|
|
|
bool
|
2013-05-27 00:34:01 -07:00
|
|
|
nsSVGLinearGradientFrame::GradientVectorLengthIsZero()
|
2012-10-06 05:52:32 -07:00
|
|
|
{
|
2013-05-27 00:34:01 -07:00
|
|
|
return GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1) ==
|
|
|
|
GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2) &&
|
|
|
|
GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1) ==
|
|
|
|
GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2);
|
2012-10-06 05:52:32 -07:00
|
|
|
}
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
already_AddRefed<gfxPattern>
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSVGLinearGradientFrame::CreateGradient()
|
|
|
|
{
|
|
|
|
float x1, y1, x2, y2;
|
|
|
|
|
2013-01-11 00:43:01 -08:00
|
|
|
x1 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1);
|
|
|
|
y1 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1);
|
|
|
|
x2 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2);
|
|
|
|
y2 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-04-22 04:15:59 -07:00
|
|
|
nsRefPtr<gfxPattern> pattern = new gfxPattern(x1, y1, x2, y2);
|
|
|
|
return pattern.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Radial Gradients
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
2009-01-19 10:31:34 -08:00
|
|
|
#ifdef DEBUG
|
2013-03-19 18:47:48 -07:00
|
|
|
void
|
2009-01-19 10:31:34 -08:00
|
|
|
nsSVGRadialGradientFrame::Init(nsIContent* aContent,
|
|
|
|
nsIFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow)
|
|
|
|
{
|
2013-01-07 19:22:41 -08:00
|
|
|
NS_ASSERTION(aContent->IsSVG(nsGkAtoms::radialGradient),
|
|
|
|
"Content is not an SVG radialGradient");
|
2009-01-19 10:31:34 -08:00
|
|
|
|
2013-03-19 18:47:48 -07:00
|
|
|
nsSVGRadialGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
|
2009-01-19 10:31:34 -08:00
|
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIAtom*
|
|
|
|
nsSVGRadialGradientFrame::GetType() const
|
|
|
|
{
|
|
|
|
return nsGkAtoms::svgRadialGradientFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGRadialGradientFrame::AttributeChanged(int32_t aNameSpaceID,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIAtom* aAttribute,
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t aModType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::r ||
|
|
|
|
aAttribute == nsGkAtoms::cx ||
|
|
|
|
aAttribute == nsGkAtoms::cy ||
|
|
|
|
aAttribute == nsGkAtoms::fx ||
|
|
|
|
aAttribute == nsGkAtoms::fy)) {
|
2012-06-23 07:19:00 -07:00
|
|
|
nsSVGEffects::InvalidateDirectRenderingObservers(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
|
|
|
|
aAttribute, aModType);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
float
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGRadialGradientFrame::GetLengthValue(uint32_t aIndex)
|
2012-03-05 22:58:40 -08:00
|
|
|
{
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGRadialGradientElement* lengthElement =
|
2012-03-05 22:58:40 -08:00
|
|
|
GetRadialGradientWithLength(aIndex,
|
2013-01-11 00:43:01 -08:00
|
|
|
static_cast<dom::SVGRadialGradientElement*>(mContent));
|
2012-03-05 22:58:40 -08:00
|
|
|
// We passed in mContent as a fallback, so, assuming mContent is non-null,
|
|
|
|
// the return value should also be non-null.
|
|
|
|
NS_ABORT_IF_FALSE(lengthElement,
|
|
|
|
"Got unexpected null element from GetRadialGradientWithLength");
|
|
|
|
return GetLengthValueFromElement(aIndex, *lengthElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
float
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGRadialGradientFrame::GetLengthValue(uint32_t aIndex, float aDefaultValue)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGRadialGradientElement* lengthElement =
|
2012-07-30 07:20:58 -07:00
|
|
|
GetRadialGradientWithLength(aIndex, nullptr);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
return lengthElement ? GetLengthValueFromElement(aIndex, *lengthElement)
|
|
|
|
: aDefaultValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
float
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGRadialGradientFrame::GetLengthValueFromElement(uint32_t aIndex,
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGRadialGradientElement& aElement)
|
2012-03-05 22:58:40 -08:00
|
|
|
{
|
|
|
|
const nsSVGLength2 &length = aElement.mLengthAttributes[aIndex];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Object bounding box units are handled by setting the appropriate
|
2007-08-27 16:11:14 -07:00
|
|
|
// transform in GetGradientTransform, but we need to handle user
|
2007-03-22 10:30:00 -07:00
|
|
|
// space units as part of the individual Get* routines. Fixes 323669.
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint16_t gradientUnits = GetGradientUnits();
|
2013-02-17 18:14:02 -08:00
|
|
|
if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
|
2012-03-05 22:58:40 -08:00
|
|
|
return nsSVGUtils::UserSpace(mSource, &length);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
NS_ASSERTION(
|
2013-02-17 18:14:02 -08:00
|
|
|
gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
2012-03-05 22:58:40 -08:00
|
|
|
"Unknown gradientUnits type");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-01-09 15:02:45 -08:00
|
|
|
return length.GetAnimValue(static_cast<SVGSVGElement*>(nullptr));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGRadialGradientElement*
|
2012-08-22 08:56:38 -07:00
|
|
|
nsSVGRadialGradientFrame::GetRadialGradientWithLength(uint32_t aIndex,
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGRadialGradientElement* aDefault)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-01-11 00:43:01 -08:00
|
|
|
dom::SVGRadialGradientElement* thisElement =
|
|
|
|
static_cast<dom::SVGRadialGradientElement*>(mContent);
|
2012-03-05 22:58:40 -08:00
|
|
|
const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
if (length.IsExplicitlySet()) {
|
|
|
|
return thisElement;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
return nsSVGRadialGradientFrameBase::GetRadialGradientWithLength(aIndex,
|
|
|
|
aDefault);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-10-06 05:52:32 -07:00
|
|
|
bool
|
2013-05-27 00:34:01 -07:00
|
|
|
nsSVGRadialGradientFrame::GradientVectorLengthIsZero()
|
2012-10-06 05:52:32 -07:00
|
|
|
{
|
2013-05-27 00:34:01 -07:00
|
|
|
return GetLengthValue(dom::SVGRadialGradientElement::ATTR_R) == 0;
|
2012-10-06 05:52:32 -07:00
|
|
|
}
|
|
|
|
|
2012-03-05 22:58:40 -08:00
|
|
|
already_AddRefed<gfxPattern>
|
|
|
|
nsSVGRadialGradientFrame::CreateGradient()
|
|
|
|
{
|
|
|
|
float cx, cy, r, fx, fy;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2013-01-11 00:43:01 -08:00
|
|
|
cx = GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX);
|
|
|
|
cy = GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY);
|
|
|
|
r = GetLengthValue(dom::SVGRadialGradientElement::ATTR_R);
|
2012-03-05 22:58:40 -08:00
|
|
|
// If fx or fy are not set, use cx/cy instead
|
2013-01-11 00:43:01 -08:00
|
|
|
fx = GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX, cx);
|
|
|
|
fy = GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY, cy);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
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
|
2010-06-30 13:24:53 -07:00
|
|
|
// make sure it is *less* than the gradient radius.
|
|
|
|
// 1/128 is the limit of the fractional part of cairo's 24.8 fixed point
|
|
|
|
// representation divided by 2 to ensure that we get different cairo
|
|
|
|
// fractions
|
2013-01-15 04:22:03 -08:00
|
|
|
double dMax = std::max(0.0, r - 1.0/128);
|
2007-03-22 10:30:00 -07:00
|
|
|
float dx = fx - cx;
|
|
|
|
float dy = fy - cy;
|
|
|
|
double d = sqrt((dx * dx) + (dy * dy));
|
|
|
|
if (d > dMax) {
|
|
|
|
double angle = atan2(dy, dx);
|
|
|
|
fx = (float)(dMax * cos(angle)) + cx;
|
|
|
|
fy = (float)(dMax * sin(angle)) + cy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-22 04:15:59 -07:00
|
|
|
nsRefPtr<gfxPattern> pattern = new gfxPattern(fx, fy, 0, cx, cy, r);
|
|
|
|
return pattern.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Public functions
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsIFrame*
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell,
|
|
|
|
nsStyleContext* aContext)
|
|
|
|
{
|
2008-10-11 04:29:35 -07:00
|
|
|
return new (aPresShell) nsSVGLinearGradientFrame(aContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-09-12 09:49:24 -07:00
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSVGLinearGradientFrame)
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIFrame*
|
|
|
|
NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell,
|
|
|
|
nsStyleContext* aContext)
|
|
|
|
{
|
2008-10-11 04:29:35 -07:00
|
|
|
return new (aPresShell) nsSVGRadialGradientFrame(aContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-09-12 09:49:24 -07:00
|
|
|
|
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSVGRadialGradientFrame)
|