KHTML
SVGRadialGradientElement.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org> 00003 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 00004 00005 This file is part of the KDE project 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 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 // Spec: If the attribute is not specified, the effect is as if a value of "50%" were specified. 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 // If we didn't find any gradient containing stop elements, ignore the request. 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 // Respect xlink:href, take attributes from referenced element 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 // Cycle detection 00168 if (processedGradients.contains(current)) 00169 return RadialGradientAttributes(); 00170 00171 isRadial = current->gradientType() == RadialGradientPaintServer; 00172 } else 00173 current = 0; 00174 } 00175 00176 // Handle default values for fx/fy 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 // KHTML ElementImpl pure virtual method 00187 quint32 SVGRadialGradientElement::id() const 00188 { 00189 return SVGNames::radialGradientTag.id(); 00190 } 00191 00192 } 00193 00194 #endif // ENABLE(SVG)
KDE 4.6 API Reference