2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; 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
|
|
|
|
* Scooter Morris.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2004
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Scooter Morris <scootermorris@comcast.net>
|
|
|
|
* Jonathan Watt <jwatt@jwatt.org>
|
|
|
|
*
|
|
|
|
* 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 "nsIDOMSVGAnimatedNumber.h"
|
|
|
|
#include "nsIDOMSVGAnimTransformList.h"
|
|
|
|
#include "nsSVGTransformList.h"
|
|
|
|
#include "nsSVGMatrix.h"
|
2008-09-30 17:51:05 -07:00
|
|
|
#include "nsSVGEffects.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMSVGStopElement.h"
|
|
|
|
#include "nsSVGGradientElement.h"
|
|
|
|
#include "nsSVGGeometryFrame.h"
|
|
|
|
#include "nsSVGGradientFrame.h"
|
|
|
|
#include "gfxContext.h"
|
|
|
|
#include "nsIDOMSVGRect.h"
|
2007-04-27 07:28:39 -07:00
|
|
|
#include "gfxPattern.h"
|
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),
|
|
|
|
mLoopFlag(PR_FALSE),
|
2008-09-30 17:51:05 -07:00
|
|
|
mNoHRefURI(PR_FALSE)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIFrame methods:
|
|
|
|
|
2008-10-13 15:03:28 -07:00
|
|
|
/* virtual */ void
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSVGGradientFrame::DidSetStyleContext()
|
|
|
|
{
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGEffects::InvalidateRenderingObservers(this);
|
2008-10-13 15:03:28 -07:00
|
|
|
nsSVGGradientFrameBase::DidSetStyleContext();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGGradientFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute,
|
|
|
|
PRInt32 aModType)
|
|
|
|
{
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::gradientUnits ||
|
|
|
|
aAttribute == nsGkAtoms::gradientTransform ||
|
|
|
|
aAttribute == nsGkAtoms::spreadMethod)) {
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGEffects::InvalidateRenderingObservers(this);
|
|
|
|
} else if (aNameSpaceID == kNameSpaceID_XLink &&
|
|
|
|
aAttribute == nsGkAtoms::href) {
|
|
|
|
// Blow away our reference, if any
|
|
|
|
DeleteProperty(nsGkAtoms::href);
|
|
|
|
mNoHRefURI = PR_FALSE;
|
|
|
|
// And update whoever references us
|
|
|
|
nsSVGEffects::InvalidateRenderingObservers(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsSVGGradientFrameBase::AttributeChanged(aNameSpaceID,
|
|
|
|
aAttribute, aModType);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
PRUint32
|
|
|
|
nsSVGGradientFrame::GetStopCount()
|
|
|
|
{
|
|
|
|
return GetStopFrame(-1, nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGGradientFrame::GetStopInformation(PRInt32 aIndex,
|
2007-04-24 01:11:22 -07:00
|
|
|
float *aOffset,
|
|
|
|
nscolor *aStopColor,
|
|
|
|
float *aStopOpacity)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
*aOffset = 0.0f;
|
2007-04-24 01:11:22 -07:00
|
|
|
*aStopColor = NS_RGBA(0, 0, 0, 0);
|
|
|
|
*aStopOpacity = 1.0f;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsIFrame *stopFrame = nsnull;
|
|
|
|
GetStopFrame(aIndex, &stopFrame);
|
|
|
|
nsCOMPtr<nsIDOMSVGStopElement> stopElement =
|
|
|
|
do_QueryInterface(stopFrame->GetContent());
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stopFrame) {
|
2007-04-24 01:11:22 -07:00
|
|
|
*aStopColor = stopFrame->GetStyleSVGReset()->mStopColor;
|
|
|
|
*aStopOpacity = stopFrame->GetStyleSVGReset()->mStopOpacity;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
// 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!");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NS_ERROR("Don't call me with an invalid stop index!");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
gfxMatrix
|
|
|
|
nsSVGGradientFrame::GetGradientTransform(nsSVGGeometryFrame *aSource)
|
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
|
|
|
|
|
|
|
PRUint16 gradientUnits = GetGradientUnits();
|
|
|
|
nsIAtom *callerType = aSource->GetType();
|
2007-08-27 16:11:14 -07:00
|
|
|
if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// If this gradient is applied to text, our caller
|
|
|
|
// will be the glyph, which is not a container, so we
|
|
|
|
// need to get the parent
|
|
|
|
if (callerType == nsGkAtoms::svgGlyphFrame)
|
2007-07-08 00:08:04 -07:00
|
|
|
mSourceContent = static_cast<nsSVGElement*>
|
|
|
|
(aSource->GetContent()->GetParent());
|
2007-03-22 10:30:00 -07:00
|
|
|
else
|
2007-07-08 00:08:04 -07:00
|
|
|
mSourceContent = static_cast<nsSVGElement*>(aSource->GetContent());
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(mSourceContent, "Can't get content for gradient");
|
|
|
|
}
|
|
|
|
else {
|
2007-08-27 16:11:14 -07:00
|
|
|
NS_ASSERTION(gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
2007-03-22 10:30:00 -07:00
|
|
|
"Unknown gradientUnits type");
|
|
|
|
// objectBoundingBox is the default anyway
|
|
|
|
|
|
|
|
nsISVGChildFrame *frame = nsnull;
|
|
|
|
if (aSource) {
|
|
|
|
if (callerType == nsGkAtoms::svgGlyphFrame)
|
|
|
|
CallQueryInterface(aSource->GetParent(), &frame);
|
|
|
|
else
|
|
|
|
CallQueryInterface(aSource, &frame);
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMSVGRect> rect;
|
|
|
|
if (frame) {
|
2007-08-30 11:45:06 -07:00
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> matrix = frame->GetOverrideCTM();
|
2007-03-22 10:30:00 -07:00
|
|
|
frame->SetMatrixPropagation(PR_FALSE);
|
2007-08-30 11:45:06 -07:00
|
|
|
frame->SetOverrideCTM(nsnull);
|
2008-01-25 01:27:03 -08:00
|
|
|
frame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
|
|
|
nsISVGChildFrame::TRANSFORM_CHANGED);
|
2007-03-22 10:30:00 -07:00
|
|
|
frame->GetBBox(getter_AddRefs(rect));
|
|
|
|
frame->SetMatrixPropagation(PR_TRUE);
|
2007-08-30 11:45:06 -07:00
|
|
|
frame->SetOverrideCTM(matrix);
|
2008-01-25 01:27:03 -08:00
|
|
|
frame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
|
|
|
|
nsISVGChildFrame::TRANSFORM_CHANGED);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
if (rect) {
|
|
|
|
float x, y, width, height;
|
|
|
|
rect->GetX(&x);
|
|
|
|
rect->GetY(&y);
|
|
|
|
rect->GetWidth(&width);
|
|
|
|
rect->GetHeight(&height);
|
2007-04-27 07:28:39 -07:00
|
|
|
bboxMatrix = gfxMatrix(width, 0, 0, height, x, y);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientElement *element =
|
|
|
|
GetGradientWithAttr(nsGkAtoms::gradientTransform, mContent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMSVGTransformList> trans;
|
2008-09-30 17:51:05 -07:00
|
|
|
element->mGradientTransform->GetAnimVal(getter_AddRefs(trans));
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> gradientTransform =
|
|
|
|
nsSVGTransformList::GetConsolidationMatrix(trans);
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
if (!gradientTransform)
|
|
|
|
return bboxMatrix;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
return nsSVGUtils::ConvertSVGMatrixToThebes(gradientTransform) * bboxMatrix;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRUint16
|
|
|
|
nsSVGGradientFrame::GetSpreadMethod()
|
|
|
|
{
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientElement *element =
|
|
|
|
GetGradientWithAttr(nsGkAtoms::spreadMethod, mContent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
return element->mEnumAttributes[nsSVGGradientElement::SPREADMETHOD].GetAnimValue();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsSVGPaintServerFrame methods:
|
|
|
|
|
2007-04-23 02:11:19 -07:00
|
|
|
PRBool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSVGGradientFrame::SetupPaintServer(gfxContext *aContext,
|
|
|
|
nsSVGGeometryFrame *aSource,
|
2007-10-21 02:05:41 -07:00
|
|
|
float aGraphicOpacity)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// Get the transform list (if there is one)
|
2007-04-27 07:28:39 -07:00
|
|
|
gfxMatrix patternMatrix = GetGradientTransform(aSource);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
if (patternMatrix.IsSingular())
|
2007-04-23 02:11:19 -07:00
|
|
|
return PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-02-08 13:52:04 -08:00
|
|
|
PRUint32 nStops = GetStopCount();
|
|
|
|
|
|
|
|
// SVG specification says that no stops should be treated like
|
|
|
|
// the corresponding fill or stroke had "none" specified.
|
|
|
|
if (nStops == 0) {
|
|
|
|
aContext->SetColor(gfxRGBA(0, 0, 0, 0));
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
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())
|
2007-04-23 02:11:19 -07:00
|
|
|
return PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRUint16 aSpread = GetSpreadMethod();
|
|
|
|
if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_PAD)
|
2007-04-27 07:28:39 -07:00
|
|
|
gradient->SetExtend(gfxPattern::EXTEND_PAD);
|
2007-03-22 10:30:00 -07:00
|
|
|
else if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_REFLECT)
|
2007-04-27 07:28:39 -07:00
|
|
|
gradient->SetExtend(gfxPattern::EXTEND_REFLECT);
|
2007-03-22 10:30:00 -07:00
|
|
|
else if (aSpread == nsIDOMSVGGradientElement::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;
|
|
|
|
|
|
|
|
for (PRUint32 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
|
|
|
|
2007-04-24 01:11:22 -07:00
|
|
|
GetStopInformation(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
|
|
|
}
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
aContext->SetPattern(gradient);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-04-23 02:11:19 -07:00
|
|
|
return PR_TRUE;
|
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)
|
|
|
|
return nsnull;
|
2008-09-30 01:47:20 -07:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGPaintingProperty *property =
|
|
|
|
static_cast<nsSVGPaintingProperty*>(GetProperty(nsGkAtoms::href));
|
|
|
|
|
|
|
|
if (!property) {
|
|
|
|
// Fetch our gradient element's xlink:href attribute
|
2008-10-11 04:29:35 -07:00
|
|
|
nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(mContent);
|
|
|
|
const nsString &href = grad->mStringAttributes[nsSVGGradientElement::HREF].GetAnimValue();
|
2008-09-30 17:51:05 -07:00
|
|
|
if (href.IsEmpty()) {
|
|
|
|
mNoHRefURI = PR_TRUE;
|
|
|
|
return nsnull; // 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);
|
|
|
|
|
|
|
|
property = nsSVGEffects::GetPaintingProperty(targetURI, this, nsGkAtoms::href);
|
|
|
|
if (!property)
|
|
|
|
return nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2008-09-30 17:51:05 -07:00
|
|
|
|
|
|
|
nsIFrame *result = property->GetReferencedFrame();
|
|
|
|
if (!result)
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
nsIAtom* frameType = result->GetType();
|
|
|
|
if (frameType != nsGkAtoms::svgLinearGradientFrame &&
|
|
|
|
frameType != nsGkAtoms::svgRadialGradientFrame)
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
return static_cast<nsSVGGradientFrame*>(result);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientElement *
|
|
|
|
nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName, nsIContent *aDefault)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (mContent->HasAttr(kNameSpaceID_None, aAttrName))
|
2008-09-30 17:51:05 -07:00
|
|
|
return static_cast<nsSVGGradientElement *>(mContent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(aDefault);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientFrame *next = GetReferencedGradient();
|
|
|
|
if (!next)
|
|
|
|
return grad;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
|
|
|
|
mLoopFlag = PR_TRUE;
|
|
|
|
// XXXjwatt: we should really send an error to the JavaScript Console here:
|
2008-09-30 17:51:05 -07:00
|
|
|
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
|
|
|
|
"while inheriting attribute!");
|
|
|
|
if (!next->mLoopFlag)
|
|
|
|
grad = next->GetGradientWithAttr(aAttrName, aDefault);
|
2007-03-22 10:30:00 -07:00
|
|
|
mLoopFlag = PR_FALSE;
|
|
|
|
|
|
|
|
return grad;
|
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientElement *
|
|
|
|
nsSVGGradientFrame::GetGradientWithAttr(nsIAtom *aAttrName, nsIAtom *aGradType,
|
|
|
|
nsIContent *aDefault)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (GetType() == aGradType && mContent->HasAttr(kNameSpaceID_None, aAttrName))
|
2008-09-30 17:51:05 -07:00
|
|
|
return static_cast<nsSVGGradientElement *>(mContent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(aDefault);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientFrame *next = GetReferencedGradient();
|
|
|
|
if (!next)
|
|
|
|
return grad;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
|
|
|
|
mLoopFlag = PR_TRUE;
|
|
|
|
// XXXjwatt: we should really send an error to the JavaScript Console here:
|
2008-09-30 17:51:05 -07:00
|
|
|
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
|
|
|
|
"while inheriting attribute!");
|
|
|
|
if (!next->mLoopFlag)
|
|
|
|
grad = next->GetGradientWithAttr(aAttrName, aGradType, aDefault);
|
2007-03-22 10:30:00 -07:00
|
|
|
mLoopFlag = PR_FALSE;
|
|
|
|
|
|
|
|
return grad;
|
|
|
|
}
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
PRInt32
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSVGGradientFrame::GetStopFrame(PRInt32 aIndex, nsIFrame * *aStopFrame)
|
|
|
|
{
|
|
|
|
PRInt32 stopCount = 0;
|
|
|
|
nsIFrame *stopFrame = nsnull;
|
|
|
|
for (stopFrame = mFrames.FirstChild(); stopFrame;
|
|
|
|
stopFrame = stopFrame->GetNextSibling()) {
|
|
|
|
if (stopFrame->GetType() == nsGkAtoms::svgStopFrame) {
|
|
|
|
// Is this the one we're looking for?
|
|
|
|
if (stopCount++ == aIndex)
|
|
|
|
break; // Yes, break out of the loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (stopCount > 0) {
|
|
|
|
if (aStopFrame)
|
|
|
|
*aStopFrame = stopFrame;
|
|
|
|
return stopCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Our gradient element doesn't have stops - try to "inherit" them
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientFrame *next = GetReferencedGradient();
|
|
|
|
if (!next) {
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aStopFrame)
|
|
|
|
*aStopFrame = nsnull;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set mLoopFlag before checking mNextGrad->mLoopFlag in case we are mNextGrad
|
|
|
|
mLoopFlag = PR_TRUE;
|
|
|
|
// XXXjwatt: we should really send an error to the JavaScript Console here:
|
2008-09-30 17:51:05 -07:00
|
|
|
NS_WARN_IF_FALSE(!next->mLoopFlag, "gradient reference loop detected "
|
|
|
|
"while inheriting stop!");
|
|
|
|
if (!next->mLoopFlag)
|
|
|
|
stopCount = next->GetStopFrame(aIndex, aStopFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
mLoopFlag = PR_FALSE;
|
|
|
|
|
|
|
|
return stopCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint16
|
|
|
|
nsSVGGradientFrame::GetGradientUnits()
|
|
|
|
{
|
|
|
|
// This getter is called every time the others are called - maybe cache it?
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGGradientElement *element =
|
|
|
|
GetGradientWithAttr(nsGkAtoms::gradientUnits, mContent);
|
|
|
|
return element->mEnumAttributes[nsSVGGradientElement::GRADIENTUNITS].GetAnimValue();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Linear Gradients
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsIAtom*
|
|
|
|
nsSVGLinearGradientFrame::GetType() const
|
|
|
|
{
|
|
|
|
return nsGkAtoms::svgLinearGradientFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGLinearGradientFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute,
|
|
|
|
PRInt32 aModType)
|
|
|
|
{
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::x1 ||
|
|
|
|
aAttribute == nsGkAtoms::y1 ||
|
|
|
|
aAttribute == nsGkAtoms::x2 ||
|
|
|
|
aAttribute == nsGkAtoms::y2)) {
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGEffects::InvalidateRenderingObservers(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
|
|
|
|
aAttribute, aModType);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
float
|
|
|
|
nsSVGLinearGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
|
|
|
|
PRUint16 aEnumName)
|
|
|
|
{
|
|
|
|
nsSVGLinearGradientElement *element =
|
2008-09-30 17:51:05 -07:00
|
|
|
GetLinearGradientWithAttr(aAtomName, mContent);
|
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.
|
|
|
|
|
|
|
|
PRUint16 gradientUnits = GetGradientUnits();
|
2007-08-27 16:11:14 -07:00
|
|
|
if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsSVGUtils::UserSpace(mSourceContent,
|
|
|
|
&element->mLengthAttributes[aEnumName]);
|
|
|
|
}
|
|
|
|
|
2007-08-27 16:11:14 -07:00
|
|
|
NS_ASSERTION(gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
2007-03-22 10:30:00 -07:00
|
|
|
"Unknown gradientUnits type");
|
|
|
|
|
|
|
|
return element->mLengthAttributes[aEnumName].
|
2007-07-08 00:08:04 -07:00
|
|
|
GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
|
2007-03-22 10:30:00 -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;
|
|
|
|
|
|
|
|
x1 = GradientLookupAttribute(nsGkAtoms::x1, nsSVGLinearGradientElement::X1);
|
|
|
|
y1 = GradientLookupAttribute(nsGkAtoms::y1, nsSVGLinearGradientElement::Y1);
|
|
|
|
x2 = GradientLookupAttribute(nsGkAtoms::x2, nsSVGLinearGradientElement::X2);
|
|
|
|
y2 = GradientLookupAttribute(nsGkAtoms::y2, nsSVGLinearGradientElement::Y2);
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
gfxPattern *pattern = new gfxPattern(x1, y1, x2, y2);
|
|
|
|
NS_IF_ADDREF(pattern);
|
|
|
|
return pattern;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Radial Gradients
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsIAtom*
|
|
|
|
nsSVGRadialGradientFrame::GetType() const
|
|
|
|
{
|
|
|
|
return nsGkAtoms::svgRadialGradientFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGRadialGradientFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute,
|
|
|
|
PRInt32 aModType)
|
|
|
|
{
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::r ||
|
|
|
|
aAttribute == nsGkAtoms::cx ||
|
|
|
|
aAttribute == nsGkAtoms::cy ||
|
|
|
|
aAttribute == nsGkAtoms::fx ||
|
|
|
|
aAttribute == nsGkAtoms::fy)) {
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGEffects::InvalidateRenderingObservers(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
|
|
|
|
aAttribute, aModType);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
float
|
|
|
|
nsSVGRadialGradientFrame::GradientLookupAttribute(nsIAtom *aAtomName,
|
|
|
|
PRUint16 aEnumName,
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGRadialGradientElement *aElement)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGRadialGradientElement *element;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (aElement) {
|
2008-09-30 17:51:05 -07:00
|
|
|
element = aElement;
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2008-09-30 17:51:05 -07:00
|
|
|
element = GetRadialGradientWithAttr(aAtomName, mContent);
|
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.
|
|
|
|
|
|
|
|
PRUint16 gradientUnits = GetGradientUnits();
|
2007-08-27 16:11:14 -07:00
|
|
|
if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsSVGUtils::UserSpace(mSourceContent,
|
|
|
|
&element->mLengthAttributes[aEnumName]);
|
|
|
|
}
|
|
|
|
|
2007-08-27 16:11:14 -07:00
|
|
|
NS_ASSERTION(gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
2007-03-22 10:30:00 -07:00
|
|
|
"Unknown gradientUnits type");
|
|
|
|
|
|
|
|
return element->mLengthAttributes[aEnumName].
|
2007-07-08 00:08:04 -07:00
|
|
|
GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
already_AddRefed<gfxPattern>
|
2007-03-22 10:30:00 -07:00
|
|
|
nsSVGRadialGradientFrame::CreateGradient()
|
|
|
|
{
|
|
|
|
float cx, cy, r, fx, fy;
|
|
|
|
|
|
|
|
cx = GradientLookupAttribute(nsGkAtoms::cx, nsSVGRadialGradientElement::CX);
|
|
|
|
cy = GradientLookupAttribute(nsGkAtoms::cy, nsSVGRadialGradientElement::CY);
|
|
|
|
r = GradientLookupAttribute(nsGkAtoms::r, nsSVGRadialGradientElement::R);
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGRadialGradientElement *gradient;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fx, nsnull)))
|
2007-03-22 10:30:00 -07:00
|
|
|
fx = cx; // if fx isn't set, we must use cx
|
|
|
|
else
|
|
|
|
fx = GradientLookupAttribute(nsGkAtoms::fx, nsSVGRadialGradientElement::FX, gradient);
|
|
|
|
|
2008-09-30 17:51:05 -07:00
|
|
|
if (!(gradient = GetRadialGradientWithAttr(nsGkAtoms::fy, nsnull)))
|
2007-03-22 10:30:00 -07:00
|
|
|
fy = cy; // if fy isn't set, we must use cy
|
|
|
|
else
|
|
|
|
fy = GradientLookupAttribute(nsGkAtoms::fy, nsSVGRadialGradientElement::FY, gradient);
|
|
|
|
|
|
|
|
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
|
|
|
|
// make sure it is *less* than the gradient radius. 0.999 is used as the
|
|
|
|
// 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 * r;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-27 07:28:39 -07:00
|
|
|
gfxPattern *pattern = new gfxPattern(fx, fy, 0, cx, cy, r);
|
|
|
|
NS_IF_ADDREF(pattern);
|
|
|
|
return pattern;
|
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,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsStyleContext* aContext)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMSVGLinearGradientElement> grad = do_QueryInterface(aContent);
|
2007-07-25 02:16:02 -07:00
|
|
|
if (!grad) {
|
|
|
|
NS_ERROR("Can't create frame! Content is not an SVG linearGradient");
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsnull;
|
2007-07-25 02:16:02 -07:00
|
|
|
}
|
2008-09-30 17:51:05 -07:00
|
|
|
|
2008-10-11 04:29:35 -07:00
|
|
|
return new (aPresShell) nsSVGLinearGradientFrame(aContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame*
|
|
|
|
NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsStyleContext* aContext)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMSVGRadialGradientElement> grad = do_QueryInterface(aContent);
|
2007-07-25 02:16:02 -07:00
|
|
|
if (!grad) {
|
|
|
|
NS_ERROR("Can't create frame! Content is not an SVG radialGradient");
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsnull;
|
2007-07-25 02:16:02 -07:00
|
|
|
}
|
2008-09-30 17:51:05 -07:00
|
|
|
|
2008-10-11 04:29:35 -07:00
|
|
|
return new (aPresShell) nsSVGRadialGradientFrame(aContext);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|