00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "config.h"
00024 #include "wtf/Platform.h"
00025
00026 #if ENABLE(SVG)
00027 #include "SVGRadialGradientElement.h"
00028
00029 #include "FloatConversion.h"
00030 #include "FloatPoint.h"
00031 #include "RadialGradientAttributes.h"
00032 #include "RenderObject.h"
00033 #include "SVGLength.h"
00034 #include "SVGNames.h"
00035 #include "SVGPaintServerRadialGradient.h"
00036 #include "SVGStopElement.h"
00037 #include "SVGTransform.h"
00038 #include "SVGTransformList.h"
00039 #include "SVGUnitTypes.h"
00040
00041 namespace WebCore {
00042
00043 SVGRadialGradientElement::SVGRadialGradientElement(const QualifiedName& tagName, Document* doc)
00044 : SVGGradientElement(tagName, doc)
00045 , m_cx(this, LengthModeWidth)
00046 , m_cy(this, LengthModeHeight)
00047 , m_r(this, LengthModeOther)
00048 , m_fx(this, LengthModeWidth)
00049 , m_fy(this, LengthModeHeight)
00050 {
00051
00052 setCxBaseValue(SVGLength(this, LengthModeWidth, "50%"));
00053 setCyBaseValue(SVGLength(this, LengthModeHeight, "50%"));
00054 setRBaseValue(SVGLength(this, LengthModeOther, "50%"));
00055 }
00056
00057 SVGRadialGradientElement::~SVGRadialGradientElement()
00058 {
00059 }
00060
00061 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement, SVGLength, Length, length, Cx, cx, SVGNames::cxAttr, m_cx)
00062 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement, SVGLength, Length, length, Cy, cy, SVGNames::cyAttr, m_cy)
00063 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement, SVGLength, Length, length, Fx, fx, SVGNames::fxAttr, m_fx)
00064 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement, SVGLength, Length, length, Fy, fy, SVGNames::fyAttr, m_fy)
00065 ANIMATED_PROPERTY_DEFINITIONS(SVGRadialGradientElement, SVGLength, Length, length, R, r, SVGNames::rAttr, m_r)
00066
00067 void SVGRadialGradientElement::parseMappedAttribute(MappedAttribute* attr)
00068 {
00069 if (attr->name() == SVGNames::cxAttr)
00070 setCxBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
00071 else if (attr->name() == SVGNames::cyAttr)
00072 setCyBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
00073 else if (attr->name() == SVGNames::rAttr) {
00074 setRBaseValue(SVGLength(this, LengthModeOther, attr->value()));
00075 if (r().value() < 0.0)
00076 document()->accessSVGExtensions()->reportError("A negative value for radial gradient radius <r> is not allowed");
00077 } else if (attr->name() == SVGNames::fxAttr)
00078 setFxBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
00079 else if (attr->name() == SVGNames::fyAttr)
00080 setFyBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
00081 else
00082 SVGGradientElement::parseMappedAttribute(attr);
00083 }
00084
00085 void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName& attrName)
00086 {
00087 SVGGradientElement::svgAttributeChanged(attrName);
00088
00089 if (!m_resource)
00090 return;
00091
00092 if (attrName == SVGNames::cxAttr || attrName == SVGNames::cyAttr ||
00093 attrName == SVGNames::fxAttr || attrName == SVGNames::fyAttr ||
00094 attrName == SVGNames::rAttr)
00095 m_resource->invalidate();
00096 }
00097
00098 void SVGRadialGradientElement::buildGradient() const
00099 {
00100 RadialGradientAttributes attributes = collectGradientProperties();
00101
00102
00103 if (attributes.stops().isEmpty())
00104 return;
00105
00106 RefPtr<SVGPaintServerRadialGradient> radialGradient = WTF::static_pointer_cast<SVGPaintServerRadialGradient>(m_resource);
00107
00108 radialGradient->setGradientStops(attributes.stops());
00109 radialGradient->setBoundingBoxMode(attributes.boundingBoxMode());
00110 radialGradient->setGradientSpreadMethod(attributes.spreadMethod());
00111 radialGradient->setGradientTransform(attributes.gradientTransform());
00112 radialGradient->setGradientCenter(FloatPoint::narrowPrecision(attributes.cx(), attributes.cy()));
00113 radialGradient->setGradientFocal(FloatPoint::narrowPrecision(attributes.fx(), attributes.fy()));
00114 radialGradient->setGradientRadius(narrowPrecisionToFloat(attributes.r()));
00115 }
00116
00117 RadialGradientAttributes SVGRadialGradientElement::collectGradientProperties() const
00118 {
00119 RadialGradientAttributes attributes;
00120 HashSet<const SVGGradientElement*> processedGradients;
00121
00122 bool isRadial = true;
00123 const SVGGradientElement* current = this;
00124
00125 while (current) {
00126 if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr))
00127 attributes.setSpreadMethod((SVGGradientSpreadMethod) current->spreadMethod());
00128
00129 if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::gradientUnitsAttr))
00130 attributes.setBoundingBoxMode(current->getAttribute(SVGNames::gradientUnitsAttr) == "objectBoundingBox");
00131
00132 if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr))
00133 attributes.setGradientTransform(current->gradientTransform()->consolidate().matrix());
00134
00135 if (!attributes.hasStops()) {
00136 const Vector<SVGGradientStop>& stops(current->buildStops());
00137 if (!stops.isEmpty())
00138 attributes.setStops(stops);
00139 }
00140
00141 if (isRadial) {
00142 const SVGRadialGradientElement* radial = static_cast<const SVGRadialGradientElement*>(current);
00143
00144 if (!attributes.hasCx() && current->hasAttribute(SVGNames::cxAttr))
00145 attributes.setCx(radial->cx().valueAsPercentage());
00146
00147 if (!attributes.hasCy() && current->hasAttribute(SVGNames::cyAttr))
00148 attributes.setCy(radial->cy().valueAsPercentage());
00149
00150 if (!attributes.hasR() && current->hasAttribute(SVGNames::rAttr))
00151 attributes.setR(radial->r().valueAsPercentage());
00152
00153 if (!attributes.hasFx() && current->hasAttribute(SVGNames::fxAttr))
00154 attributes.setFx(radial->fx().valueAsPercentage());
00155
00156 if (!attributes.hasFy() && current->hasAttribute(SVGNames::fyAttr))
00157 attributes.setFy(radial->fy().valueAsPercentage());
00158 }
00159
00160 processedGradients.add(current);
00161
00162
00163 Node* refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href()));
00164 if (refNode && (refNode->hasTagName(SVGNames::radialGradientTag) || refNode->hasTagName(SVGNames::linearGradientTag))) {
00165 current = static_cast<const SVGGradientElement*>(const_cast<const Node*>(refNode));
00166
00167
00168 if (processedGradients.contains(current))
00169 return RadialGradientAttributes();
00170
00171 isRadial = current->gradientType() == RadialGradientPaintServer;
00172 } else
00173 current = 0;
00174 }
00175
00176
00177 if (!attributes.hasFx())
00178 attributes.setFx(attributes.cx());
00179
00180 if (!attributes.hasFy())
00181 attributes.setFy(attributes.cy());
00182
00183 return attributes;
00184 }
00185
00186
00187 quint32 SVGRadialGradientElement::id() const
00188 {
00189 return SVGNames::radialGradientTag.id();
00190 }
00191
00192 }
00193
00194 #endif // ENABLE(SVG)